Skip to main content
On this page

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 prepare is pre-warm only. SKILL.md presents adk pr-queue get-next (Phase 0, claims) then adk pr-task prepare (Phase 1) as a chain, but pr-task prepare hard-codes --prepare-only which skips locked rows. Real review entry point is prepare_task.py directly (without --prepare-only). Either: (a) update SKILL.md to call python3 prepare_task.py <url> for Phase 1 (or just prepare_task.py for queue-claim mode); or (b) add a non---prepare-only mode to adk 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:823 still emits commentID for 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 --strict that spawns claude -p per 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-local load_config / get_cfg, and a die() wrapper.
  • scripts/lib/code_index/_lib_common.py: 145 → 81 LOC (44% reduction).
  • scripts/config_io.py: dropped _file_lock, now imports from adk_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 from set-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:

  1. Gap 1: -i only walked NEW findings; the 14 resolves slid straight to the posting plan unchallenged. Walker now mirrors triage.py’s accept/reject/edit lifecycle for posting steps.
  2. Gap 2: AskUserQuestion saw bullet summaries, not the actual posting body. Walker’s --render <step_id> returns the full rendered markdown — the exact body that would post.
  3. 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 Bitbucket commentID reference. 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 --strict mode added. The walker handles the practical re-validation in-context (the agent re-reads the worktree snippet for each resolve/reopen). A separate --strict mode using claude -p per 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)

Next-best actions (Session 3)

Recommended order:

  1. 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 for v4.0.0-rc1 tag.

  2. 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.

  3. SKILL.md / adk pr-task prepare cleanup (small, follow-up) — clarify the workflow so future -i runs don’t hit the “locked by another reviewer” collision after pr-queue get-next. Either update the SKILL.md table to point Phase 1 at prepare_task.py directly, or add a non---prepare-only mode to adk pr-task prepare.

  4. Bitbucket signature audit — drive a /adk-pr-review end-to-end against a Bitbucket PR (one is sitting near the top of your queue at bitbucket.org/lastbrand/ecomm-ssr/pull-requests/5522) and apply the same fix pass to resolveComment / reopenComment / addPullRequestComment mcp_args.

  5. validate_findings.py --strict (for headless automation use case) — spawn claude -p per finding with a focused yes/no re-validation prompt. Lower urgency now that the walker provides the in-context equivalent for interactive runs.

  6. Phase 7 — Release readiness report + v4.0.0-rc1 tag.

User-side actions (independent of next session):

  • The earlier Session 1 list still applies (./install.sh to refresh hooks; /adk-setup --init to scaffold connectors; /adk-setup --enrich to populate improve/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).