Harness Intelligence Wiki
SpecsCLIIssue 204 Portable Commit Gates

Issue 204: portable commit gates

Spec: Portable commit gates

Context

Harness CLI 4.0.4 generated .devpunks/commit-gate-contracts.json with a machine-specific absolute root. When the repository was cloned elsewhere or used through a linked worktree, the generated runner attempted to launch owner-local quality commands in the obsolete directory. Node returned a launch-time ENOENT, but the runner discarded the useful error message and reported only generic exit-1 failures.

Current scaffold output already emits repository-relative owner paths without an absolute root. Existing committed legacy contracts remain unsafe because the runner still treats their obsolete root field as authoritative.

Non-Goals

  • Adding a new absolute-root field or another machine-specific contract locator.
  • Redesigning Lefthook configuration, quality-command discovery, or staged-file selection.
  • Weakening commit-gate failures, scaffold/check integrity, or command exit behavior.
  • Defining general policy for arbitrary hand-authored absolute or traversing owner paths.
  • Requiring an npm or baseline publication as part of this issue.

Requirements and Outcomes

OUT-001: Commit-gate owner execution follows the active checkout

Commit-gate owner directories resolve from the active Git worktree top level. Generated repository-relative owner paths work after cloning, moving a checkout, and within a linked worktree. A legacy machine-specific root may be read for compatibility but cannot select the execution directory.

OUT-002: Process-launch failures are actionable

When a quality command cannot launch, the aggregate failure identifies the owner, command kind, resolved working directory, and underlying launch error code or message while retaining available command stdout and stderr.

OUT-003: Existing commit-gate behavior remains stable

The repair preserves staged-file scoping, deletion exclusion, owner-relative file arguments, lint and format-check execution, aggregate failure reporting, and nonzero final status when any command fails.

Acceptance Criteria

  • AC-001: A contract with a deliberately stale absolute legacy root executes owner commands beneath the current Git worktree root. Covers: OUT-001.
  • AC-002: The same owner-relative contract behavior succeeds in both an ordinary repository and a linked Git worktree without regenerating machine-specific paths. Covers: OUT-001.
  • AC-003: Fresh scaffold output contains repository-relative owner path values and no machine-specific root. Covers: OUT-001.
  • AC-004: A missing resolved owner directory reports owner, command kind, resolved cwd, and the underlying launch error code or message. Covers: OUT-002.
  • AC-005: Existing root and nested owner staged-file tests continue to prove scoped arguments, ignored deletions, aggregate lint/format failures, and read-only checks. Covers: OUT-003.

Constraints

  • Use git rev-parse --show-toplevel semantics for the active worktree; do not use the shared Git common directory.
  • Preserve the generated contract's current provider-neutral shape: quality commands, owner identity, and repository-relative path.
  • Legacy root compatibility is one-way: it may be tolerated in input but is non-authoritative.
  • Preserve existing command templates and staged-file substitution behavior.

Dependency Readiness

Ready:

  • Parent branch: open PR #208 head fix/issue-203-scaffold-convergence at 2d8839978075419cb9a8a70f296f078626d31a7d.
  • Child branch: team/stefan/issue-204-portable-commit-gates was created at the original issue #203 head and fast-forwarded onto the current PR #208 head before review; ancestry was verified with git merge-base --is-ancestor.

Branch/Base Intent

The issue #204 branch must remain stacked directly on fix/issue-203-scaffold-convergence. Its pull request targets the issue #203 branch rather than main so the 203 → 204 stack remains explicit.

Accepted Technical Decisions

  • Resolve the active worktree root at runner runtime and resolve each contract path beneath it.
  • Ignore legacy contract.root as execution authority instead of attempting to rewrite or trust it.
  • Preserve launch-error metadata separately from process stdout and stderr so ENOENT and equivalent failures remain visible.
  • Keep the current runner and scaffold producer seams; do not introduce a new service or contract schema field.

Accepted Testing Decisions

  • Test through the generated runner's executable boundary with real temporary Git repositories and staged files.
  • Add a stale-root relocation regression and linked-worktree regression.
  • Add a missing-owner launch regression that proves cwd and underlying error visibility.
  • Retain existing generated-gate/scaffold assertions proving no absolute root is emitted and command behavior remains read-only.

Verification Seams

  • node .agents/scripts/commit-gate-runner.mjs --contracts .devpunks/commit-gate-contracts.json in isolated repositories and linked worktrees.
  • The canonical source runner test suite under apps/cli/src/data/scripts.
  • Scaffold output tests that decode generated contracts and execute the generated runner.
  • Package-scoped CLI typecheck, lint/format checks, and build.

Parked Decisions

  • Semantic hi check rejection of legacy root fields is parked for a future issue; resume if desired-byte update drift proves insufficient migration guidance.
  • General confinement of arbitrary hand-authored owner paths is parked for a future security/contract-hardening issue; resume if such paths become a supported public contract.

Decision Log

DecisionEvidenceRationale
Active Git worktree root is authoritativeIssue #204 expected behavior and runner traceIt selects the checkout and index actually running the commit gate.
Legacy absolute root is ignoredCurrent generator is rootless while old committed contracts remainNew runner bytes repair existing contracts without trusting stale machine paths.
Launch metadata is retainedNode missing-cwd probe returns ENOENT with empty stdout/stderrGeneric exit 1 is not actionable without the discarded error and cwd.
Existing staged-file semantics remain stableCurrent runner and generated-gate regression suitesPortability does not require changing quality-command scope or mutation behavior.

On this page