Harness Intelligence Wiki
SpecsCLIIssue 204 Portable Commit Gates

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 to 2d8839978075419cb9a8a70f296f078626d31a7d, and rebased through the moving PR #208 stack to current parent head d50fe8b6a63cea52db6a2ff56e2c9b42868ef79d.
  • Branch/Base Intent: preserve the 203 → 204 stack. The child branch is team/stefan/issue-204-portable-commit-gates; its PR base must be fix/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

DecisionResolution
Checkout authorityActive Git worktree top level from git rev-parse --show-toplevel.
Legacy contractsAccept an obsolete root field syntactically but never use it as execution authority.
Owner locationResolve generated repository-relative path beneath the active worktree root.
Failure detailInclude owner, command kind, resolved cwd, launch code/message, stdout, and stderr when available.
Preserved behaviorKeep staged ACMR filtering, deletion exclusion, owner-relative arguments, command templates, parallel execution, and aggregate exit status.
Contract producerAdd coverage only; do not add another root field or producer abstraction.
Release scopeNo publication or version bump. Do not edit either changelog; classify the child against its issue #203 parent.
Review modeCLI-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 → closeout

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

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-terra worker recovered one aggregate executable RED suite at pre-fix commit 7357f43b; 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: tdd applicable_behavior: Run one executable public-result RED before each behavior change, apply the minimum GREEN, and retain exact RED/GREEN evidence.
    • skill: codebase-design applicable_behavior: Keep root discovery and failure capture behind the existing runner executable seam; add no service or caller-visible configuration.
    • skill: quality-types applicable_behavior: Derive error fields at the process boundary without unsafe duplicated shapes; keep the declaration aligned with generated contract truth.
    • skill: simplify applicable_behavior: After GREEN, remove obsolete root authority and keep names and derived state local without changing behavior.
  • 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 plus ENOENT/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.ts ran 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 and ENOENT/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.ts also 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 --detach linked 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 path values with no own root property. Do not alter the already-correct producer.
  • validation: AC-003 and producer portion of AC-005.
  • status: Complete
  • log: Non-Astra gpt-5.6-terra worker 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: tdd applicable_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-design applicable_behavior: Assert the public materialized artifact, not private planner implementation details.
    • skill: quality-types applicable_behavior: Parse boundary JSON once and assert observable contract keys without unsafe casting.
    • skill: simplify applicable_behavior: Reuse the existing output-test fixture and avoid duplicate setup.
  • 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.ts passed; parent combined W1 command also passed.
  • codebase_design_notes: The emitted .devpunks/commit-gate-contracts.json file 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-terra worker 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-agents applicable_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: simplify applicable_behavior: Keep the update local and concise, with the new Commit Gate paragraph byte-aligned between root and routed runbooks.
  • 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, and git diff --check passed.
  • 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:

  1. bun run --cwd apps/cli test -- src/data/scripts/commit-gate-runner.test.ts src/scaffold/output.test.ts
  2. bun run --cwd apps/cli check-types
  3. bun run --cwd apps/cli lint
  4. bun run --cwd apps/cli format
  5. bun run --cwd apps/cli build
  6. bun run --cwd apps/wiki check:content
  7. bun run --cwd apps/wiki postinstall to parse/generate the edited MDX documentation.
  8. git diff --check
  9. bun run release:classify -- --base fix/issue-203-scaffold-convergence --head HEAD
  10. Explicit review-phase against the frozen child diff, followed by bounded repair if findings exist.
  11. docs-ingest-phase to 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.ts with current rootless producer truth and includes typecheck/build proof.
  • Stack drift: verify merge-base and PR base against fix/issue-203-scaffold-convergence at 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.

On this page