You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out of #78, which adds declared per-gate setup steps. #78 runs those steps inside the existing
clean/HEAD observation window and does not change what invalidated means. That leaves a real gap worth
settling on its own, because it is a question about the meaning of invalidated, not about declaring setup.
git status --porcelain=v1 -z --untracked-files=all --ignore-submodules=none
No --ignored. So gitignored paths are invisible, but modified tracked files and untracked non-ignored files
both make the tree dirty.
Both execution paths then force the gate result to invalidated when the tree is dirty at either end
(scripts/run-ci-gate-sensor.ts:91, src/services/session-service.ts:670).
The gap
Provisioning is exactly the kind of step that writes to the tree. Under the current rule:
Setup writes
Reported dirty
Gate result
Modified tracked file, e.g. uv sync refreshing uv.lock
yes
invalidated
Untracked non-ignored path, e.g. .venv/ absent from .gitignore
yes
invalidated
Gitignored path, e.g. .venv/ when ignored
no
passes
So a consumer whose declared setup is legitimate but whose repository does not gitignore its provisioning
output gets invalidated, whose message points at repository state rather than at the setup declaration that
actually caused it. invalidated currently means "the evidence does not describe HEAD", and a lockfile
refresh during provisioning is a different situation from a gate that mutated the repository under test.
#78 records per-step clean observations, so the receipt does contain enough to tell these apart. Nothing
consumes that distinction yet.
Relaxing or subdividing invalidated changes the meaning of an existing recorded status that already appears
in stored receipts and in the runner skill's status allowlist. #78 is already a two-contract change; folding a
third semantic change into it would make a partial landing more likely.
Options
Leave invalidated as is and document the constraint: governed setup must use frozen or locked install
modes and must write only gitignored paths. Free, but every adopter has to discover the rule.
Narrow the post-setup cleanliness check to tracked files only, letting setup create untracked output
without requiring the consumer to gitignore it. Weakens the current invariant.
Snapshot and restore, or otherwise scope, the tree between setup and gate execution. Strongest guarantee,
most machinery.
Option 2 looks most consistent with the direction #78 takes, since it adds meaning to evidence that will
already be recorded rather than relaxing an invariant.
Acceptance criteria
A setup step that dirties the working tree produces an outcome whose message names the setup step and the
paths it changed, distinct from a gate that mutated the repository.
The invariant that a passing receipt describes exactly the observed HEAD is preserved or its intentional
change is documented.
Local and CI execution paths classify the situation identically.
Whatever rule applies to provisioning output is documented in docs/consumer-onboarding.md with a worked
example.
Existing stored receipts carrying invalidated keep their current meaning.
Summary
Split out of #78, which adds declared per-gate
setupsteps. #78 runs those steps inside the existingclean/HEAD observation window and does not change what
invalidatedmeans. That leaves a real gap worthsettling on its own, because it is a question about the meaning of
invalidated, not about declaring setup.Current behavior
observeProofRepository(src/adapters/git/client.ts:82) defines cleanliness as:No
--ignored. So gitignored paths are invisible, but modified tracked files and untracked non-ignored filesboth make the tree dirty.
Both execution paths then force the gate result to
invalidatedwhen the tree is dirty at either end(
scripts/run-ci-gate-sensor.ts:91,src/services/session-service.ts:670).The gap
Provisioning is exactly the kind of step that writes to the tree. Under the current rule:
uv syncrefreshinguv.lockinvalidated.venv/absent from.gitignoreinvalidated.venv/when ignoredSo a consumer whose declared setup is legitimate but whose repository does not gitignore its provisioning
output gets
invalidated, whose message points at repository state rather than at the setup declaration thatactually caused it.
invalidatedcurrently means "the evidence does not describe HEAD", and a lockfilerefresh during provisioning is a different situation from a gate that mutated the repository under test.
#78 records per-step clean observations, so the receipt does contain enough to tell these apart. Nothing
consumes that distinction yet.
Why this is deliberately not in #78
Relaxing or subdividing
invalidatedchanges the meaning of an existing recorded status that already appearsin stored receipts and in the runner skill's status allowlist. #78 is already a two-contract change; folding a
third semantic change into it would make a partial landing more likely.
Options
invalidatedas is and document the constraint: governed setup must use frozen or locked installmodes and must write only gitignored paths. Free, but every adopter has to discover the rule.
gate-caused one, so the operator handoff names the offending setup step and what it wrote.
without requiring the consumer to gitignore it. Weakens the current invariant.
most machinery.
Option 2 looks most consistent with the direction #78 takes, since it adds meaning to evidence that will
already be recorded rather than relaxing an invariant.
Acceptance criteria
paths it changed, distinct from a gate that mutated the repository.
change is documented.
docs/consumer-onboarding.mdwith a workedexample.
invalidatedkeep their current meaning.