Session 2 — Production-Readiness Pass
Date: 2026-05-21.
Branch: main. Start HEAD: 9b91965. End HEAD: 2e74c91.
Tests: 412 passing (unchanged count throughout — verified green after each commit).
Session 1 close: see SESSION-1-REPORT.md (Phases 0–3 done).
TL;DR
Three commits this session covering the two highest-priority items from Session 1’s “Next-best actions”: F-009/F-010 helper consolidation (Phase 2 continuation) and end-to-end real-PR validation (Phase 6, with -i and live posting). Phase 6 was the most informative: the live-posting walk surfaced 5 additional skill bugs that the audit had missed (interactive mode preview gap, posting-plan re-validation gap, three MCP signature mismatches, plus a stale-name NameError in report.py and a walker corner-case for past-EOF anchors). Built a new walk_posting_plan.py to close the interactive-preview + re-validation gaps. Phases 4 (OSS hardening) and 5 (TUI build) remain for Session 3.
Risk / Blockers / Follow-ups
- CLI / workflow doc mismatch —
adk pr-task prepareis pre-warm only. SKILL.md presentsadk pr-queue get-next(Phase 0, claims) thenadk pr-task prepare(Phase 1) as a chain, butpr-task preparehard-codes--prepare-onlywhich skips locked rows. Real review entry point isprepare_task.pydirectly (without--prepare-only). Either: (a) update SKILL.md to callpython3 prepare_task.py <url>for Phase 1 (or justprepare_task.pyfor queue-claim mode); or (b) add a non---prepare-onlymode toadk pr-task prepare. Documented; no code change yet. - Bitbucket MCP signatures not validated. This session’s PR was on GitHub. The same signature-mismatch class (commentID vs commentId, channel vs channel_id, missing method) may exist on the Bitbucket side (resolveComment / reopenComment / addPullRequestComment).
post_comments.py:823still emitscommentIDfor Bitbucket — left untouched pending a Bitbucket-PR validation run. - Phase 3 strict re-validation as a separate step is not implemented. The “LLM-backed re-validation” the user asked for is now done IN-CONTEXT by the walker (it surfaces the worktree at each anchor for the agent to re-check), which is the practical equivalent. A standalone
validate_findings.py --strictthat spawnsclaude -pper finding for non-interactive automation is still on the table for a future session. - Phase 4 (OSS hardening) and Phase 5 (TUI build) deferred to Session 3. Per the user’s call to wrap after Phase 6.
- From Session 1 still open: F-018 (env-var presence helper using adk_common), F-019 (doctor.py uses ensure_ollama), F-021 (scripts/verify_repo.py rewrite + CI gate), F-024 (agents-codex/junie READMEs), F-025 (decision_logger.py coverage), F-028 (query_index.py vs query.py).
What got done — by phase
Phase 2 continuation — F-009 + F-010 (1 commit)
| Commit | Subject |
|---|---|
4394d70 |
refactor(scripts): hoist shared helpers to adk_common.py (F-009/F-010) |
Three legacy “_common” modules carried duplicated helpers — the
config_io.py private _file_lock literally said in a comment “Local
copy so this script doesn’t depend on adk-pr-review’s _common.py.”
Consolidated into scripts/lib/adk_common.py:
- logging (
get_logger), subprocess (run,run_ok,which) - JSON IO (
read_json,write_json,emit_json) - hashing (
sha256_hex,sha1_hex) - fcntl locks (
file_lock,try_file_lock,LockHeldError) - dict
deep_merge ADK_HOME/REPOS_ROOT- All REPOS_ROOT-derived path helpers —
repo_dir_for,repo_clone_for,repo_branch_dir,clone_lock_for,repo_meta_path_for,branch_worktree_for,branch_meta_path_for die(msg, prefix)with caller-specified prefix
Legacy modules became thin re-exporters:
skills/adk-pr-review/scripts/_common.py: 387 → 211 LOC (45% reduction). Keeps PR-review-specific path helpers (task_dir_for,pr_review_dir,pr_lock_for, …), state-file helpers (read_state/write_state/mark_phase),parse_pr_url, the skill-localload_config/get_cfg, and adie()wrapper.scripts/lib/code_index/_lib_common.py: 145 → 81 LOC (44% reduction).scripts/config_io.py: dropped_file_lock, now imports fromadk_common.
repo.py (F-010): replaced local _repo_dir / _bare_clone_dir / _branch_dir / _branch_worktree / _branch_meta_path copies with imports from
_common. Aliases preserved so existing call sites stay readable.
pr_sync.py drive-by: dropped REPOS_ROOT / repo / "original-clone"
reconstruction in _remote_tip in favor of repo_clone_for(repo).
Test fixture: test_repo.py::fake_repos_root now patches both
repo.REPOS_ROOT and adk_common.REPOS_ROOT — the canonical helpers
read it dynamically.
Phase 6 — Real-PR validation (2 commits + 1 follow-up)
| Commit | Subject |
|---|---|
a74a20d |
feat(pr-review): walk_posting_plan.py — per-step preview + worktree re-validation |
2e74c91 |
fix(pr-review): MCP signature mismatches + report.py NameError + walker EOF clamp |
Ran /adk-pr-review -i --verbose end-to-end on
https://github.com/Quince-Engineering/event-schema-registry/pull/1 (the
next pending row in the queue). 22 changed files, 28 prior comment
threads (Copilot + sujeet-pro with author replies).
Findings written (1):
f-001— appreciation for the broader refactor that drops git writes entirely fromset-internal-version.sh, sidestepping the lockfile-staging concerns rather than patching them.
Existing-comment actions (14):
- 13
resolve(each verified against the worktree via the new walker) - 1
leave-as-is(the wontfix on DEVELOPMENT.md branch naming — repo default branch IS master, the docs match reality)
Posting plan dispatched (17/17 steps, all via real MCPs):
- 1 review (APPROVE event) via
pull_request_review_write - 1 appreciation comment via
add_issue_comment - 13 thread-resolution replies via
add_reply_to_pull_request_comment - 1 approve (bundled in review event)
- 1 Slack summary in the originating review thread
New tool: walk_posting_plan.py (512 LOC). Closes the three
interactive-mode gaps the user surfaced mid-run:
- Gap 1:
-ionly walked NEW findings; the 14 resolves slid straight to the posting plan unchallenged. Walker now mirrorstriage.py’s accept/reject/edit lifecycle for posting steps. - Gap 2:
AskUserQuestionsaw bullet summaries, not the actual posting body. Walker’s--render <step_id>returns the full rendered markdown — the exact body that would post. - Gap 3: Phase 3 validate only checked anchor + suggestion presence; no re-verification that the issue still applies. Walker’s render now includes the worktree context at the affected anchor (looked up via pr-comments.json for resolve/reopen, via findings-final.json for appreciation findings) — the agent reads the snippet and re-verifies in-context, which is the practical equivalent of an LLM-backed re-validation pass.
SKILL.md updated to wire the walker into the -i workflow (between
post_comments.py --use-mcp and the MCP dispatch loop).
Bugs fixed in the same session (5):
| Bug | File | What was wrong | Fix |
|---|---|---|---|
| MCP method missing | post_comments.py:705 |
pull_request_review_write signature requires method (create / submit_pending / …) but plan emitted only event |
Set method: "create" in mcp_args |
| MCP key mismatch | post_comments.py:804 |
add_reply_to_pull_request_comment uses commentId (lower d, int) but plan emitted commentID (caps, str) |
Renamed key + cast to int |
| MCP key mismatch | post_comments.py:869 |
conversations_add_message uses channel_id but plan emitted channel |
Renamed key |
| NameError | report.py:296 |
final_path referenced but never assigned (stale name from refactor) |
Restored final_path = pr_review_file(task_dir, "findings-final.json") |
| Walker corner case | walk_posting_plan.py:_worktree_snippet |
When original_line > file_length (file shortened in PR), lo came out > hi, producing an empty fence |
Clamp anchor to file length; surface “original_line N is past EOF” explicitly |
Test test_devx.py::test_plan_includes_slack_step_when_queue_ctx_has_thread
updated to assert the new channel_id key.
Files touched
| File | Change |
|---|---|
scripts/lib/adk_common.py |
NEW (288 LOC) — canonical home for shared helpers |
skills/adk-pr-review/scripts/_common.py |
Shrunk 387 → 211; re-exports from adk_common; drops duplicated helpers |
scripts/lib/code_index/_lib_common.py |
Shrunk 145 → 81; re-exports from adk_common |
scripts/config_io.py |
Dropped private _file_lock; imports from adk_common (361 → 337) |
skills/adk-cli/scripts/repo.py |
Imports path helpers from _common; aliases preserved (drop ~22 LOC of duplicates) |
skills/adk-cli/scripts/pr_sync.py |
_remote_tip uses repo_clone_for(repo) instead of reconstructing the path |
skills/adk-cli/scripts/tests/test_repo.py |
fake_repos_root fixture patches adk_common.REPOS_ROOT too |
skills/adk-pr-review/scripts/walk_posting_plan.py |
NEW (~530 LOC after the EOF-clamp fix) |
skills/adk-pr-review/SKILL.md |
New “Interactive mode: walk the posting plan” section under the Posting Policy block |
skills/adk-pr-review/scripts/post_comments.py |
3 MCP signature fixes |
skills/adk-pr-review/scripts/report.py |
Restored final_path assignment |
skills/adk-cli/scripts/tests/test_devx.py |
Asserts the new channel_id Slack key |
Files intentionally not touched
skills/adk-pr-review/scripts/post_comments.py:823— the BitbucketcommentIDreference. The same signature-mismatch class likely applies to Bitbucket MCPs but this session didn’t run an end-to-end against a Bitbucket PR; left for a Bitbucket-driven validation pass.validate_findings.py— no--strictmode added. The walker handles the practical re-validation in-context (the agent re-reads the worktree snippet for each resolve/reopen). A separate--strictmode usingclaude -pper finding is still on the roadmap for headless automation use cases.shared/constitution.md— §VIII forbids programmatic edits.docs/plans/**.md— historical planning docs.
What got skipped (and why)
- Phase 5 (TUI build) — per user call to wrap after Phase 6.
- Phase 4 (OSS hardening) — same.
- F-018, F-019, F-021, F-024, F-025, F-028 — still open from Session 1.
Decisions made this run
| Fork | Choice | Type | Reason |
|---|---|---|---|
| Session 2 order | helper-consolidation → real-PR validation → TUI → OSS hardening | user-answered | User’s explicit pick. |
| F-009 architecture | hoist to scripts/lib/adk_common.py (not next to existing _common.pys) |
inferred | scripts/lib/ is already the “library” namespace; cleaner cross-skill access path. |
| F-009 path helpers location | live in adk_common.py, not in _common.py |
corrected after a test failure | repo_branch_dir had to read REPOS_ROOT from the canonical module so monkeypatch worked correctly; tests forced the right architecture. |
| PR validation scope | end-to-end with -i | user-answered | Direct user pick — surfaced all 5 additional bugs. |
| Posting decision after the bug reveal | fix the 3 bugs first, then re-run | user-answered | Lets us validate the FIXED pipeline rather than the broken one. |
| Bug 3 implementation | walker-based in-context re-validation (not standalone —strict) | inferred | Walker already needs to read the worktree; reusing that view gives the agent the same evidence it would get from a separate claude -p call, in less code and faster. |
| Test fixture patch shape | patch both repo.REPOS_ROOT and adk_common.REPOS_ROOT |
inferred | Less invasive than rewriting tests to patch only the canonical module; preserves existing test pattern. |
| Posting decision (final) | accept all 17 | user-answered | After full re-validation pass — every resolve verified against worktree. |
| Bitbucket signature fix | deferred | inferred | This run didn’t exercise Bitbucket; speculative fixes risk introducing new bugs. |
Evidence (where to look)
- Commit list:
git log --oneline 9b91965..HEAD(3 commits). - Per-commit diff: standard git tooling.
- Test status:
python3 -m pytest skills/adk-cli/scripts/tests/ skills/adk-pr-review/scripts/tests/ -q→ 412 passed. - Live PR posting:
- Review: https://github.com/Quince-Engineering/event-schema-registry/pull/1#pullrequestreview-4339137783
- Appreciation comment: https://github.com/Quince-Engineering/event-schema-registry/pull/1#issuecomment-4510782807
- 13 thread replies (ids 3283074871, 3283075078, …) on the same PR.
- Slack summary: posted to
C0A6AGBDNURthread1779183172.107789.
- Task folder:
~/.agents-devkit/skill-pr-review/event-schema-registry_pr-1/(precis, findings, posting-plan, walker state, final report). - Walker artifacts:
pr-review/posting-walk-state.json,pr-review/posting-plan-final.json. - Session 1 baseline:
SESSION-1-REPORT.mdin the same folder.
Next-best actions (Session 3)
Recommended order:
-
Phase 4 — Open-source hardening (lower-risk, high signal-to-effort) — README polish, CONTRIBUTING.md, CODE_OF_CONDUCT.md,
.github/ISSUE_TEMPLATE, CI workflow,pyproject.toml. Parallelizable across 3 agents. Prereq forv4.0.0-rc1tag. -
Phase 5 — TUI build (highest visible net-new functionality) — Layered textual TUI with three tabs: setup wizard, queue dashboard, skill runner. Most net-new code of any pending track (~1500 LOC). Genuinely standalone — independent of helper consolidation.
-
SKILL.md /
adk pr-task preparecleanup (small, follow-up) — clarify the workflow so future-iruns don’t hit the “locked by another reviewer” collision afterpr-queue get-next. Either update the SKILL.md table to point Phase 1 atprepare_task.pydirectly, or add a non---prepare-onlymode toadk pr-task prepare. -
Bitbucket signature audit — drive a
/adk-pr-reviewend-to-end against a Bitbucket PR (one is sitting near the top of your queue atbitbucket.org/lastbrand/ecomm-ssr/pull-requests/5522) and apply the same fix pass toresolveComment/reopenComment/addPullRequestCommentmcp_args. -
validate_findings.py --strict(for headless automation use case) — spawnclaude -pper finding with a focused yes/no re-validation prompt. Lower urgency now that the walker provides the in-context equivalent for interactive runs. -
Phase 7 — Release readiness report +
v4.0.0-rc1tag.
User-side actions (independent of next session):
- The earlier Session 1 list still applies (
./install.shto refresh hooks;/adk-setup --initto scaffold connectors;/adk-setup --enrichto populateimprove/metadata/<source>.json). - Optional: clean stale terminal-status PR folders to reclaim disk (~1.85 GB of ecomm-ssr worktrees per Session 1 D-014).