Repository navigation
Conversation
An env-only Compose edit stranded a retained run whose graph has a `hack.dependencies.*` cache: plan reconciliation skipped every cache graph, so the edit fell through to the hostname-change proof and `up`/`restart` refused with a misleading `graph_hostname_change`. - Cache graphs are now eligible for reconciliation. A cache whose freshly resolved identity equals the recorded one is kept with its provenance; a changed identity selects that identity's shared cache exactly as a fresh admission does (adopt by labels or create, then the initializer runs) from a freshly published source snapshot, and only this run's reference to the old shared cache is released. Run-owned data is never reselected as a cache: declaring one refuses with `graph_plan_reconcile` and names the service and the `hack.dependencies.cache-volume` field. - A cache identity now binds the initializer's own reviewed definition and its cache volume declaration instead of the whole Compose digest, so an edit to another service keeps the cache, as Compose keeps a named volume. Receipts recorded under the earlier whole-document identity keep their cache while the review still resolves to it, and move to the new identity on the first edit. - Graphs that reconciliation still does not select (live source, a carried cache scope, a pending source-device rebind or initializer cache release) refuse a non-hostname edit with `graph_plan_change_unsupported` instead of `graph_hostname_change`; a hostname change mixed with other edits names the routed service. Errors carry a value-free `plan_change` diagnostic and the CLI prints closed guidance: revert, or `hack down --remove-data` then `up`. - Adds the native-cache-reconcile TLA+ model (54 states) with negative controls for whole-document identities, stale cache reattachment and run data reused as a cache. Refs HACK-1937 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (2)
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
The v2 dependency-cache identity bound the mount layout only when a mount used a subpath. Adding or changing another service that mounts the shared cache volume read-write therefore kept the same identity, so a new writer could change contents that other runs and instances reuse. The current identity now always binds the full layout: every active service that mounts the cache volume, with its target, subpath and read-only flag. Adding, removing or changing a writer selects a fresh cache; an environment-only edit to a service keeps it. Mounts stay as declared, as in Compose and v4, rather than being forced read-only. The legacy whole-document identity is unchanged, so earlier receipts still match exactly. Regression tests cover a new read-write mount, its access mode, an env edit to that writer, a second initializer, and reconciliation selecting a fresh cache when a writer service is added. Refs HACK-1937 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Follow-ups at Cache identity now binds every mount of the cache volume (security review, MEDIUM). Before this, the v2 identity included the mount layout only when a mount used a subpath. Another service that mounted the shared cache read-write could therefore be added or changed under the same identity and alter contents that other runs reuse. The current identity now always binds every active service mount of the cache volume: service, target, subpath and read-only flag. Adding, removing or changing a writer selects a fresh cache; an env-only edit still keeps it. I did not force non-initializer mounts to read-only: Compose and v4 mount them as declared, and apps commonly write into these volumes, so the identity change is the safeguard. The legacy whole-document identity is unchanged. New regression tests cover four cases:
A mutation that drops the layout fails both writer tests. Focused Rust tests: 31 pass. clippy, fmt and all TLA+ models (162 controls) pass, and gitleaks is clean. Loopback port-probe test ( @codex review |
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: afb4526eb6
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: 139be6c345
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…nstance A service other than the initializer that mounts a dependency cache read-write can change the cache contents through its own image, command, environment or source, none of which the cache identity hashes. On a contributor branch it could therefore poison a cache that a linked worktree later reuses. Within one checkout the same author controls every input, so the trust boundary is sharing across worktrees and branch instances. - A cache with a writable non-initializer consumer binds the plan namespace (this checkout and branch instance) into its scope, so it is never shared across linked worktrees. Caches whose other consumers all mount read-only keep sharing; the initializer's definition, image and lockfiles stay in the identity. - Such graphs always re-prove the cache through reconciliation, and no earlier whole-document identity is matched for them: a run created by an earlier build moves to its instance-scoped cache once instead of reusing the shared one. Env-only edits inside one instance still keep the cache. - The native-cache-reconcile model adds writable consumers and foreign writes (2,208 states) with a `poison` negative control that keeps such caches shared and fails `NoForeignWrites`. Refs HACK-1937 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Host proof at Worktree A, app mounts the cache read-write (an instance-scoped cache)
Linked worktree B: sharing follows the consumer mode
Pre-existing behavior found during the proof. When B runs as its default branch instance One fixture mistake: an edit that switched the app mount to Afterwards I stopped the VM and removed the native home, the fixtures, the candidate bundle and the VM home alias. |
## What this is Merge train batch 7 into `next`: three real-project trial fixes. Each component PR's reviewed head is merged with `git merge --no-ff`, in this order (#638 is stacked on #636). Integration conflicts are resolved in the batch's merge commits, described below. Hosted CI on this branch is the full-suite gate for the combined result. | PR | Title | Linear | Head included | Review at that head | | --- | --- | --- | --- | --- | | #636 | fix(native): compile host aliases like execution and name unbound aliases | HACK-1939 | `4d25fa5a` | Codex code + security: no findings; 0 open threads | | #638 | fix(native): run stock image processes in wrappers like Docker, naming refusals | HACK-1939 | `08f2d8c3` | Codex code + security: no findings; 0 open threads | | #637 | fix(native): reconcile edited graphs that have a dependency cache | HACK-1937 | `592a9b1d` | Codex code + security: no findings (the security review confirms the cache-poisoning fix); 0 open threads; real-VM proof passed | ## Integration changes - **#636 with batches 1–6:** - The restart preflight and native `up` pass both #608's `dependencyOwners` and #636's `internalExtraHostSources`. - #615 and #636 both added a "nothing was reserved" startup report. They are now one `finalInspectionFailure`: #615's check plus #636's guards (a settled failure, not a restore, no mapping attempted), with the combined message "nothing was created and no cleanup is needed" followed by #615's diagnostic. - #636 matched `native_graph_unreserved`, but image projects inspect with `graph inspect`, which only returns `graph_unreserved`. #636's check therefore could never fire, so its tests now use `graph_unreserved`. - #636's ready summary and confirmed-stop line ride #611's progress events, so `up` prints one ready line, `Project is ready (SERVICES; run RUN). …`, with HTTPS URLs and published ports under it. Ctrl-C prints one stopped line, which states that data was retained when a run mapping was published. - **#638 with #615 / #622:** the error type keeps the fixed-message type and adds #638's process-refusal types. The unified startup report appends #638's named process refusals after the startup diagnostic. Doctor keeps the amd64 emulation and settings checks next to #638's process-wrapper check. - **#637 with #615 / #638:** failures keep the fixed message, service and process refusals, and add #637's `planChange`. Its guidance replaces "inspect owned state before retrying". The cache-poisoning fix holds in the merged code: - `dependency_cache.rs` is #637's file unchanged; - `plan_reconcile::ordinary_layout` still routes caches with a writable consumer through reconciliation; - no batch change mounts a cache volume outside `instance_scoped_volumes`. - **Size fix (`dbcf2bcc`):** the three error additions together pushed `CandidateError` past clippy's large-error bound. `cause_code` is now a boxed `str`, and process refusals and the plan change share one boxed, flat-serialized `RefusalDiagnostics`. A test pins the size and the JSON shape. - **#640** (credential-helper EPIPE race fix) was folded into batch 6, so it is not listed here. ## Validation on this branch (`458e0a93`) - Clean CLI typecheck: pass. Biome on changed files: no errors. - `RUSTUP_TOOLCHAIN=1.97.1 bun run check:local`: pass. All-features clippy `-D warnings` (Zig 0.15.2): pass. - Cargo `--lib`: 1375 pass. `--features native-config-plan` `provider::graph`: 688 pass. Contracts: `project_contract` 66, `compose_fields_contract` 10, `interpolation_budget_contract` 1, `local_contract` 14. - `bun run test:models` (TLA+ 1.7.4): exit 0, 177 controls verified. - Focused bun tests, bounded runner, the changed test files: 260 pass, 0 fail. - `docs:prepare` + `docs:check`, `privacy:check`, gitleaks over `origin/next..HEAD`: pass. Not run locally: the full bun suite, the Linux cargo jobs, docker-e2e and native host qualification. Hosted CI covers the first three. After this merges, each component PR is closed with a link to the merge commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://backend.blacksmith.sh/track/run-proof?expires=1796634294&installation_model_id=17053&pr_number=641&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F641&variant=run_proof_on_this_pr&signature=daf0979b3cf0e8fb0d4344fa34460d87b7d75f22ce9fa22f3da3d8c483a575a9"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-light.svg"><img alt="Run Proof on this PR" src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-run-proof-on-this-pr-dark-3x.png" width="168" height="28"></picture></a> <sup><a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/641?autoLogin=true&ref=codesmith_pr_footer">Open in [code]smith</a> · Need help on this PR? Tag <code>@codesmith-bot</code> with what you need.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> --------- Co-authored-by: Dimitri Kennedy <344842+roodboi@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged into 🤖 Addressed by Claude Code |
Problem
An env-only Compose edit stranded a retained native run whose graph has a
hack.dependencies.*cache. Afterupand Ctrl-C, changing one environment value on the app madeup(andrestart) refuse withgraph_hostname_change, and only reverting the edit worked. Compose and v4 apply this edit on the nextup.Cause
Plan reconciliation (#614) treated every graph with a dependency cache as ineligible, so the edit fell through to the narrower hostname-change proof. That proof found no hostname change and refused with its own code, which named the wrong field. Even if reconciliation had run, the cache identity bound the whole Compose digest, so any edit anywhere would have selected a new, empty cache.
Final behavior
plan_reconcilenow selects graphs with dependency caches. A cache whose freshly resolved identity equals the recorded binding is kept, with its provenance fence. A changed identity selects that identity's shared cache exactly as a fresh admission does: it is adopted by labels or created, and the initializer installs into it, from a freshly published source snapshot (source-compatibilityreportsreconcile: truewith no retained revision, and the CLI publishes the current snapshot). Only this run's reference to the old shared cache is released. Run-owned data keeps the existing reattach rules.config::retain_recorded_legacy_caches, used by strict replay, restart and reconciliation). It moves to the new identity once, on the first edit, instead of refusing. A receipt whose cache has a writable consumer never matches an earlier shared identity; it moves to its instance-scoped cache once.graph_plan_reconcileand names the service and thehack.dependencies.cache-volumefield.graph_plan_change_unsupportedinstead ofgraph_hostname_change.graph_hostname_changeand now names the routed service.plan_changediagnostic (service identifier plus a closed field). The CLI validates it and prints closed guidance: revert the edit, or runhack down --remove-dataand thenhack up. Native messages are still never printed.Validation
plan_reconcile,dependency_cache,hostname_change): 33 pass at592a9b1d, and the full lib suite passes 1,200/1,200 from a real-path target. Mutations that drop the layout or the instance scope from the identity fail their tests. New cases cover a writable consumer in worktree A not sharing with worktree B, a read-only consumer still sharing, an env edit inside one instance keeping the cache, and an earlier shared receipt with a writer moving to its instance cache. New cases cover the synthetic repro (app env edit keeps the cache and its provenance; the reconciled receipt still loads), initializer and lockfile changes selecting a fresh cache while keeping run data, a new read-write (or read-only) mount of the cache by another service changing the identity while an env edit to that service keeps it, reconciliation selecting a fresh cache when a writer service is added, run data refused as a cache (pure check and projection), dropping a cache declaration, a legacy identity kept on an unchanged review and replaced on edit, reserved shared caches allowed to exist, and the hostname refusal codes.cargo +1.97.1 test: 1,352 pass. The remaining failures are environment-only:node_contractfailed with SUN_LEN on the long checkout path and passes 20/20 from a short path.explicit_root_binding_requires_exact_executablefailed through the/tmpsymlink and passes from its real path. The loopback port-probe test failed twice during an earlier full run; on a recheck it passed 3/3 on cleanorigin/nextand 3/3 on this branch (short-path checkouts,cargo +1.97.1), so it is transient and not caused by this PR.cargo fmt --checkandcargo clippy --all-targets -D warningsare clean.bun run --cwd packages/cli typecheck: pass, from a checkout outside/private/tmp. Biome is clean on the changed files; one pre-existing complexity warning remains in an untouched file.docs:checkpasses.native-cache-reconcilemodel (2,208 distinct states) with four negative controls. They fail as intended: a whole-document identity failsUnrelatedEditKeepsCache, reattaching a stale cache failsCacheMatchesInputs, reusing run data as a cache failsNoDataAsCache, and keeping writable-consumer caches shared (the poisoning path) failsNoForeignWrites. Every maintained model still verifies.origin/next..HEADboth report no leaks. Normal hooks ran.Host proof (at
afb4526e; real VM, isolated HOME and native home, synthetic fixture)The candidate is this branch's
hack-nativeand CLI in a copy of the 5.0.0-next.10 bundle, with unchanged guest binaries. The fixture is an alpine initializer that fills a cache volume, plus an app that prints itsMARKERand the cache contents.up(MARKER=one), then Ctrl-C. Ready; the cache was created.MARKERone to two, thenhack restarton the stopped graph. It refuses with the existing pointer tohack up, notgraph_hostname_change.up. Same run,marker=two, and the same cache volume: identical name,created_atand directory identity, and the initializer's first-run stamp is preserved.MARKERtwo to three andhack restart. Same run,marker=three, and the same cache volume.up. Same run, a new cache volume (new identity),installed=v2, and a new first-run stamp.Remaining gaps
project_share), so I could not create a next.10 run there.upthat refuses inside the foreground owner (not at thesource-compatibilitypreflight) still prints the generic foreground startup envelope with the code. The new guidance appears on the preflight path, which runs the same pure checks first.Refs HACK-1937
🤖 Generated with Claude Code