Skip to content

feat(conformance): migrate the default-workspace-mount unit, and find a compose defect#366

Open
pofallon wants to merge 2 commits into
fix/t115-metadata-raw-configfrom
feat/step5b-migrate-state-diff
Open

feat(conformance): migrate the default-workspace-mount unit, and find a compose defect#366
pofallon wants to merge 2 commits into
fix/t115-metadata-raw-configfrom
feat/step5b-migrate-state-diff

Conversation

@pofallon

Copy link
Copy Markdown
Contributor

Stacked on #365 (fix/t115-metadata-raw-config). Retarget to main before #365 merges with --delete-branch.

What

Migrates parity_state_diff::default-workspace-mount-target-parity into declarative cases, and records the spec violation that measurement surfaced while attempting the two compose units.

The unit needed two cases, not one

It asserted two distinct claims through one reported outcome — research D2's inverse defect:

Case Oracle type Claim
case-state-default-mount live-differential the two CLIs agree on container state
case-state-default-mount-target spec-expectation absolute: NEITHER CLI mounts the workspace at workspaceFolder, BOTH mount it at the spec default /workspaces/<basename> (#273)

A differential structurally cannot carry the second: it would pass if deacon and the reference regressed together. This is the T072 twin-case pattern.

No new assertion predicate was needed. workspaceBindTargets is already a DERIVED observer field, so the quantified ∄ /workspace ∧ ∃ /workspaces/* claim becomes plain equality against a one-element list — the design commitment ("when an assertion needs a search, add a derived field to the observer") paying off rather than being restated.

The legacy unit wrote no report fragment at all (its assert_parity call was absent), so this is a coverage gain, not a transfer.

The frozen-denominator guard fired, and was right to

bhv-state-default-workspace-mount-target pushed the behavior count past the allowance. It is newly named, not newly observed: the baseline unit genuinely asserted the claim while the registry described only the agreement half (bhv-state-diff-parity). Refusing it would migrate the unit at reduced fidelity — losing a claim to preserve a number, which is the precise under-count 023 exists to fix, reintroduced by the guard meant to catch it.

POST_BRANCH_BEHAVIORS now distinguishes its two categories explicitly (newly observed / newly named) instead of one being stretched to cover both, and the new entry argues its own case.

The two compose units are held back — deacon has a defect (T117)

The spec is explicit:

overrideCommand … Defaults to true for when using an image Dockerfile and false when referencing a Docker Compose file. … Set to false if the default command must run for the container to function properly.

crates/core/src/compose.rs:1323 reads self.override_command.unwrap_or(true) — on a code path reached only for compose — under a comment asserting the opposite of the spec. test_generate_injection_override_command_default_on pins the wrong default and cites "Spec default" while doing it.

Measured, not inferred (pinned oracle 0.87.0). A compose service with command: ["sh","-c","touch <marker>; sleep infinity"]:

marker created?
reference YES
deacon NO

docker inspect shows the mechanism: the reference puts its keep-alive in Entrypoint ending in exec "$@" and leaves Cmd as the compose command, so the declared command runs and the keep-alive loop is reached only when there is none. deacon puts its keep-alive in Cmd and leaves Entrypoint empty, discarding the command outright.

Consequence: any compose service whose command matters — a server, a database bootstrap, a queue worker — silently does not start under deacon. It is invisible for the common command: ["sleep","infinity"] idiom, which is why every existing compose fixture passed.

Migrating the two units now would require a scoped tolerance, i.e. recording a spec violation as intentional — the one move this model exists to prevent. They stay residual under res-state-diff-compose-command-override, whose text states the blocker is a defect, not a missing capability, and T117 carries the fix with acceptance criteria. parity_state_diff therefore stays for now; deleting it is the PR after the fix.

A guard fired on this change's own data and was obeyed

The conservation report's no-absolute-paths check rejected a /tmp/-shaped path inside a rationale string. The rationale was rephrased; the guard was not touched.

Verification

Gate Result
cargo fmt --all -- --check pass
cargo clippy --all-targets --all-features -- -D warnings pass (0)
cargo nextest run --profile dev-fast --no-fail-fast 3597 passed
validate / certify pass; 0 blocking
migration check 118 units — migrated 75, residual 43, unaccounted 0; 0 violations
snapshot check 1 fresh, 0 stale
cargo nextest run --profile parity -E 'binary(=parity_conformance_runner)' every case-state-* agrees, including both new cases

The parity lane remains red on the 51 chan-structured-output T113 cases, untouched here.

🤖 Generated with Claude Code

https://claude.ai/code/session_017UCGzJEFZd85HJqz1Wx2kE

… a compose defect

Migrates `parity_state_diff::default-workspace-mount-target-parity` into two
declarative cases, and records the spec violation that measurement surfaced
while attempting the two compose units.

The migrated unit needed TWO cases, not one, because it asserted two distinct
claims through one reported outcome (research D2's inverse defect):

- `case-state-default-mount` (live-differential) — the two CLIs agree.
- `case-state-default-mount-target` (spec-expectation) — the ABSOLUTE claim
  that NEITHER CLI mounts the workspace at `workspaceFolder` and BOTH mount it
  at the spec default `/workspaces/<basename>` (#273). A differential cannot
  carry this: it would pass if both sides regressed together.

The absolute claim needed no new assertion predicate. `workspaceBindTargets` is
already a DERIVED observer field, so the quantified `∄ /workspace ∧ ∃
/workspaces/*` claim becomes plain equality against a one-element list.

The legacy unit wrote no report fragment at all — its `assert_parity` call was
absent — so this is a coverage GAIN, not a transfer.

`bhv-state-default-workspace-mount-target` is a new behavior, and the frozen
denominator guard fired on it, correctly. It is NEWLY NAMED rather than newly
observed: the baseline unit genuinely asserted the claim while the registry
described only the agreement half. Refusing it would mean migrating the unit at
reduced fidelity — losing a claim to preserve a number, which is the exact
under-count 023 exists to fix. `POST_BRANCH_BEHAVIORS` now distinguishes the two
categories explicitly rather than stretching one.

The two compose units are NOT migrated, and the reason is a deacon defect
(T117). The spec says `overrideCommand` "Defaults to `true` for when using an
image Dockerfile and `false` when referencing a Docker Compose file", because
"the default command must run for the container to function properly".
`compose.rs:1323` reads `unwrap_or(true)` on a compose-only path, under a comment
asserting the opposite. Measured against pinned oracle 0.87.0 with a service
whose command touches a marker then sleeps: the marker exists under the
reference and not under deacon. deacon puts its keep-alive in `Cmd` and discards
the service's command; the reference puts it in `Entrypoint` ending in
`exec "$@"` and keeps `Cmd`, so the declared command runs.

Any compose service whose command matters — a server, a bootstrap, a worker —
silently does not start under deacon. It is invisible for the common
`command: ["sleep","infinity"]` idiom, which is why every existing compose
fixture passed.

Migrating those units now would mean tolerating the divergence, i.e. recording a
spec violation as intentional. They stay residual under
`res-state-diff-compose-command-override`, whose text says the blocker is a
defect and not a missing capability, and T117 carries the fix with its
acceptance criteria.

One guard fired on this change's own data and was obeyed, not loosened: the
conservation report's no-absolute-paths check rejected a `/tmp/`-shaped path in
a rationale string, so the rationale was rephrased.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017UCGzJEFZd85HJqz1Wx2kE
@pofallon
pofallon force-pushed the feat/step5b-migrate-state-diff branch from 438e853 to f7b3e13 Compare July 26, 2026 01:21
…T118)

`case-state-appport` is green locally and RED in the `live-certification` lane.
Found by reading the lane's failure list rather than trusting the local run: it
reports `divergingPaths: ["chan-container-state"]` — the channel ROOT, not a
field — with all six of its scoped tolerances STALE. That combination is the
signature of one side having no container at all.

The cause is the fixture: `"appPort": [3000]` is a FIXED host port. 024 Phase 3's
D-3 fix made the two sides sequential so they cannot collide with each other, but
nothing makes port 3000 free on a shared runner. When it is taken, that side's
`up` fails and the differential compares an object against an absence.

It matters beyond one red case: the lane is already red on the T113 families, so
an environment-dependent case hides inside a list of known-red ones, and the
published-ports half of `bhv-state-diff-parity` quietly stops being proven.

Pre-existing on main; recorded rather than papered over. No tolerance was
authored — a whole-channel divergence caused by a missing container is not a
characterized difference, and tolerating it would make "the container was never
created" report `allowed-difference`, the exact silent green pass D-2 exists to
prevent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017UCGzJEFZd85HJqz1Wx2kE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature (alias)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant