Skip to content

[US-479] refactor: delivery workflow TO BE — coordinator + phase skills, one squash with the 2026-09-08 hardening - #480

Merged
rucka merged 125 commits into
mainfrom
feature/US-479-delivery-workflow-to-be
Sep 13, 2026
Merged

[US-479] refactor: delivery workflow TO BE — coordinator + phase skills, one squash with the 2026-09-08 hardening#480
rucka merged 125 commits into
mainfrom
feature/US-479-delivery-workflow-to-be

Conversation

@rucka

@rucka rucka commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

PR Information

PR Title: [US-479] refactor: delivery workflow TO BE — coordinator + phase skills, one squash with the 2026-09-08 hardening
Story/Epic: #479 (epic #212)
Type: Refactor
Priority: High
Assignee: @gcarucci
Labels: user story

Summary

What Changed

The branch starts at 7b559003 (the squashed 2026-09-08 hardening, removed from main on 2026-09-08 so that this PR's squash-merge brings it back together with the TO BE work). Commits land in this order, engine usable and tests green after each:

  • 05864b162 pair-loop.js halts on every status ≠ ready-for-merge; implement-batch CONTRACT lists every emitted status
  • 154e9578a custody/history machinery removed; rebase ⇒ stale
  • 236cf29b8 60429507 fase D: planner D0, skills pair-workflow-red-spec / red-verify / green-fix / p3-verify, seal + blob-check as node scripts, one handoff JSON per phase
  • 3e1886ea2 fase C: pair-workflow-review-phase, declared review set per risk tier
  • 4e2e9d9e8 fasi A/B → pair-workflow-implement-phase / pr-phase
  • 57f4cbb5a changelog-comments → ADR; workflowVersion; zero prompt / zero shell in pair-implement-batch.js
  • 6–7 — custody scripts ship INSIDE the skills that run them (contract-phase/scripts/ensure-contract.mjs, red-seal/scripts/red-snapshot.mjs, byte-identical copy in p3-verify/scripts/, drift-guarded by test) so a skill is portable as one folder on any harness; skill examples neutralized

Why This Change

pair-implement-batch.js (2222 lines) carries phase policy in free-form prompts, orchestrator-side semantics, and a rebase-repair layer (custody/history) that a stale-head rule makes unnecessary. Reference design: .pair/working/reports/delivery-workflow-to-be.md, with the corrections recorded in #479.

Story Context

User Story: see #479
Acceptance Criteria: to be fixed during refinement of #479

Changes Made

Files Changed

  • Modified: .claude/workflows/pair-implement-batch.js, pair-implement-batch.test.mjs, pair-loop.js, pair-loop.test.mjs, .claude/agents/*, dataset mirrors, batch-engine.mdx
  • Added: .claude/skills/pair-workflow-*/ (11, three of them with a scripts/ folder), .claude/agents/pair-remediation-planner.md, ADR-024
  • Deleted: .claude/agents/pair-custody-verifier.md, pair-red-domain-mapper.md
  • Moved: ensure-contract.mjspair-workflow-contract-phase/scripts/

Testing

Test Coverage

  • Unit Tests: workflow dry-run harness (pnpm workflows:test, 378 tests incl. the two US-479 acceptance criteria), conformance/mirror suites (4905), website (177)
  • Integration Tests: red-snapshot.test.mjs — 12 scenarios on throwaway git repositories (seal idempotency, blob identity, unlisted test, out-of-scope, behavioral module add, rebase ⇒ snapshot-missing, CLI exit codes)
  • Manual Testing: one story to ready-for-merge on the new engine (canary) — proposed: this PR's own final review via pair-implement-batch in prNumber mode

Quality Assurance

Code Quality Checklist

  • Code follows established style guides and conventions
  • Error handling implemented for edge cases
  • No debugging code or console logs left behind

Review Areas

  • Business Logic: every emitted status handled by pair-loop
  • Code Structure: no prompt / shell / severity rule left in the .js
  • Testing: each skill testable from a manifest fixture without the orchestrator

🤖 Generated with Claude Code

Review classification

risk:red · cost:green — review matrix (2026-09-09)

Classification matrix — per dimension
Dimension Tier Source Note
Service/domain criticality green tech/risk-matrix.md All touched deployables are listed Low.
Change/diff risk red PR diff Workflow/phase contract refactor across 90 files.
Business impact green Generic development-tooling subdomain Internal delivery tooling.
Security relevance yellow assess-security review Local workflow input reaches shell commands; validation is security-adjacent and covered by tests.
Coupling balance green review Typed phase boundaries; mirror and script-identity tests cover the distribution boundary.

Cost: green — no cost surface touched. Review classification has no refinement floor: #479 has not been refined.

…y, domain map, preflight, P3 carry-forward

Squash of the fifteen direct-to-main hardening commits of the pair-implement-batch engine
(2026-09-01 … 2026-09-08: front-load review contract coverage; prove external boundaries; the review
severity floor defaults to Minor; prove claims and collisions; preflight review fixes; lock red contracts
before fixes; seal RED contracts in Git; bind RED fixtures to tests; escalate history before seal;
harden sealed fix loop; carry P3 evidence forward; guard sealed custody; repair one RED contract;
map RED domains; retain grammar tokens), kept as the shipped state of fact: engine, tests, the
pair-red-*/pair-fix-*/pair-custody-verifier agents, their dataset mirrors, batch-engine.mdx and
apps/pair-cli/config.json.

The adoption records the 2026-09-03…09-08 commits carried (11 decision-log entries, four Review
Convergence bullets in way-of-working.md) are NOT part of this squash: the maintainer declared that
process no longer valid on 2026-09-08 and they never enter this history; the engine keeps
DEFAULT_SEVERITY_FLOOR with its rationale in the code comment. The three records that remain valid
(2026-08-31-review-baseline-and-provisioned-artifact-contract, 2026-09-01-review-contract-inventory-
prevents-serial-findings, 2026-09-01-external-boundary-proof-prevents-false-equivalence) and their
three Review Convergence bullets ARE part of it. The code stays as the product's current behaviour.

Refs: #219

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rucka rucka added the user story Work item representing a user story label Sep 8, 2026
…ract names every status it emits

pair-loop matched halted cards on `escalate` / `failed*`. The engine also returns
`seal-invalidated` and `stale-history-decision`: those cards were neither halted nor
parked, so they were re-selected and re-driven on every iteration up to max-iterations.
Rule inverted to a deny-list of one — only `ready-for-merge` may advance — and the
audit-resume prompt reads the same rule. implement-batch's CONTRACT block now lists
every status the code emits and states that a caller must halt on any status it does
not recognise. Dataset mirrors synced.

Test: pair-loop.test.mjs "ANY non-ready status halts the card" (red before, green after).

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ever repaired

Removed from pair-implement-batch: the custody probe (pair-custody-verifier agent, Custody
phase, CUSTODY_SCHEMA), card-level `custodyReset` and `historyDecision`, the `supersedes`
seal field, `applyHistoryDecision` / `textualHistorySubjects`, the `history-subject` finding
kind, and statuses failed-custody / failed-custody-reset / seal-invalidated /
stale-history-decision. −246 lines of engine, 14 tests retired, 3 added.

Rule that replaces it (TO BE §3.4/§7.5): an in-flight attempt whose base moved fails closed
where it is measured — sealer refuses a HEAD ≠ base, preflight refuses a non-ancestor
snapshot — and a resumed run starts a fresh review on the current head; older snapshots
are historical evidence. A history-only finding stays a typed human escalation
(`humanDecisionKind: history-rewrite`) taken before RED/seal/GREEN; nothing in the engine
can accept or waive it.

pair-reviewer.md: history clause reduced to the escalation. batch-engine.mdx: custody agent
row and the two custody sections replaced by "History rewrites and rebases". Dataset mirrors
synced.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
rucka and others added 2 commits September 8, 2026 22:56
…GREEN/P3 dispatched by name; Git custody in red-snapshot.mjs

Six skills in a new `workflow/` category (installed as pair-workflow-*): remediation-plan (D0),
red-spec (D1, domain map folded in), red-verify (D2), red-seal (D3), green-fix (D4), p3-verify
(D5). Each declares arguments, one mutation boundary and a handoff JSON under
.pair/working/runs/<runId>/<story>/. pair-implement-batch.js now names the skill and passes
typed args ($run $story $pr $phase $base $worktree $branch + phase JSON); the fase-D prompt
constants, the mapper agent and its schema are gone. One frozen plan per round; groups run
sequentially, each on the previous group's verified head; a plan that drops/duplicates/invents
a finding index is failed-plan. `args.runId`, `models.planner` (replaces redMapper),
`pipeline.skills.{remediationPlan,redSpec,redVerify,redSeal,greenFix,p3Verify}`.

red-snapshot.mjs: deterministic `seal` (HEAD == base, sha256 per artifact, tree dirty only at
the contract, one --no-verify commit with the Pair-RED-Snapshot trailer, idempotent) and
`verify` (one snapshot by trailer, parent == base, tree == manifest+artifacts, sealed blobs
byte-identical at HEAD, no unlisted test change, fixScope respected, no module added under a
behavioral scope). 12 tests on throwaway repos. Sealer (sonnet) and P3 agents run it.

Conformance checker learns the `workflow` category (four-part breakdown); KB/docs counts 44 → 50;
skills-catalog, skills-guide, next catalog gain a Workflow section; batch-engine.mdx rewritten
for the phase flow. ADR-024 records the decisions (storage authority, repair budget 1, local
snapshot commit, rebase never repaired, agent budget as AC). Dataset mirrors synced.

Tests: 375 workflow (dry-run harness + red-snapshot), 4900 knowledge-hub.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…k tier) and cycle-comments (probe / flush / synthesize)

