Issue 204 portable commit gates implementation plan
Issue 204 portable commit gates implementation plan
Status: Complete
Authority and planning state
Sources: SPEC.md, requirements status, research report, and GitHub issue #204.
architecture_applicability: local: the existing generated runner remains the sole behavior owner and executable seam. No public schema, cross-domain dependency, service, or composition ownership changes.- Dependency Readiness: Ready. The child was created at the original issue #203 head
7357f43b686f4866e45925f875e458e8c29ef6f3, fast-forwarded to2d8839978075419cb9a8a70f296f078626d31a7d, and rebased through the moving PR #208 stack to current parent headd50fe8b6a63cea52db6a2ff56e2c9b42868ef79d. - Branch/Base Intent: preserve the 203 → 204 stack. The child branch is
team/stefan/issue-204-portable-commit-gates; its PR base must befix/issue-203-scaffold-convergence. - Requirements ambiguity: none. The user confirmed the persisted shared understanding and instructed delivery to continue from plan onward.
- Spec retention: the normal dedicated commit was attempted twice. After dependencies were installed, the hook reached wiki checks and failed on 497 pre-existing wiki source/tool errors already documented by issue #203. No hook was bypassed. The accepted local agent-ready spec remains planning authority under the user's explicit start-at-plan instruction.
- Backlog sync: skipped. The supplied authority is GitHub issue #204, no retained Linear projection exists, and the user requested delivery from plan onward. All tasks use planning-only identities.
- External documentation: not required. The repair uses stable Node child-process and Git commands already present in the repository; primary evidence is local executable behavior.
Initial situation and findings
Current scaffold output serializes quality commands, owner, and repository-relative path; it emits no root. The generated runner still resolves owner cwd from contract.root ?? process.cwd(), so an obsolete absolute v4.0.4 root overrides the active checkout. When that directory does not exist, Node raises a launch-time ENOENT; the runner keeps neither its string code nor message and emits empty generic exit-1 failures.
Existing tests prove no-staged behavior, aggregate command failure, deleted-file exclusion, root-relative staged paths, nested owner cwd, generated execution, and read-only formatting. They do not prove stale-root recovery, linked-worktree execution, actionable launch diagnostics, or raw absence of a generated root field.
The solution keeps the runner interface deep and small: discover the active Git worktree root once, resolve each owner path beneath it, ignore legacy root authority, and retain process-launch metadata in the existing failure result. The scaffold producer needs only regression coverage because its current behavior already satisfies AC-003.
Resolved decision ledger
| Decision | Resolution |
|---|---|
| Checkout authority | Active Git worktree top level from git rev-parse --show-toplevel. |
| Legacy contracts | Accept an obsolete root field syntactically but never use it as execution authority. |
| Owner location | Resolve generated repository-relative path beneath the active worktree root. |
| Failure detail | Include owner, command kind, resolved cwd, launch code/message, stdout, and stderr when available. |
| Preserved behavior | Keep staged ACMR filtering, deletion exclusion, owner-relative arguments, command templates, parallel execution, and aggregate exit status. |
| Contract producer | Add coverage only; do not add another root field or producer abstraction. |
| Release scope | No publication or version bump. Do not edit either changelog; classify the child against its issue #203 parent. |
| Review mode | CLI-only executable and diff review; no browser surface. |
Dependency graph and waves
W1
├── T1 portable runner + executable TDD
└── T2 rootless generated-contract coverage
│
▼
W2
└── T3 synchronized operator documentation
│
▼
delivery validation → review-phase → docs ingest → closeoutWave W1 contains every unblocked task with disjoint write scopes. T1 and T2 can run concurrently. T3 depends on both proven behavior and producer coverage so its wording records verified behavior. Review and closeout remain delivery-phase gates rather than duplicate implementation tasks.
Common task identity
Every task uses:
task_identity_mode: planning-onlybacklog_item_id: not_applicablebacklog_item_url: not_applicablerelation_mode: unprojectedbacklog_sync_skip_reason: GitHub issue #204 has no retained Linear task projection; user requested delivery from plan onward.
Workers must not revert other changes and must edit only their assigned owned_paths. The parent records worker results and evidence in IMPLEMENTATION-NOTES.md; workers do not share-write planning artifacts.
Parent-owned lifecycle evidence
The delivery parent exclusively owns IMPLEMENTATION-NOTES.md and updates it after each worker result, validation gate, review route, and docs-ingest outcome. It creates the ledger before Wave W1 and never assigns it to a worker, so disjoint worker write scopes remain enforceable.
Tasks
T1: Portable runner and launch-diagnostic TDD
- depends_on: []
- location:
apps/cli/src/data/scripts - owned_paths: [
apps/cli/src/data/scripts/commit-gate-runner.mjs,apps/cli/src/data/scripts/commit-gate-runner.d.ts,apps/cli/src/data/scripts/commit-gate-runner.test.ts] - wave_boundary: W1
- description: Test-drive stale-root recovery, active-worktree owner resolution, linked-worktree execution, and actionable launch diagnostics through the runner executable. Keep the current process and staged-file behavior intact. Align the declaration with the rootless producer contract.
- validation: AC-001, AC-002, AC-004, and preserved runner portions of AC-005.
- status: Complete
- log: Non-Astra
gpt-5.6-terraworker recovered one aggregate executable RED suite at pre-fix commit7357f43b; its three failing tests proved stale-root execution failure, linked-worktree misrouting, and missing cwd/launch cause. One production patch then made the full seven-test suite GREEN. This recovered sequence proves all behaviors but is recorded as an aggregate-suite TDD deviation rather than three vertical slices. - files edited/created:
apps/cli/src/data/scripts/commit-gate-runner.mjs,apps/cli/src/data/scripts/commit-gate-runner.d.ts,apps/cli/src/data/scripts/commit-gate-runner.test.ts,apps/cli/src/data/bundled-baseline-identity.generated.ts - task_identity_mode: planning-only
- backlog_item_id: not_applicable
- backlog_item_url: not_applicable
- relation_mode: unprojected
- backlog_sync_skip_reason: GitHub issue #204 has no retained Linear task projection; user requested delivery from plan onward.
- assigned_skills: [
tdd,codebase-design,quality-types,simplify] - implementation_skill_guidance:
- skill:
tddapplicable_behavior: Run one executable public-result RED before each behavior change, apply the minimum GREEN, and retain exact RED/GREEN evidence. - skill:
codebase-designapplicable_behavior: Keep root discovery and failure capture behind the existing runner executable seam; add no service or caller-visible configuration. - skill:
quality-typesapplicable_behavior: Derive error fields at the process boundary without unsafe duplicated shapes; keep the declaration aligned with generated contract truth. - skill:
simplifyapplicable_behavior: After GREEN, remove obsolete root authority and keep names and derived state local without changing behavior.
- skill:
- tdd_status: recovered
- tdd_target: A legacy contract with a stale absolute root executes from the active checkout; a missing owner reports cwd and the underlying launch error; a linked worktree uses its own top level and index.
- red_command:
bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts - expected_red_failure: Current runner resolves the stale
contract.root, linked-worktree commands never start, and missing-owner output omits cwd plusENOENT/message. - green_command:
bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts - reason_not_testable:
- red_evidence: At isolated pre-fix commit
7357f43b,bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.tsran the three new public-boundary cases together: stale Legacy root returned exit 1 instead of 0; the linked-worktree case produced no marker in the linked checkout; the missing Owner path output omitted resolved cwd andENOENT/message. - green_evidence: After the single runner patch, the same focused command passed all 7 runner tests. Parent combined command
bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts src/scaffold/output.test.tsalso passed. Per-behavior minimal-change chronology was not retained, so no vertical-slice claim is made. - codebase_design_notes: The runner executable is the public seam. Git and child-process details remain internal; tests invoke the same file and real Git repositories that consumers use.
- review_mode: cli
- runtime_validation: required
- runtime_target: Canonical generated runner in a real temporary repository and
git worktree add --detachlinked worktree. - runtime_evidence: Marker output proves owner cwd and owner-relative staged arguments in the active linked worktree; failed owner output proves owner, kind, cwd, and launch cause.
- runtime_cleanup: Use unique temporary roots; remove only the linked worktree and repositories created by the test after processes exit.
Review repair evidence: .trim() corrupted a real checkout path ending in whitespace. bun run --cwd apps/cli test src/data/scripts/commit-gate-runner.test.ts -t 'preserves trailing whitespace in the active worktree path' was RED with runner code 1 instead of 0, then GREEN 1/1 after replacing broad trimming with terminal-newline removal. Review pass 2 then found that removing terminal CRLF could still truncate a valid checkout path ending in \r; a real repo\r case was RED within the 9-test runner suite, then GREEN 9/9 after stripping only the terminal LF. Combined runner and scaffold output validation passed 28/28.
T2: Rootless generated-contract coverage
- depends_on: []
- location:
apps/cli/src/scaffold - owned_paths: [
apps/cli/src/scaffold/output.test.ts] - wave_boundary: W1
- description: Decode materialized commit-gate contracts and prove fresh scaffold output contains repository-relative
pathvalues with no ownrootproperty. Do not alter the already-correct producer. - validation: AC-003 and producer portion of AC-005.
- status: Complete
- log: Non-Astra
gpt-5.6-terraworker added coverage at the materialized JSON artifact seam without manufacturing RED. Parent review and combined W1 validation passed. - files edited/created:
apps/cli/src/scaffold/output.test.ts - task_identity_mode: planning-only
- backlog_item_id: not_applicable
- backlog_item_url: not_applicable
- relation_mode: unprojected
- backlog_sync_skip_reason: GitHub issue #204 has no retained Linear task projection; user requested delivery from plan onward.
- assigned_skills: [
tdd,codebase-design,quality-types,simplify] - implementation_skill_guidance:
- skill:
tddapplicable_behavior: Do not manufacture RED for behavior already present; record this as coverage-only and run the focused test after the assertion is added. - skill:
codebase-designapplicable_behavior: Assert the public materialized artifact, not private planner implementation details. - skill:
quality-typesapplicable_behavior: Parse boundary JSON once and assert observable contract keys without unsafe casting. - skill:
simplifyapplicable_behavior: Reuse the existing output-test fixture and avoid duplicate setup.
- skill:
- tdd_status: not_applicable
- tdd_target: Coverage for already-correct generated contract bytes.
- red_command: not_applicable
- expected_red_failure: not_applicable
- green_command:
bun run --cwd apps/cli test -- src/scaffold/output.test.ts - reason_not_testable: Production behavior already satisfies AC-003; this task adds missing regression evidence only.
- red_evidence:
- green_evidence:
bun run --cwd apps/cli test -- src/scaffold/output.test.tspassed; parent combined W1 command also passed. - codebase_design_notes: The emitted
.devpunks/commit-gate-contracts.jsonfile is the stable test seam. - review_mode: cli
- runtime_validation: not_required
- runtime_target: not_applicable
- runtime_evidence: not_applicable
- runtime_cleanup: not_applicable
T3: Synchronize operator documentation
- depends_on: [T1, T2]
- location: root docs and routed project runbook
- owned_paths: [
docs/README.md,docs/runbooks/hi-cli-scaffolding.md,apps/wiki/content/docs/project/runbooks/hi-cli-scaffolding.md] - wave_boundary: W2
- description: Document active-worktree owner resolution, legacy-root non-authority, and actionable missing-cwd diagnostics in the existing Commit Gate lifecycle surfaces. Keep root and routed runbooks aligned.
- validation: Documentation reflects proven AC-001 through AC-004 behavior and introduces no duplicate flow page.
- status: Complete
- log: Non-Astra
gpt-5.6-terraworker added one concise operational invariant at the existing Commit Gate lifecycle seam and kept the new Commit Gate paragraph byte-aligned between the root and routed runbooks. Content sync, Fumadocs generation, and diff checks passed. - files edited/created:
docs/README.md,docs/runbooks/hi-cli-scaffolding.md,apps/wiki/content/docs/project/runbooks/hi-cli-scaffolding.md - task_identity_mode: planning-only
- backlog_item_id: not_applicable
- backlog_item_url: not_applicable
- relation_mode: unprojected
- backlog_sync_skip_reason: GitHub issue #204 has no retained Linear task projection; user requested delivery from plan onward.
- assigned_skills: [
writing-for-agents,simplify] - implementation_skill_guidance:
- skill:
writing-for-agentsapplicable_behavior: Add one precise operational rule at the existing Commit Gate pointer; state the positive runtime invariant and diagnostic result without duplicating source-visible details. - skill:
simplifyapplicable_behavior: Keep the update local and concise, with the new Commit Gate paragraph byte-aligned between root and routed runbooks.
- skill:
- tdd_status: not_applicable
- tdd_target: Documentation-only synchronization after executable behavior is GREEN.
- red_command: not_applicable
- expected_red_failure: not_applicable
- green_command:
bun run --cwd apps/wiki check:content && bun run --cwd apps/wiki postinstall && git diff --check - reason_not_testable: Documentation-only task; executable acceptance belongs to T1 and T2.
- red_evidence:
- green_evidence:
bun run --cwd apps/wiki check:content,bun run --cwd apps/wiki postinstall, andgit diff --checkpassed. - codebase_design_notes: Existing Commit Gate lifecycle sections remain the sole operator-documentation seam.
- review_mode: cli
- runtime_validation: not_required
- runtime_target: not_applicable
- runtime_evidence: not_applicable
- runtime_cleanup: not_applicable
Validation and review gates
After all writing workers finish, the parent freezes the diff and runs:
bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts src/scaffold/output.test.tsbun run --cwd apps/cli check-typesbun run --cwd apps/cli lintbun run --cwd apps/cli formatbun run --cwd apps/cli buildbun run --cwd apps/wiki check:contentbun run --cwd apps/wiki postinstallto parse/generate the edited MDX documentation.git diff --checkbun run release:classify -- --base fix/issue-203-scaffold-convergence --head HEAD- Explicit
review-phaseagainst the frozen child diff, followed by bounded repair if findings exist. docs-ingest-phaseto retain implementation evidence and classify any remaining docs delta before closeout.
The normal wiki lint/build baseline has 497 unrelated pre-existing errors on the issue #203 parent. Delivery records that baseline instead of weakening it or claiming a repository-wide clean result. Focused CLI and content-route gates must pass.
Risks and mitigations
- Wrong Git root: use active worktree top level, not common Git directory; prove with a real linked worktree.
- Hidden launch failure: retain string launch code/message separately from numeric exit status and command output.
- Regression in staged scope: preserve current ACMR/deletion and owner-prefix tests; run focused suites together.
- False TDD evidence: T1 captures real RED before production edits; T2 is explicitly coverage-only.
- Generated declaration drift: T1 aligns
commit-gate-runner.d.tswith current rootless producer truth and includes typecheck/build proof. - Stack drift: verify merge-base and PR base against
fix/issue-203-scaffold-convergenceat closeout. - Release overreach: leave both changelogs and package version unchanged; classify child diff against the parent branch.
Unresolved questions
None. The wiki-wide pre-existing lint baseline is a validation limitation, not a product decision or permission to weaken gates.