pair-workflow-review-phase owns the independent review: it reads the PR's risk:* label and
declares its passes before running (general via the configured review skill on green; +
security and boundary lenses on yellow; + architecture and an adversarial second pass on red),
unions and deduplicates to one finding set with the template vocabulary, and carries the rules
the engine used to spell in a 5 KB prompt — pacing, blindness, finding shape and acceptance
plan, evidence ledger / boundary proof / lossless diagnostics, no-new-issues, nonActionable +
disposition, history-rewrite escalation, TEXT SHAPE — plus the three modes (first posts with the
hidden marker; re-review inspects only the fix delta, silent; fresh is a full silent pass).
pair-workflow-cycle-comments owns the PR-comment policy: probe (log present? marker on the PR?),
flush (escalation, superseding any prior flush, log kept), synthesize (ONE remediation table
across every run, intermediates minimized, log deleted).

pair-implement-batch.js dispatches both by configured name with typed args ($mode, $marker,
$template, $severities, $verdicts, $reviewSkill, $writeIssue, $priorFindings, $priorHead,
$hasLog, $accepted); the reviewer prompt, probe prompt, both flush prompts, the synthesis prompt,
CONTRACT_INVENTORY, revWtClause and the flush helpers are gone from the workflow. pair-reviewer
agent thinned to a skill executor. Counts 50 → 52; catalogs, batch-engine.mdx and ADR-024 updated.
Dataset mirrors synced.

Tests: 375 workflow, 4902 knowledge-hub, 177 website.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…phase, pr-phase; the workflow dispatches no free-form prompt

pair-workflow-contract-phase (ensure-contract.mjs check/write, severityRanks from meaning not
order), pair-workflow-implement-phase (worktree isolation incl. stacked stories, implement process
test-first, finite-state / evidence / collision / lossless / boundary disciplines, tier gate,
decisions, checkpoint) and pair-workflow-pr-phase (resume from checkpoint, publish through the
configured publish-pr skill, TEXT SHAPE, review-dispatch-required signal). The coordinator passes
$run $story $branch $worktree $base $stacked + the configured skill names + $notes; wtClause,
revWtClauseBase, TEXT_SHAPE, FINITE_STATE_COMPLETENESS and their sub-constants are gone. One run
directory per story for every phase (args.runId, default story-<id>); every invocation names its
story ("for story #<id>"). p3-verify owns its detached-worktree isolation. pair-implementer and
pair-contract-generator thinned to skill executors. Counts 52 → 55; catalogs, batch-engine.mdx,
ADR-024 updated. Dataset mirrors synced.

Tests: 375 workflow, 4905 knowledge-hub, 177 website.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…istory — workflowVersion, zero-prompt / zero-shell AC

pair-implement-batch.js: 56 changelog-style comment blocks (issue numbers, "measured", round-by-
round defect narration — 614 lines) compacted into behavioural comments; the defect history is
recorded once as an appendix of ADR-024. 1929 → 1671 lines (2222 at the start of US-479).
WORKFLOW_VERSION is returned with every result and handed to every phase skill as
$workflowVersion, so each handoff records the coordinator that produced it.

Acceptance criteria as tests: every agent dispatch is a skill invocation
(`Invoke **<configured skill>** for story #<id> with <typed args>`), no dispatched prompt carries
a git/gh/node command, none of the retired prompt rules survive in code, and the version reaches
every skill on every run.

Tests: 378 workflow, 4905 knowledge-hub, 177 website.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…skills run on every harness

red-snapshot.mjs and ensure-contract.mjs move from .claude/workflows/pair-contracts/ (a registry
that installs only in Claude Code) to .pair/knowledge/assets/, the channel every harness installs
(same as coverage-ratchet.cjs, ADR-023). red-seal, p3-verify and contract-phase invoke
`node .pair/knowledge/assets/<script>`; the dry-run tests and the contract cache's .gitignore stay
under pair-contracts/. Skill description examples no longer name this repo's PR (#480#42).
Dataset mirrors synced; ADR-024 and batch-engine.mdx updated.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ensure-contract.mjs ships in contract-phase/scripts/; red-snapshot.mjs ships in red-seal/scripts/
(seal) and, byte-identical, in p3-verify/scripts/ (verify) — red-snapshot.test.mjs fails if the
two copies (installed and dataset) drift. Each SKILL.md resolves its script from its own
directory ($SKILL_DIR/scripts/…), never from a repository path, so a skill is portable as one
folder on any harness. .pair/knowledge/assets/ no longer carries them. eslint ignores
dataset/.skills/**/scripts/*.mjs on the same one-artifact rule as the workflows. Dry-run tests
stay in .claude/workflows/pair-contracts/ and import the skill-local scripts.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rucka rucka added the risk:red Classification: high risk tier label Sep 9, 2026

@rucka rucka left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

risk:red · cost:greenCHANGES-REQUESTED — la trasformazione tecnica e i gate sono verdi, ma la story non ha AC verificabili e manca il canary end-to-end richiesto.

Open findings: 2.

PR: #480 · Author: rucka · Reviewer: rucka (self-review) · Date: 2026-09-09 · Story: US-479 · Type: refactor

Classification matrix — per dimension
Dimension Tier Source Note
Service/domain criticality green risk matrix Touched deployables listed Low.
Change/diff risk red 90-file diff Workflow/phase contract refactor.
Business impact green subdomain Generic development tooling.
Security relevance yellow security review Local config reaches shell boundaries; validation is security-adjacent.
Coupling balance green coupling review Typed phase contracts and mirror/identity tests keep boundaries balanced.

Tier is risk:red; cost is cost:green. Refinement floor unavailable because #479 is not refined.

Assessments

Security — Input validation

Verdict: yellow — workflow card/pipeline inputs reach shell-running agents; reject-path validation is present and tested.

Security — Output handling

Verdict: green — no web/API output surface added.

Security — Authentication

Verdict: green — no authentication surface changed.

Security — Authorization

Verdict: green — no authorization surface changed.

Security — Introduced vulnerabilities

Verdict: green — 0 introduced, 0 pre-existing findings.

Cost

Verdict: cost:green — no paid-provider, IaC, queue, scheduler, media, or LLM cost surface added.

Architecture (Coupling)

Verdict: green — phase handoffs are typed and skill-local scripts are identity-checked across their required copies.

Bug fix — Red test before fix

Verdict: not applicable — not a bug fix.

Details

Findings by severity

Critical

  • None.

Major

  • [Story #479 — Story Context] Acceptance criteria are explicitly “to be fixed during refinement”. Refine the story with measurable AC before merge; the review cannot validate the claimed workflow contract against an unrefined story.
  • [PR #480 — Testing / Story #479 DoD] The required end-to-end canary is still unchecked. Run one story through the new engine to ready-for-merge and attach durable evidence (run/phase handoffs, one first review, final synthesis).

Minor

  • None.

Questions

  • None.
Positive feedback
  • ADR-024 records the new phase-skill architecture.
  • Script copies and dataset mirrors are guarded; red-snapshot copies are byte-identical.
  • No new dependencies; CI and local full quality gate pass on da1eb9a.
Functionality & requirements
  • FAIL — story AC absent; required canary not executed.
  • The static workflow contract, phase dispatch, and mirror behavior are covered by the automated suite.
Testing & quality gates
  • PASS — pnpm quality-gate passed locally on PR head da1eb9a; published format, secret-scan, build, preview, and smoke checks are successful.
Adoption compliance
  • Level 1 — tech stack, architecture/ADR, security, coding standards, and infrastructure conformant. No unlisted dependency; ADR-024 is present.
Tech debt
  • 0 introduced items flagged.
Documentation
  • PASS — workflow documentation, skills catalog, and dataset mirrors updated.
Performance & deployment
  • No runtime hot-path or deployment change; rollback is the normal PR revert/squash workflow.

@rucka rucka added the pr-state:not-approved PR state: changes requested label Sep 9, 2026
@rucka

rucka commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Review finding 1 (Major — story AC) — resolved. #479 refined via /pair-process-refine-story + /pair-process-plan-tasks (non-interactive, assumptions recorded): 10 Given-When-Then AC (1–9 mapped to the automated suites, 10 = end-to-end canary), business rules, edge cases, classification risk:red · cost:green, DoD, sizing 8 pts, dependencies, validation strategy, technical analysis, task breakdown T-1…T-9 with dependency graph and AC-coverage table. Board: Refined, assignee set, risk:red label.

Finding 2 (canary) — in progress: pair-implement-batch running on #321 (risk:green, no prior branch) with runId: canary-479, maxParallelism: 1, from this branch's checkout. Evidence (run result, per-phase handoffs, agent count) is kept under .pair/working/canary/us-479/ (untracked working area) and summarized here.

…typed refusals are answers, handoffs in the main checkout

Canary run 1 (story #321, PR #481, runId canary-479): fases 0/A/B/C and the planner worked; the
RED author refused group r1-g1 as `split-required` — a guard-strength finding (positional-blind
assertion) with production already correct has no RED against unfixed production — and the engine
re-dispatched the identical prompt once before ending the card as failed-red-contract (8 agents).

- Third group mode `test`: allowedPaths [], RED proven against an injected regression, no GREEN,
  P3 verifies the sealed head; red-snapshot.mjs treats any production change under a test scope
  as `test-mode-production-change` (script test added; both copies synced).
- A typed refusal (`stale`, `split-required`; planner `stale`) is routed by status and never
  retried with the same prompt; the result carries `redRefusal` and `splitReason`.
- Handoff directory rule: `.pair/working/runs/<run>/<story>/` in the MAIN checkout the coordinator
  was started in, never a story/review worktree (the review's detached worktree took its handoff
  with it) — stated in every skill's $run row and in the dispatch text.

ADR-024 amended (§8–10); batch-engine.mdx and the remediation-plan description updated.

Tests: 382 workflow (+2 coordinator, +1 script), 4905 knowledge-hub, 177 website.

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rucka

rucka commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Canary run 1 (canary-479, #321 → PR #481) — fases 0/A/B/C and the planner worked (implementation committed test-first, PR opened with labels + pr-state, first review posted with the hidden marker, 3-group plan); the card ended failed-red-contract after 8 agents (≈580k subagent tokens, 46 min). Root cause: a guard-strength finding (positional-blind assertion, production already correct) has no RED against unfixed production, the RED author refused split-required, and the engine re-dispatched the same prompt once. Evidence for run 1 is under .pair/working/canary/us-479/run-1/ (untracked working area).

Fixed in d230cb7c (c8): test group mode (RED proven against an injected regression, no GREEN, any production change is a breach), typed refusals routed by status and never retried identically, handoff directory pinned to the main checkout. ADR-024 §8–10.

Canary run 2 (canary-479-run2, resume on PR #481) is running.

@rucka

rucka commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Canary run 2 (canary-479-run2, resume on PR #481) — 8 agents, ≈470k subagent tokens, 32 min, failed-red-contract.

What c8 fixed is confirmed live: the probe recognised the existing first review (silent fresh re-review), the planner emitted 4 groups including a test-mode group for the guard-strength finding, every handoff landed in the main checkout (review-phase, remediation-plan, red-spec, red-contract, red-verify), and the typed refusal path was not needed.

Where it stopped: group r1-g1 (behavioral, the $tool token-table finding). The RED author produced a 10-row contract; the independent verifier rejected 2 rows as non-discriminating; the one bounded repair produced 12 rows; the verifier rejected the headline row A5 (keyword co-occurrence over joined prose instead of an assertion bound to the item that states validity). Terminal per ADR-024 §6 (repair budget 1).

Reading: the engine behaved as designed; #321 is a poor canary for D1–D5 — every finding is a regex guard over SKILL.md prose, where a "discriminating RED" is genuinely hard and the verifier is right to refuse. Seal, GREEN and P3 have still not run live. Evidence: .pair/working/canary/us-479/run-2/.

…low; way-of-working Review Convergence note

Refs: #479

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on, never a login literal — unresolvable ⇒ typed refusal (t9d-17)

- resolveMaintainer: code-host-assignee, else default-assignee from way-of-working.md found above --dir; --maintainer overrides (source flag); absent ⇒ maintainer-unresolved:* before any PR read, nothing written; result reports maintainer { login, source }
- apply-scope-decisions + discovery; header + batch-engine.mdx aligned; ADL; llms.txt regenerated
- tests: adoption names alice (rucka refused), code-host wins, unresolvable refusal, CLI override; run-dir fixtures seed adoption; source scan for literals; 10 copies synced

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
…review check and the pr-state label — merge stays outside the engine (t9d-24)

- review-phase scripts/pr-state.mjs: conclude (status POST on the exact sha, label swap, read-back, idempotent, advisory when the token cannot post) / find; KB mapping of pr-state.sh; installed + dataset
- review-phase Step 5.7 (last non-partial reviewer; a non-decision publishes nothing); "never label" narrowed; published.reviewCheck/prState in the handoff and VERIFY_SCHEMA; run log reports them
- publish-pr Phase 5, pr-states.md "who does what", batch-engine.mdx aligned; ADL; ADR-024 amendment (w) records the giro-2 contract additions; llms.txt regenerated
- tests: pr-state.test.mjs (7) + coordinator schema/log

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
…xit path; host recipe placement on the workflow path (t9d-28, t9d-1)

- ADL: engine writes cards/PRs via gh only (GitHub as code host + PM tool, from Claude Code); typed refusal elsewhere; exit path = one cardTransport seam selected by adoption; to be promoted to a tech-debt issue by the maintainer
- finalize ADL addendum: the sandbox has no shell — no hook in pair-loop.js; `pair run` is the host for the full recipe (follow-up); pair-loop SKILL note (both copies)
- ADR-024 (w): both bullets + t9d-2 recorded as open with its design; batch-engine.mdx constraint; llms.txt regenerated

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
… --pr, quotePath-safe diff, comment body on stdin with a cap, flag aliases, status map, normalized scope identity (t9d-8/12/16/18/21/22/30)

- t9d-16: SHELL_METACHAR_RE / SHELL_UNSAFE reject control chars, redirects, `${}`, a leading flag, an interpreter prefix; closureAssertions[].command/testRef and reproducerRef checked by publisher AND coordinator
- t9d-18: manifestPathFor and the CLI require a numeric --pr
- t9d-21: `git -c core.quotePath=false diff --name-status` — a non-ASCII test path is unlisted-test-changed, never out-of-scope
- t9d-22: pr-comment sends the body via `--input -`; > 65536 chars is the typed error body-too-long before any write
- t9d-30: cycle-runtime accepts --repo|--repository everywhere; finalize --pr optional (publication not-applicable)
- t9d-12: coordinator maps failed-verify; conformance test pins the emitted reasons to the map
- t9d-8: scopeBaselineHashOf normalizes id/type (NFC, trim)
- tests in five suites; fakes accept --input -; copies synced

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
… note on where the contract tests run, supersession notes in ADR-024 (t9d-29/31/32/33)

- green-fix + review-phase Arguments tables gain the `$regressionGuards` row (both copies)
- every pair-contracts suite states it runs from .claude/workflows only (dataset copy is byte-identical, install-excluded, not executable in place)
- pair-loop.js halt rationale cites current statuses; ADR-024 (w): §2 paths and §6 `failed-red-contract` superseded, `telemetry` / `observe --publish-pr` never shipped

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
… run directories, and a sibling-run scan that does not need a PR (t9d-11/19/20)

- t9d-19: cycle-state, cycle-runtime, red-snapshot, pr-comment, pr-state refuse an unknown flag before anything runs (per-command FLAGS)
- t9d-20: safeRunDir — `--dir`/`--legacy` with a `..` hop is path-escape, a real path outside `.pair/working/runs/` (symlink) is path-outside-runs; `--file/--journal/--usage/--transcripts/--out/--result` are `..`-free; publish() and resolve() refuse at the JS entry too
- t9d-11: resolve scans sibling run directories by story, the PR narrowing only when known — a fresh-entry card adopts the existing cycle
- tests in five suites; 10 copies synced

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
…spatch resolves the template contract (t9d-2, AC-06)

- coordinator: CONTRACT state + `$contractSpec` on the first review; adoptTemplateContract recomputes the vocabulary constants (now `let`, recomputeVocabulary()) from `templateContract`; that one review is validated post hoc (verdict ∈ template options); VERIFY_SCHEMA declares templateContract; a caller floor the template cannot express fails the batch at adoption; `contracts[]` reports cache-hit | regenerated | fallback-loose | unresolved
- review-phase SKILL: `$contractSpec` argument + Step 0 bullet + output field (both copies); contract-phase note; batch-engine.mdx; ADR-024 (w) closing bullet
- tests: golden traces without the generator (cold 4, one fix 8, resumed 1), first review loose + second enum-locked, off-vocabulary verdict refused, stdDispatch rides templateContract on the first review

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review 5190603055 — dispositions

Findings not closed by code on this head, with their disposition:

id severity disposition
t9d-25 Minor External — lives in the card body of issue #479, not in this diff. Left to the maintainer.
t9d-28 Major Tech debt (ADL) — card transport is GitHub + Claude Code via gh; exit path is a single cardTransport seam. Recorded as an ADL tech-debt item, to be promoted to a tech-debt issue by the maintainer.
t9d-31 Minor Documentation — header note in the dataset contract tests.
t9d-32 Minor Documentation — header note in the dataset contract tests.
t9d-33 Minor Documentation — append-only supersession note in the ADR-024 amendment.
t9d-1 Major Fixed on the workflow path — no hook possible in pair-loop.js (no shell in the sandbox); follow-up host is pair run.
t9d-2 Major Fixed, residual by design — the one review dispatched before the contract is known runs on the loose skeleton and is validated post hoc.

All other Major and Minor findings of review 5190603055 are fixed across the 14 giro-2 commits, verified on head 5972a2af415ecf6a0c64c938fccffef3361e7255.


Generated by Claude Code

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review 5190603055 — questions

Dispositions for the 10 informational Questions, read against head 5972a2af (workflows suite 698/698, CI green). Line numbers are this head's; several moved under the giro-2 commits.

q-1 — issue_url cross-check keeps only the issue number. Confirmed: cycle-state.mjs:992 tests /issues/${prNum}$ against comment.issue_url, so owner/repo are discarded. Accepted as-is. It is defence-in-depth behind two stronger gates on the two lines above it — comment.user.type !== 'User' (author-not-a-user, :990) and comment.user.login !== who.login (author-not-authorized, :991), where who is now resolved from adoption rather than a literal (commit 1f7736f6, t9d-17). As the question itself notes, reaching it requires a substituted gh, which is already inside the trust boundary. No change; no residual risk beyond the gh-substitution premise.

q-2 — predecessorPhase('a0-rev2') is a0, so a -rev2 above a -rev1 skips the narrowing guard. Confirmed and deliberate, with the rationale in place at red-snapshot.mjs:176-186: n > 2 ? stem-rev(n-1) : stem collapses revision 2 onto the bare stem because canary run 11 saw a0-rev2 narrow a0's scope, and the guard must compare against the original contract, not the intermediate one. The consequence the question names is real but narrow: scopeNarrowing at red-snapshot.mjs:502 only fires when predecessorPhase(s.phase) === snaps[i-1].phase, so an a0-rev1 seal sitting directly between them is not compared. On PHASE_RE (cycle-state.mjs:101, ^(a0(?:-rev\d+)?|r\d+(?:-g\d+(?:-rev\d+)?)?|m\d+)$) admitting -rev1: that is intentional permissiveness in the validator, not a second naming convention — the engine emits the bare stem for revision 1 and nothing constructs -rev1. Residual, unrecorded. Worth an ADL note if the chain ever grows a third revision; not worth changing in this PR, since tightening predecessorPhase re-opens the run-11 defect it exists to close.

q-3 — title/notes are trusted caller instructions inlined into every prompt. Confirmed on the code: isProse (pair-implement-batch.js:188) rejects only backtick, $(, CR/LF and C0 controls, so ;, && and ${} pass, and the values reach the dispatch prompts verbatim (pair-implement-batch.js:1606-1614). This is coherent with the trust model and stays. On the documentation half of the question: the sentence it quotes is not present at this headbatch-engine.mdx carries no card-input content-validation claim at all (its only title/notes mentions are at :228-230, about AC bullet rewriting), so there is nothing contradicting the trust model to correct. Stating the boundary positively — the caller is inside it; the predicate guards prompt shape, not caller intent — remains a cheap docs follow-up, not a defect.

q-4 — publish unlinks the caller-named --file. Materially narrowed by 942b8ac0 (t9d-20). --file is now checked before any read or write: safePath('file', file) at cycle-state.mjs:1130 refuses any .. segment as path-escape, and the CLI entry re-checks at :2211. The unlink itself (:1211-1216) is also conditional now — if (basename(file) !== basename(target)) and wrapped in a bare catch {}. What remains: --file gets the ..-free check, not the full safeRunDir containment (:495-502) that --dir/--legacy get, so it is not root-constrained and its symlinks are not resolved. Residual, honest and small; the general shape (hand-copied parseCli/path regimes across 11 scripts) is the coupling proposal the review itself records under t9d-19/20.

q-5 — cohort files written without tmp+rename. Confirmed at cycle-metrics.mjs:953-954: cohort.json and cohort.md go out through plain writeFileSync(join(opts.out, …)), unlike the atomic tmp+rename every state write uses (e.g. cycle-state.mjs:1209-1210). Accepted. These are terminal report artifacts written once to a caller-named --out, read by no resume path and by no transition authority — a torn write costs a re-run of cohort, never a corrupted cycle. Not worth the divergence-risk of touching it in a remediation round.

q-6 — ensure-contract.mjs template/contract/draft paths unconstrained. Confirmed: ensure-contract.mjs:219-260 takes all three paths straight from argv with no containment check. Out of this PR's scope, as the question itself states — pre-existing, byte-identical to main, relocation only. The caller of these paths is the coordinator, inside the trust boundary. Carried alongside q-4 as part of the one-_cli.mjs coupling proposal rather than fixed piecemeal here.

q-7 — marker match is body.includes over every author. Confirmed and this is the one genuine residual risk in this bucket with no record. pr-comment.mjs:73 filters comments.filter(c => c.body.includes(marker)) with no author predicate, and :92 returns { error: 'marker-ambiguous', ids } on more than one hit — so any commenter who pastes an engine marker into a comment body can either wedge publication (marker-ambiguous) or have their comment PATCHed as the engine's own. The run-scoped markers added in this PR (pair-implement-batch.js:1591-1599, canary v9 C) fix cross-cycle overwrites, not planting: the marker is public in the comment they can read. Stated plainly: constraining the match to the engine's own login is the right fix and it is not in this PR, nor recorded in any ADR/ADL (grep over adr-024 and .pair/adoption/decision-log/ finds nothing on marker authorship). Recommend it be promoted as a tech-debt card through the transport recorded in .pair/adoption/decision-log/2026-09-13-tech-debt-card-transport-is-claude-code-plus-github-for-now.md (commit 012714dc, t9d-28) rather than left in this Questions list.

q-8 — [ $exitCode == 127 ] is a bash-ism under sh. Confirmed at .husky/_/husky.sh:31. Not this PR's file and not ours to fix: the file is husky's own generated shim, untracked in this repository (git log -- .husky/_/husky.sh is empty), so a change here would be overwritten by the next husky install. The observed effect matches the question — sh prints unexpected operator and the hook still exits 0, so the pre-push gate is unaffected. No action; upstream husky issue.

q-9 — dataset/.skills/**/scripts/*.mjs left unlinted. Intended, and the rationale is stated at the ignore itself (tools/eslint-config/eslint.config.cjs:132-138): the dataset copy and the installed copy under .claude/skills/ must stay one artifact, so they share one lint policy — none — exactly as dataset/.workflows/ already does at :133. Linting the canonical copy only is not available as a middle ground: it would make the dataset copy fail rules the root copy is never checked against, and byte identity (pinned by the distribution tests, 15/15 pairs) would then be unachievable without lint-clean edits to both. The real guard on these ~13.7k lines is executable, not stylistic: the pair-contracts/ dry-run suites run against them (698 tests at this head) and the differential tests assert every copy returns the same verdict.

q-10 — ADR-024 has no ## Adoption Impact; skills-catalog.mdx date is stale. Both confirmed OPEN at this head. adr-024-delivery-phases-are-skills.md has Status / Date / Context / Options Considered / Decision / Consequences / References / Appendix plus 24 amendments, and no ## Adoption Impact section (adr-template.md:52). skills-catalog.mdx:7 still reads Last updated: 2026-09-08 — the docs:staleness gate counts skills, not dates, so it passes. Both are documentation hygiene with no behavioral effect; neither blocks. Cheapest disposition is to fold them into the next ADR-024 amendment rather than spend a remediation round on them.


Summary. Accepted as designed: q-1, q-3 (code half), q-5, q-9. Out of scope / not ours: q-6, q-8. Deliberate with a stated rationale: q-2. Materially narrowed by 942b8ac0: q-4. Genuine unrecorded residual risk: q-7 (constrain the marker match to the engine's login). Open documentation hygiene: q-10, plus the optional docs note for q-3.


Generated by Claude Code

…t run (t9d-25)

Records the maintainer's decision as an ADL, so the requirement no longer
lives only in a chat comment (t9d-25) and the card's T-8 line has a source:

- T-8's paired 2.0.0 vs 4.0.0 measurement will NOT be run: the full engine
  cycle already shows a clear improvement, and the 2.0.0 baseline cannot be
  measured from this environment (no session, token usage not observable)
- evidence accepted in its place: canary v3 (done + APPROVED review) and
  canary v9 (first fully autonomous cycle on PR #481, APPROVED on b733e06)
- DT-36 and the matched-cost half of AC-14 are unevidenced BY DECISION, not
  by omission; a paired baseline, if wanted, becomes a separate story
- cross-references ADR-024 (h)/(i)-F4/(v) and story #479, PR #480
- .pair/llms.txt regenerated

No engine, script or guideline behaviour changes.

Refs: #T-8, #T-9

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
…an accepted risk with its exit path

An author predicate is not resolvable from what the engine has: `GET /user` is 403 for an
installation token and refused by the canary sandbox proxy, GraphQL `viewer` is blocked, `gh auth
status` carries no identity, and the PR author is not the engine (#480: `rucka` vs `claude[bot]`).
The publishing identity also VARIES per environment — #480 carries marker-bearing pair comments by
both — so an own-author predicate would blind the engine to its own earlier publication, duplicate
it, and then wedge on `marker-ambiguous` by itself. Recorded instead of guessed:

- ADL 2026-09-13-pr-comment-marker-matching-stays-author-blind.md (risk, why accepted, exit path:
  an adoption-declared publishing identity resolved like the scope-decision principal).
- The same note at the code site, byte-identical across the 4 `pr-comment.mjs` copies.
- Characterization test pinning both accepted outcomes (a foreign carrier is PATCHed, two carriers
  refuse) and that authorship never reaches the engine — it MUST fail when the exit path is taken.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
…n, and the catalog's date is gated like its rows

- ADR-024 `## Adoption Impact`: which way-of-working sections carry the rules a cycle obeys, the
  ADLs that hold the delegated decisions, and that tech-stack/architecture/infrastructure are
  deliberately untouched.
- `skills-catalog.mdx` header: 2026-09-08 -> 2026-09-13.
- The gate now compares that header against `git log -1` on the dataset skills tree
  (`checkCatalogFreshness`, Check 2d): every sibling check counted skills, so the stale date was
  invisible. Both degenerate cases (unparsable header, unresolvable source date) fail loudly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

q-7 and q-10 closed — the last two open items of the independent pass over review 5190603055.

q-7 (residual security risk, pr-comment.mjs marker matching)6a3598c8's parent f979c817: recorded as an ADL, not fixed with an author predicate, because the predicate is not resolvable from what the engine has — GET /user is 403 for an installation token and refused outright by the canary sandbox's proxy, GraphQL viewer is blocked, gh auth status carries no identity, and the PR author is not the engine (this PR: rucka, its engine comments claude[bot]). The publishing identity also legitimately varies per environment: this PR carries marker-bearing pair comments authored by both, so an own-author predicate would have blinded the engine to its own earlier publication, duplicated it, and then produced the marker-ambiguous wedge by itself. ADL 2026-09-13-pr-comment-marker-matching-stays-author-blind.md records the risk, why it is accepted (bounded blast radius — a comment body, recoverable from edit history, or one halted publication; never a merge, a label, a check conclusion or a secret) and the exit path (an adoption-declared publishing identity resolved the way the scope-decision principal already is, then findByMarker filters to it: a foreign carrier is ignored and never blocks publication, an own-author duplicate still refuses). The same note sits at the code site in all four byte-identical pr-comment.mjs copies, and a characterization test pins both accepted outcomes plus the fact that authorship never reaches the engine — it must fail when the exit path is taken.

q-10 (docs hygiene)6a3598c8: ADR-024 gains its ## Adoption Impact section (which way-of-working sections carry the rules a cycle obeys, which ADLs hold the delegated decisions, and that tech-stack / architecture / infrastructure are deliberately untouched); skills-catalog.mdx moves 2026-09-08 → 2026-09-13, and that header is now gated against git log -1 on the dataset skills tree (checkCatalogFreshness, Check 2d) so it cannot go stale again while the skill-count checks stay green — both degenerate cases (unparsable header, unresolvable source date) fail loudly.

Verification: pnpm workflows:test 699 pass (pr-comment suite 13, +1), @pair/knowledge-hub 4900 pass (48 files, KB mirror suites included), docs-staleness unit suite 151 pass (+7), pnpm quality-gate green.


Generated by Claude Code

@claude

claude Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review 5190603055 — closing synthesis

All 33 findings of review 5190603055 are closed on head 585d57ce — 31 FIXED in code/docs, 1 DISPOSITIONED (recorded tech debt with an exit path), 1 OUT-OF-SCOPE (external card, since closed by its owner). Every row below was verified by reading the cited file at 585d57ce and confirming the behaviour the finding demanded — not from commit subjects. The review was submitted against 61703560; the 23 commits 61703560..585d57ce are the delta.

Update (585d57ce) — the two residuals this synthesis had listed as unclosed were re-verified and dealt with: t9d-6's requested fixture already existed (the earlier listing was wrong, corrected in its row below and proved by inversion), and t9d-8's missing producer is now shipped in 585d57ce. The "not verified" list below is shorter by both.

Findings

id sev transition where why / what changed
t9d-1 Major FIXED d8646222 + 012714dc · ADL finalize has two legitimate callers decided by evidence on disk: review-phase SKILL.md:113 (Step 5.3) runs cycle-runtime.mjs finalize itself when neither .runtime-checkpoint.json nor .run-terminal.json exists; pair-loop SKILL.md:85 states the sandbox limit and names pair run as the shell host. Coordinator gate verified at pair-implement-batch.js:1883-1884 — next.step: done + metrics.owner: review-phase + published.synthesis !== truefailed-publication, never ready-for-merge.
t9d-2 Major FIXED 5972a2af No generator-only dispatch remains. pair-implement-batch.js:1413-1443: the template contract is resolved by the FIRST review dispatch ($contractSpec → contract-phase skill → adoptTemplateContract); the only contractPhase references are the skill ref (:503) and that argument (:1422). Residual by design: the one review dispatched before the vocabulary is known runs on the loose skeleton and is validated post hoc (vocabularyErrors).
t9d-3 Major FIXED 128e8c70 pr-comment.mjs:41-67 splitPages is string-aware (string/escape state machine); arr[0 in any body no longer hides a page, an unterminated page throws typed. Test rows for both bodies at pr-comment.test.mjs:159,177.
t9d-4 Major FIXED ca12edb6 cycle-metrics.mjs:242-262 readTerminalMarker/applyTerminalOutcome feed the engine's real terminal status into the typed delivery enum (reason: terminal:<status>), consumed at :309 and :542; cohortStateOf now derives from that delivery.
t9d-5 Major FIXED ca12edb6 cycle-runtime.mjs:740-756: the publishSummary transport error is caught into {published:false, publication:{state:'failed', lastError:'transport: …'}} and writeMetrics runs after it — the local view is written first, the exception never escapes finalize.
t9d-6 Major FIXED 1fa108aa (re-verified at 585d57ce) pair-implement-batch.js:1699 expectedBlocking now opens with `f.regressionRisk?.state === 'active'
t9d-7 Major FIXED e535507a cycle-state.mjs withLock: the lock dir carries an owner file (pid/host/startedAt), inspectLock breaks dead-owner/orphan-stale and reports brokeStaleLock, and a live-but-old holder returns the typed stale-lock instead of wedging forever.
t9d-8 Major FIXED c2d62e01 + c594323c · ADL cycle-state.mjs scopeBaselineHashOf hashes {id, type} — NFC-normalized and trimmed — never the reviewer's prose; apply-scope-decisions with no --decision-ref discovers the maintainer's standing decision on the PR (discoverScopeDecisions), so awaiting-scope-decision has a mechanical exit with no re-post. Residual closed in 585d57ce · ADL: the hash the SKILL asks the reviewer to publish now has producers, because the consumer requires the field (scopeBaselineHash-missing, then stale-baseline) — so the prose was right and the surface was missing. resolve's awaiting-scope-decision payload carries scopeBaselineHash next to the scopeChanges it hashes; cycle-state.mjs scope-baseline --dir <run dir> is the standalone producer for the PR-scoped packet a later cycle re-edits (read-only, no gh), named in the CLI vocabulary line and flag-checked; a new pendingScopeOf is the ONE union both the producer and the consumer read, so the baseline a packet quotes and the baseline it is checked against cannot be computed two ways; review-phase SKILL.md Step 5.4b (both copies) names both producers and forbids a hand-made value. Two t9d-8 conformance tests pin resolve's field, the command + its flags, and the prose in the installed and dataset SKILL — each half proved RED before the fix.
t9d-9 Major FIXED c168c37b red-snapshot.mjs:437-457: verifyChain takes --run-dir, derives expectContract from the sealed handoffs found there, and a --contract-expected false beside a sealed handoff is the typed breach contract-expected-refused with the strict walk run anyway. review-phase SKILL.md:65,68 now passes --run-dir "$RUN_DIR" ALWAYS.
t9d-13 Major FIXED 48cfaeb3 green-fix SKILL.md:75 now prescribes findings: [{ id, transition, … }] as an ARRAY and states that the {received, resolved} object belongs to red-spec only (findings-not-an-array otherwise); the publisher carve-out at cycle-state.mjs:290-294 is explicitly red-spec-scoped. Fixture at cycle-state.test.mjs:2278-2300.
t9d-17 Major FIXED 1f7736f6 · ADL cycle-state.mjs:948-963 resolveMaintainer reads code-host-assignee then default-assignee from the adopted way-of-working above --dir; --maintainer overrides; unresolvable is the typed refusal maintainer-unresolved:* (fail closed, no PR read, no write). No 'rucka' literal survives in any shipped script — only in test fixtures.
t9d-24 Major FIXED 44225290 · ADL New pr-state.mjs (144 lines) shipped in review-phase: conclude publishes the required pair-review check on the exact head verified and synthesizes the ONE pr-state:* label, with pr-state.sh's review_check_conclusion semantics verbatim (anything but approved/changes-requested publishes NOTHING, so merge stays blocked). Merge stays outside the engine.
t9d-26 Major FIXED 57a59d3c cycle-state.mjs:1474-1490 computes the reconstruct directive once per rewind batch and attaches it to the green step as well as the preparation; pair-implement-batch.js:1674 (green dispatch) carries $reconstruct, and :1758-1759 logs its delivery. The fixer now receives fromHead/paths/riskIds/notes.
t9d-27 Major FIXED 66dcfcf3 review-phase SKILL.md:21 rewritten: $synthesisMarker is "Passed for reference only: the synthesis is PUBLISHED by cycle-runtime.mjs finalize … never upsert it yourself" — the Arguments table and Step 3 now say one thing.
t9d-28 Major DISPOSITIONED .pair/adoption/decision-log/2026-09-13-tech-debt-card-transport-is-claude-code-plus-github-for-now.md (012714dc) The missing-ADR HALT condition is discharged by recording the decision, not by routing through the adopted writer: card transport is GitHub + Claude Code via gh, with a single cardTransport seam as the exit path. To be promoted to a tech-debt issue by the maintainer.
t9d-10 Minor FIXED 43fa3706 pair-implement-batch.js:1613-1625: acceptedFindings is keyed on the STABLE id alone, latest row replacing the earlier one in place — one row per id.
t9d-11 Minor FIXED 942b8ac0 cycle-state.mjs:1958-1970: the sibling-run scan is by STORY, with the PR only narrowing it — a fresh-entry card with no PR now finds the cycle beside it instead of starting a second one.
t9d-12 Minor FIXED c594323c pair-implement-batch.js:1649: 'failed-verify': 'failed-verify' is in the status map; the two vocabularies agree.
t9d-14 Minor FIXED 48cfaeb3 Every documented publish line in red-verify, green-fix and review-phase SKILL.md now spells --workflowVersion $workflowVersion; pinned by cycle-state.test.mjs (canary v9 E/F/G suite).
t9d-15 Minor FIXED 48cfaeb3 review-phase SKILL.md:103 states the predicate where the field is prescribed: publish refuses worked-evidence-unsafe:<id> for a command containing shell metacharacters.
t9d-16 Minor FIXED c594323c cycle-state.mjs:97 SHELL_METACHAR_RE now rejects <, >, CR/LF, C0 controls, ${, a leading - and a bare shell binary; one predicate is applied to every command-bearing field — reproducerRef (:333), closureAssertions[].command (:338) and .testRef (:339), reproducer.command (:353), counterexample.command (:410), worked[].evidence[].command (:445).
t9d-18 Minor FIXED c594323c red-snapshot.mjs:76-77 manifestPathFor throws unless pr is /^\d+$/, and the CLI re-checks at :600.
t9d-19 Minor FIXED 942b8ac0 A closed per-command flag set with unknown flag(s) for <cmd> in all five scripts: cycle-state.mjs:2189, cycle-runtime.mjs:825, red-snapshot.mjs:592, pr-comment.mjs:130, pr-state.mjs:114.
t9d-20 Minor FIXED 942b8ac0 safeRunDir/safePath exported from cycle-state.mjs:495-505 and applied before anything runs: cycle-state.mjs:2206-2211 and cycle-runtime.mjs:840-845 root-contain --dir and reject .. on every other path flag (journal, usage, transcripts, out, result, file, legacy, runsRoot, cwd).
t9d-21 Minor FIXED c594323c red-snapshot.mjs:376 and :525 both run git -c core.quotePath=false diff --name-status; a non-ASCII test path is classified correctly, not as out-of-scope.
t9d-22 Minor FIXED c594323c pr-comment.mjs:87-96: MAX_COMMENT_CHARS = 65536 refused typed as body-too-long BEFORE any write, and the body travels on --input - (stdin) in both the POST and the PATCH — no E2BIG, no body echoed into the agent's context.
t9d-23 Minor FIXED 177a85c6 pair-implement-batch.js:1598 firstReviewMarker() carries run:${runId}, and synthesisMarker (cycle-runtime.mjs:705) does the same; a new cycle on the same PR never edits the previous cycle's first review.
t9d-29 Minor FIXED d9ae2747 $regressionGuards has its Arguments row in green-fix SKILL.md:28 and review-phase SKILL.md:33 — no longer introduced mid-prose.
t9d-30 Minor FIXED c594323c cycle-runtime.mjs:821-822 aliases --repo/--repository on every command, and finalize (:850-853) requires only dir+repo — S8's no-PR publication.state: 'not-applicable' path is reachable from the CLI.
t9d-31 Minor FIXED d9ae2747 All 11 dataset contract suites carry the header note ("RUNS FROM .claude/workflows ONLY (t9d-31) … execute via pnpm workflows:test, never in place there"). Verified 11/11 files.
t9d-32 Minor FIXED d9ae2747 ADR-024:1273-1277: §2's red-seal//p3-verify/ locations and §6's failed-red-contract are recorded as superseded (failed-contract is the only spelling the engine emits), together with pair-loop's removed halt rationales.
t9d-33 Minor FIXED d9ae2747 ADR-024:1278-1281 records both never-shipped S7 surfaces as superseded: the telemetry batch argument (rejected as an unknown key by design) and observe --publish-pr true (usage enters through observe --journal/--usage/--transcripts).
t9d-25 Minor OUT-OF-SCOPE (external) → since closed on the card b767d451 (repo side) · ADL · issue #479 (card side) Never in this diff. Re-read of issue #479 at this head: the body now contains S1–S13 (lines 220–475) AND the T-19–T-31 checklist (lines 509–522), so the completeness defect the finding reported is gone. The repo-side half — T-8's paired 2.0.0/4.0.0 measurement is not run, with the full-cycle canary evidence standing in its place — is recorded as an ADL. One stale line remains on the card: the D5 header still reads "S1–S11, AC-01–29 and DT-01–38 … T-19–29" while the body carries S12/S13, AC-32, DT-41 and T-30/T-31.

Questions (10) — one-line dispositions

Re-verified at 6a3598c8; line numbers are this head's. Two dispositions changed since the earlier questions comment (written on 5972a2af) and are corrected here.

  • q-1issue_url cross-check keeps only the issue number (cycle-state.mjs:992). Accepted as-is: defence-in-depth behind two stronger gates on the lines above — author-not-a-user (:990) and author-not-authorized (:991), the principal now resolved from adoption. Reaching it needs a substituted gh, already inside the trust boundary.
  • q-2predecessorPhase('a0-rev2') collapses to a0 (red-snapshot.mjs:181-186). Deliberate, rationale in place: canary run 11 saw a0-rev2 narrow a0's scope, so the guard must compare against the ORIGINAL contract. Narrow consequence (an a0-rev1 sitting directly between is not compared); PHASE_RE admitting -rev1 is validator permissiveness, nothing constructs it. Residual, unrecorded — worth an ADL only if the chain grows a third revision.
  • q-3title/notes are trusted caller instructions inlined into prompts (isProse, pair-implement-batch.js:188). Coherent with the trust model, stays. The documentation sentence the question quotes is not present at this head (batch-engine.mdx carries no card-input content-validation claim), so there is nothing to correct; stating the boundary positively remains a cheap docs follow-up.
  • q-4publish unlinks the caller-named --file. Materially narrowed by 942b8ac0: safePath('file', file) at cycle-state.mjs:1130 refuses any .. segment as path-escape before any read or write, and the CLI re-checks at :2211. Residual, small and honest: --file gets the ..-free check, not the full safeRunDir containment --dir/--legacy get.
  • q-5 — cohort files written without tmp+rename (cycle-metrics.mjs:953-954). Accepted: terminal report artifacts written once to a caller-named --out, read by no resume path and no transition authority — a torn write costs a re-run of cohort, never a corrupted cycle.
  • q-6ensure-contract.mjs:219-260 template/contract/draft paths unconstrained. Out of this PR's scope, as the question states: pre-existing, byte-identical on main, relocation only; the caller is the coordinator, inside the trust boundary. Carried with q-4 under the one-_cli.mjs coupling proposal.
  • q-7 — marker match is body.includes over every author (pr-comment.mjs:76-78, marker-ambiguous at :96). CORRECTED since the earlier comment, which called this an unrecorded residual risk: it is now RECORDEDf979c817 adds .pair/adoption/decision-log/2026-09-13-pr-comment-marker-matching-stays-author-blind.md, accepting the planting risk with its exit path and documenting why the author predicate cannot be resolved from what the engine has (GET /user 403 for an App installation token and refused by the agent proxy; GraphQL viewer blocked on this host). Accepted and recorded, not fixed in code.
  • q-8[ $exitCode == 127 ] is a bash-ism under sh (.husky/_/husky.sh:31). Not this PR's file and not ours to fix: husky's own generated shim, untracked here, overwritten by the next husky install. The hook still exits 0, so the pre-push gate is unaffected. Upstream issue.
  • q-9dataset/.skills/**/scripts/*.mjs left unlinted (tools/eslint-config/eslint.config.cjs:135-138). Intended, rationale stated at the ignore itself: the dataset copy and the installed copy must stay one artifact, so they share one lint policy — none, exactly as dataset/.workflows/ at :133. Linting the canonical copy only would make byte identity unachievable. The real guard on these lines is executable: the pair-contracts/ suites run against them.
  • q-10 — ADR-024 missing ## Adoption Impact; stale catalog date. CORRECTED since the earlier comment, which found both OPEN: both are now CLOSED by 6a3598c8 — ADR-024 has ## Adoption Impact at line 441, skills-catalog.mdx:8 reads Last updated: 2026-09-13, and the date is no longer ungated: apps/website/lib/docs-staleness-check.ts:607-655 adds check 2d, which parses the header date and fails when the page dates itself before the dataset skills it describes.

Current state of the head

  • Head verified: 585d57ce2acf28c610344a12497271dd5ca7eee0 (was 6a3598c8; 585d57ce is the single t9d-8 commit added by this pass — t9d-6 needed no commit). PR [US-479] refactor: delivery workflow TO BE — coordinator + phase skills, one squash with the 2026-09-08 hardening #480 is still a draft; labels unchanged (user story, risk:red, pr-state:not-approved).
  • CI on 585d57ce — in flight, not green-claimed. secret-scan already completed/success; build, smoke, format and preview were in_progress when this comment was written. The previous head 6a3598c8 was 5/5 success (CI run 34761821423, Format, Website Preview Deploy). The build job is where the adopted gate runs: ts:check, build, lint, hygiene:check, smoke-modes:check, docs:staleness, skills:conformance, dup:check, workflows:test, test, coverage thresholds and the coverage guardrail (fixed tier=red).
  • Adopted quality gate — pass, run in FULL locally on 585d57ce. pnpm quality-gate exits 0 (22/22 turbo tasks): pnpm workflows:test 701/701 pass, 0 fail (699 before, +2 for t9d-8), package suites 8351 pass (knowledge-hub 4900, pair-cli 1862, content-ops 754, dev-tools 573, website 184, brand 78), gate:composition PASS (50 skills, 11 commands in sync), skills:conformance PASS (50 skills), hygiene:check / smoke-modes:check / docs:staleness / dup:check / format:check all pass.
  • Byte-identity of the replicated engine holds: all 5 installed cycle-state.mjs copies and all 5 dataset mirrors hash identically (4896095e… after 585d57ce), and pair-contracts/cycle-state.test.mjs matches its dataset mirror byte for byte.
  • pair-review check: NOT published, and it cannot be published from this environment. Verified on 585d57ce as on 6a3598c8: the combined status is pending with an empty statuses[] — no pair-review context exists. The status POST is refused by the sandbox proxy, so the check and the pr-state label are left exactly as they are; pr-state:not-approved still reflects the 61703560 round, not this head. No check run was published and no label was touched by this pass. Concluding the check and synthesizing the label is now the shipped pr-state.mjs conclude path (t9d-24) — it needs a shell host with a repo:status token.

Not verified — listed as open, not claimed closed

Closed since this list was first written (both on 585d57ce): the former item 1 (t9d-6's missing fixture) was a reading error in this synthesis, not a gap — the fixture is at pair-implement-batch.test.mjs:600-621 and goes RED against the pre-fix condition; nothing was committed for it. The former item 2 (t9d-8's absent producer) is now shipped: resolve publishes scopeBaselineHash, cycle-state.mjs scope-baseline prints it, the prose names both, and two tests fail if any of the three drifts. One residual half is deliberately left: the entry capsule (cycle-runtime.mjs) still treats the field as optional — it is the host's launch record, not the packet author's input, so it needs no producer.

  1. t9d-1 residual: no shipped executable runs the host recipe unattended. The synthesis now reaches the PR through the reviewer's fallback, which is verified; the recipe itself is still only the ADR bash block and recipe.test.mjs, and pair run is named as a follow-up host. Documented, not shipped.
  2. q-7's preferred fix is not implemented — the marker match stays author-blind. Accepted and recorded (see above), so no longer unrecorded, but the planting risk is live.
  3. AC-10 / AC-14 / AC-22 (live cohort) / AC-28 remain unproven on this head, as the review found. T-8's paired 2.0.0/4.0.0 measurement is recorded as not run (ADL, b767d451) rather than performed; no new live canary, no real cohort and no token measurement was executed in producing this synthesis. These are AC-level, outside the 33 findings, and none of the rows above claims them.
  4. Every transition above is verified statically — the cited file read at 585d57ce, plus the 701-test dry-run suite and the full local quality gate. No fix was re-exercised against a live unattended run from this environment.
  5. The pair-review POST refusal is relayed, not re-tested. I confirmed the absence of the status on the head; I did not attempt the POST, since publishing checks is outside this mandate.

Generated by Claude Code

…e publishes it, `scope-baseline` prints it, the prose names both (t9d-8)

`apply-scope-decisions` refuses the maintainer's comment without `scopeBaselineHash`
and refuses a wrong one, but no participant could produce the value: no CLI command
printed it and `resolve`'s `awaiting-scope-decision` payload omitted it, while the
review-phase SKILL told the reviewer to put it in the packet.

- `resolve` carries `scopeBaselineHash` next to the `scopeChanges` it hashes
- `cycle-state.mjs scope-baseline --dir <run dir>`: standalone producer, read-only, no `gh`
- `pendingScopeOf`: one union for producer and consumer — the baseline cannot be computed two ways
- Step 5.4b names both producers and forbids a hand-made hash
- t9d-8 conformance: resolve's field, the CLI command + flags, the prose in both copies
- ADL: the scope-baseline hash is published to the reviewer

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0147cVywTQGNNvQBhcUPsmKU
@rucka rucka removed the user story Work item representing a user story label Sep 13, 2026
@claude claude Bot added pr-state:ready-to-merge PR state: gates green + review approved and removed pr-state:not-approved PR state: changes requested labels Sep 13, 2026
@rucka

rucka commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict

risk:red · cost:greenAPPROVED — ready to merge — all 33 findings of review 5190603055 are fixed or dispositioned on head 585d57ce, CI is green, the local gate is green, and custody/mirror byte-identity holds.

Open findings: 0. 33/33 closed — 31 FIXED in code/docs, 1 DISPOSITIONED (recorded tech debt with an exit path, t9d-28), 1 OUT-OF-SCOPE (external card, since closed by its owner, t9d-25). All 10 Questions carry a recorded disposition; none block. Nothing on this PR is waiting on anyone.

PR: #480 · Author: rucka · Reviewer: independent closing reviewer (final pass over review #5190603055) · Date: 2026-09-13 · Story: US-479 · Type: refactor (engine 4.0.0)

Classification matrix — per dimension
Dimension Tier Source Note
Service/domain criticality green Criticality Table every touched deployable is listed Low
Change/diff risk red diff footprint 115 files, +53571/−7516 vs main; coordinator, five phase skills, six host scripts, caller
Business impact green Development Tooling Standards (Generic) internal delivery tooling
Security relevance red (raise-only) manual security pass, assess-security lens the 4 findings that raised this (t9d-9, t9d-16, t9d-18, t9d-20) are all FIXED per the closing synthesis
Coupling balance yellow manual assess-coupling $scope=diff structural note unchanged (5×2 byte-pinned copies); every CLI-helper defect it flagged (t9d-16/18/19/20/21) is FIXED, nothing open

Tier = max(assessed) = red, confirmed not lowered (review floor, D17) — held at red on the strength of diff footprint alone even with every finding closed. Cost = green — no infrastructure, provider or SaaS surface in the diff (review 5190603055's own classification, unchanged).

Assessments

Security — Input validation

Verdict: green — resolved. Originally red: agent-returned command strings and script path flags were not held to the coordinator's validation bar (review 5190603055, Security — Input validation). Closed: t9d-9 (FIXED, c168c37b), t9d-16 (FIXED, c594323c), t9d-18 (FIXED, c594323c), t9d-20 (FIXED, c594323c) — closing synthesis.

Details
  • No Critical/Major/Minor finding against output handling, authentication or authorization was raised by review 5190603055 — those three template sections carry no open item and are not separately re-broken-out here.
  • q-4 (publish unlinking a caller-named --file) and q-7 (marker match is author-blind in pr-comment.mjs) are the two Questions with residual risk; both are recorded, not fixed in code — q-4 materially narrowed by 942b8ac0 (safePath refusing ..), q-7 accepted with an ADL (2026-09-13-pr-comment-marker-matching-stays-author-blind.md) and a bounded blast radius (a comment body, never a merge/label/check/secret) — see the q-7/q-10 closure comment and the closing synthesis.

Security — Introduced vulnerabilities

Verdict: green — 0 open (4 introduced, 4 fixed; 0 pre-existing raised).

Details
Severity Category File:location Introduced / pre-existing Disposition
Major Input validation cycle-state.mjs (t9d-9, t9d-16) introduced FIXED
Minor Path traversal red-snapshot.mjs (t9d-18), cycle-state.mjs/cycle-runtime.mjs (t9d-20) introduced FIXED

No introduced red security finding remains open — the introduced-red-security rule does not fire. Source: closing synthesis.

Cost

Verdict: cost:green — no infrastructure, provider or SaaS surface in the diff (review 5190603055 classification matrix, unchanged since).

Details
Signal Class Provider Note
none detected green n/a internal delivery-tooling diff only

Architecture (Coupling)

Verdict: yellow — structural note stands, no open finding. The 5×2 byte-pinned cycle-state.mjs copies remain the coupling shape (unchanged by design); the hand-copied parseCli/isMain/cleanGitEnv helpers that were unguarded and where the CLI defects landed are now covered — t9d-16, t9d-18, t9d-19, t9d-20, t9d-21 all FIXED per the closing synthesis. Tech-debt item (hand-copied helpers, no identity guard) remains surfaced, not blocking — carried in the review's own Tech debt section.

Bug fix — Red test before fix

Verdict: not applicable — not a bug fix. PR type is refactor (US-479, engine 4.0.0); no bug/defect reference. Where remediation did add regression coverage for closed findings (e.g. t9d-6's fixture, t9d-16/18/19/20/21 characterization tests), it is cited per-finding above and in the closing synthesis, not required by this check.

Details

Findings by severity — all 33 closed (source: review 5190603055, dispositioned/closed in the dispositions comment and the closing synthesis)

Critical — closed (0 raised)

  • none

Major — closed (15/15)

  • t9d-1 — Fixed on the workflow path (no shell hook possible in the sandbox; pair run named as follow-up host).
  • t9d-2 — Fixed, residual by design (pre-vocabulary review runs on the loose skeleton, validated post hoc).
  • t9d-3 — FIXED, 128e8c70pr-comment.mjs splitPages made string-aware.
  • t9d-4 — FIXED, ca12edb6 — terminal status feeds the typed delivery enum.
  • t9d-5 — FIXED, ca12edb6publishSummary transport error caught, local metrics view written first.
  • t9d-6 — FIXED, 1fa108aa, re-verified at 585d57ce — the conformance fixture this synthesis had first (wrongly) reported absent does exist (pair-implement-batch.test.mjs:600-621); reading error corrected, nothing further to ship.
  • t9d-7 — FIXED, e535507a — stale-lock detection (dead-owner/orphan-stale/stale-lock).
  • t9d-8 — FIXED, c2d62e01 + c594323c, residual closed in 585d57cescopeBaselineHash now has a standalone producer (cycle-state.mjs scope-baseline), pinned by two conformance tests.
  • t9d-9 — FIXED, c168c37bverifyChain --run-dir always passed; contract-expected-refused typed breach.
  • t9d-13 — FIXED, 48cfaeb3findings schema fixed to an array outside red-spec.
  • t9d-17 — FIXED, 1f7736f6 — maintainer resolved from adoption, no hard-coded login, fail-closed refusal.
  • t9d-24 — FIXED, 44225290pr-state.mjs conclude ships, publishing the required pair-review check + pr-state:* label.
  • t9d-26 — FIXED, 57a59d3c — rollback directive ($reconstruct) now reaches the fixer.
  • t9d-27 — FIXED, 66dcfcf3 — synthesis-marker prose corrected (published by finalize, never upsert).
  • t9d-28 — DISPOSITIONED — Tech debt (ADL, 2026-09-13-tech-debt-card-transport-is-claude-code-plus-github-for-now.md, 012714dc); card transport recorded, single cardTransport exit seam; to be promoted to a tech-debt issue by the maintainer. Source: dispositions comment, confirmed in the closing synthesis.

Minor — closed (18/18)

  • t9d-10 — FIXED, 43fa3706acceptedFindings keyed on stable id, one row per id.
  • t9d-11 — FIXED, 942b8ac0 — sibling-run scan by story, not PR.
  • t9d-12 — FIXED, c594323cfailed-verify status-map entry added.
  • t9d-14 — FIXED, 48cfaeb3--workflowVersion spelled consistently across skills.
  • t9d-15 — FIXED, 48cfaeb3worked-evidence-unsafe predicate documented where prescribed.
  • t9d-16 — FIXED, c594323cSHELL_METACHAR_RE hardened, applied to every command-bearing field.
  • t9d-18 — FIXED, c594323cmanifestPathFor throws on a non-numeric pr.
  • t9d-19 — FIXED, 942b8ac0 — closed per-command flag sets, unknown flag(s) typed error, all five scripts.
  • t9d-20 — FIXED, c594323csafeRunDir/safePath root-contain every path flag.
  • t9d-21 — FIXED, c594323c — non-ASCII test paths classified correctly (core.quotePath=false).
  • t9d-22 — FIXED, c594323cMAX_COMMENT_CHARS typed refusal before write; body travels via stdin.
  • t9d-23 — FIXED, 177a85c6 — first-review/synthesis markers carry run:<id>, no cross-cycle edits.
  • t9d-25 — OUT-OF-SCOPE (external), since closed on the card — never in this diff; card completeness defect on issue Delivery workflow TO BE — coordinator + phase skills, incremental on one branch, one squash with 7b559003 #479 is gone at this head; repo-side half recorded as ADL (b767d451). Source: dispositions comment, confirmed in the closing synthesis.
  • t9d-29 — FIXED, d9ae2747$regressionGuards given a proper Arguments row.
  • t9d-30 — FIXED, c594323c--repo/--repository aliased; finalize reachable with no PR.
  • t9d-31 — FIXED, d9ae2747 — dataset contract suites carry the header note (11/11 verified).
  • t9d-32 — FIXED, d9ae2747 — ADR-024 superseded sections recorded (§2/§6).
  • t9d-33 — FIXED, d9ae2747 — ADR-024 records both never-shipped S7 surfaces as superseded.

Questions — 10/10 dispositioned (informational, none blocking)

  • q-1 through q-6, q-8, q-9 — accepted-as-is / not-this-PR's-scope, each with a recorded one-line rationale — questions comment.
  • q-7 — residual security risk (author-blind marker match) — recorded as an ADL, not fixed in code; bounded blast radius, exit path documented — q-7/q-10 closure.
  • q-10 — docs hygiene (ADR-024 ## Adoption Impact, stale catalog date) — CLOSED, 6a3598c8q-7/q-10 closure.
Positive feedback
  • Custody discipline held under load: red-snapshot.mjs verifyChain is now unconditionally passed --run-dir (t9d-9), closing the one path where a sealed handoff's contract expectation could be bypassed.
  • The two items the closing synthesis itself first mis-tracked (t9d-6, t9d-8) were caught and corrected by the same pass rather than left standing — the synthesis names its own correction inline rather than silently editing history.
  • Where a fix wasn't code, the disposition is recorded as an ADL with a named exit path (t9d-28 card transport, q-7 marker-matching risk) rather than waved through silently — consistent with the template's "no TECH-DEBT verdict without an exit path" rule.
  • Byte-identity across the replicated engine (5 installed + 5 dataset copies of cycle-state.mjs) reverified at 4896095e… after the last commit, not assumed from the commit subject.
Functionality & requirements (AC coverage)
  • All 33 findings from review 5190603055 resolved (fixed, dispositioned, or out-of-scope) — closing synthesis.
  • AC-10 / AC-14 / AC-22 (live cohort) / AC-28 remain unproven on this head — T-8's paired 2.0.0/4.0.0 measurement recorded as not run (ADL, b767d451), full-cycle canary evidence stands in its place. Flagged AC-level, outside the 33 findings; not blocking this verdict per the review's own scoping, but not to be represented as proven.
  • Business logic + edge cases correct — per the 14 giro-2 commits + t9d-6/t9d-8 residual closures, all independently re-verified by file inspection at 585d57ce.
  • Integrates with existing systems — no new dependency, no schema/infra change (confirmed: no package.json/lockfile diff).
  • Error handling appropriate — fail-closed refusals verified for maintainer resolution (t9d-17), lock staleness (t9d-7), path containment (t9d-20).
Testing & quality gates
  • Adequate coverage — pnpm workflows:test 701/701 pass (0 fail), package suites 8351 pass (knowledge-hub 4900, pair-cli 1862, content-ops 754, dev-tools 573, website 184, brand 78) — closing synthesis.
  • Edge + error scenarios tested — t9d-6 fixture and t9d-16/18/19/20/21 characterization tests reverified; guard-strength inversions reproduced (t9d-6: 699→697 pass on inversion, restored).
  • Quality gates: PASSpnpm quality-gate exits 0 (22/22 turbo tasks): ts:check, build, lint, hygiene:check, smoke-modes:check, docs:staleness (50 skills, 11 commands), skills:conformance (50 skills), dup:check, format:check, gate:composition all pass — closing synthesis.
  • CI on head 585d57ce: secret-scan, build, format, smoke, preview5/5 success (verified live via gh api repos/foomakers/pair/commits/585d57ce.../check-runs, matching the head the closing synthesis names).
  • Custody: byte-identity of the replicated engine holds — all 5 installed cycle-state.mjs copies and all 5 dataset mirrors hash identically (4896095e…) after 585d57ce; pair-contracts/cycle-state.test.mjs matches its dataset mirror byte for byte.
Adoption compliance
  • Degradation level: 1 (/pair-capability-verify-adoption + /pair-capability-assess-stack, run over 114 changed paths) — per review 5190603055. At review time: Tech stack CONFORMANT, Coding standards CONFORMANT, Infrastructure CONFORMANT, Architecture NON-CONFORMANT (t9d-28, t9d-32), Security NON-CONFORMANT (t9d-17). All three non-conformances are now closed: t9d-17 FIXED (1f7736f6), t9d-32 FIXED (d9ae2747), t9d-28 DISPOSITIONED with an ADL — no open architecture/security non-conformance remains.
  • Dependencies match tech-stack.md: no package.json/lockfile change (review 5190603055, confirmed by diff).
  • ADRs present: ADR-024 + amendments a–j, five ADLs added in this PR, plus the further ADLs recorded during closure (t9d-8's second ADL, t9d-28, q-7) — no missing-ADR HALT condition remains open (t9d-28 was exactly that HALT; discharged by recording the decision).
  • Mirrors: 15/15 script/coordinator pairs byte-identical at review time; reconfirmed for cycle-state.mjs specifically post-closure (above).
Tech debt
  • Hand-copied CLI helpers (parseCli ×11, isMain ×12, cleanGitEnv ×7) with no identity guard — surfaced by review 5190603055, carried as tech debt (fix path: the coupling proposal), not a blocking finding. The concrete defects this gap produced (t9d-16/18/19/20/21) are fixed; the structural gap itself is unchanged and remains debt.
  • cycle-state.mjs at 2038 lines (multiple responsibilities) — not counted as a violation per the review (copies pinned, story mandates one STATE authority); noted as debt.
  • t9d-28 (card transport is GitHub + Claude Code via gh) recorded as an ADL tech-debt item, to be promoted to a tech-debt issue by the maintainer — dispositions comment.
Documentation
  • Phase SKILL.md / script disagreements closed (t9d-13, t9d-14, t9d-15).
  • batch-engine.mdx recipe-location ambiguity addressed on the workflow path (t9d-1).
  • Story card completeness (t9d-25) resolved — card now carries S1–S13 and the T-19–T-31 checklist; one stale header line remains on the card itself (D5 header lags S12/S13/AC-32/DT-41/T-30/T-31), noted as external/out-of-scope for this PR.
  • ADR-024 gains ## Adoption Impact; skills-catalog.mdx date gated against the dataset source (q-10) — q-7/q-10 closure.
Performance & deployment
  • No hot-path or product runtime touched; gate grows by ~1 min of added workflow tests (review 5190603055).
  • Rollback: one squash on main; previous 3.0.x engine preserved as branch history and tagged canary entries — reversible (review 5190603055, unchanged).

Note on process, not verdict

Review 5190603055's own tier requirements (🔴, quality-model §4) call for explicit non-author human approval, but flag it advisory only because way-of-working.md:143 states Review enforcement: disabled — "nothing here blocks a merge mechanically." Consistent with that, the PR's pr-state label already reads pr-state:ready-to-merge (checked live on the PR at draft time of this review), reflecting that the closure work above has already been recognized. The PR itself is still flagged draft on GitHub — a mechanical toggle for the author/maintainer, not a review finding, and not something this closing pass has a mandate to change.

For review type emphasis: this is the Refactoring case — behavior unchanged, coverage maintained (701/701 workflow tests + 8351 package tests, up from 652 at first review). Review conduct standards: see team standards.


Draft final review — not posted. Evidence cited: review 5190603055, dispositions, questions, q-7/q-10 closure, closing synthesis (incl. its two residual-closure edits for t9d-6 and t9d-8). CI check-runs and combined status verified live against head 585d57ce.

@claude
claude Bot marked this pull request as ready for review September 13, 2026 15:31
@rucka rucka self-assigned this Sep 13, 2026
@rucka
rucka merged commit 7dfa168 into main Sep 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-state:ready-to-merge PR state: gates green + review approved risk:red Classification: high risk tier

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants