Repository navigation
fix(native): bound adoption and authored product clocks by the caller deadline - #499
Merged
Merged
Conversation
… deadline (HACK-1458) Public adoption dispatch now starts one command deadline before it opens the store. Each store inspection phase takes the time left on that deadline, capped at 60 s, instead of a fixed 15 s clock, and an expired deadline returns E_STARTUP_TIMEOUT with the store's fixed deadline message instead of E_CONFIG_INVALID. Authored startup compiler calls are bounded by the remaining startup deadline (floor 1 ms, ceiling 60 s) instead of a fixed 10 s each. Compiler calls outside startup, including the down-hook acquisition after a cancel, take the 60 s ceiling: the fixed 10 s clock failed the graceful stop under load, which then retained the live owner and host processes until a hard cancel (the "Source5 cancellation after readiness" hang). A start that fails or is cancelled after host processes began and before reservation now stops them: their teardown re-acquires inputs under the hard signal, because the startup inputs refuse once the startup signal aborts. A host process launch that fails part-way ends its owned session through the token it created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nslation An adopted store with a caller deadline still reports a held lock as E_LEGACY_ADOPTION_BUSY; only an otherwise unclassified failure becomes the deadline refusal (HACK-1458). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit aea7084f57116a1aae2dc1e312e999fd61280cce)
(cherry picked from commit 86252283e20bfac031b49e25d95edd5cb1bf7fba)
(cherry picked from commit 4f8404ff9e03e7e75507c47f882daa58743444d2)
(cherry picked from commit 5c4ae64cb9de82a09ba97362f2fc9dd1f960a6aa)
(cherry picked from commit 537f0c26f51bc451809eb58724da6e2ead85c997)
A start that fails after reservation retains its host processes on purpose, for `hack down` recovery that a failed test case never reaches, so failed cases left stand-in mux groups running (HACK-1458 item 4). Add a per-case failure cleanup to the native fixture harness, end the recorded mux window groups through it, and cap the stand-in host process lifetime. A passing case never runs the cleanup, so a leak the product causes still fails settlement. Ported from the unreviewed rework-next-499 working tree (wf_b6312000-9d8-2). Not run: tests are on hold; only typecheck and Biome ran on this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeps both sides of the rollback routing deadline: this branch's named probe clocks and next's released-binding read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cleanup signalled every recorded window pid, and a window that exited stays recorded, so a reused id could be sent SIGKILL. It also stopped at a group that ended between its check and its signal. The stand-in now records each window's start time, and the cleanup skips a group whose live leader differs or that has no recorded time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#419 renamed the stand-in owner cap to STAND_IN_CAP_MS and sized it from the case ceiling; this keeps that and this PR's host process cap and fixture helpers. The failed-case test's Bun timeout uses the named fixture margin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both sides appended tests to the end of the routing generation test file: this PR's live caller budget cases and next's HACK-1359 mutation deadline refusal (#563). Both are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roodboi
marked this pull request as ready for review
November 3, 2026 17:34
This was referenced Nov 3, 2026
roodboi
added a commit
that referenced
this pull request
Nov 3, 2026
…split (#570) Repairs a typecheck break on `next` that came from merging two PRs back to back. ## What broke #566 (HACK-1811) split `tests/native-compose-adoption-generation.test.ts`, moving its shared setup into `tests/helpers/native-compose-adoption-generation-fixture.ts`. #499 (HACK-1458) was squash-merged right after it. Its CI had run on a head that merged `next` before #566 landed. Its two public dispatch deadline cases then landed in the slimmed file without the names they use: - `spyOn` - `HackCliError` - `LegacyComposeAdoptedGenerationError` - `mutationCommands` - the bare `root` and `projectRoot` `tsc` on `next` at 1233175 fails with TS2304 for each of these. ## Fix Import the missing names, take `mutationCommands` from the fixture, and read `context.root` and `context.projectRoot` as the other split files do. No test logic changes. ## Checked - `tsc -p packages/cli` passes, and Biome is clean. - `tests/native-compose-adoption-generation.test.ts`: 51 pass, 0 fail, including both HACK-1458 cases. Bun 1.4.4, M5, one run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://backend.blacksmith.sh/track/run-proof?expires=1796319595&installation_model_id=17053&pr_number=570&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F570&variant=start_proof&signature=a07cab5fce585d7c1120766873c16944c4d2e29b77e7251a61d83cccfe26e15c"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-start-proof-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-start-proof-light.svg"><img alt="Start Proof" src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-start-proof-dark-3x.png" width="108" height="28"></picture></a> <sup><a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/570?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>
roodboi
added a commit
that referenced
this pull request
Nov 3, 2026
Brings in #499, #557-#564, #566, #568-#570. #563 added a file-owner case with its own timeout, which this PR's two-argument test wrapper rejected. The wrapper now forwards a case timeout and keeps the file's 60 s budget as its floor. The fixture git spawn scan still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 3, 2026
roodboi
added a commit
that referenced
this pull request
Nov 4, 2026
…refusal (#504) **Update at 9fe1186:** this merges `next` at 1f5a905, bringing in #499, #557–#564, #566 and #568–#570. The text merge was clean, but typecheck found one semantic conflict. #563 added a file-owner case that passes its own timeout, and this PR's two-argument `test` wrapper in `tests/native-compose-file-owner.test.ts` rejected the third argument. The wrapper now forwards a case timeout, and the file's 60 s budget stays the floor. Checked on Bun 1.4.4, with the config compiler built with Rust 1.97.1: - `tsc` passes, and Biome passes. - The file-owner tests, the fixture git spawn scan, and the env, doctor and lifecycle files: 507 pass, 0 fail. **Update at 72661c0:** merged `next` at 1df527b (#545, #419, #337). The e2e fixture conflict was two import additions; both are kept. This PR's git spawn scan then caught three spawns that arrived on `next` with their own git environment: `tests/project-env-worktree-local.test.ts`, `tests/env-legacy-service-scope.test.ts` (which keeps its private `HOME` and now commits with the shared fixture identity) and `tests/e2e/scenarios/worktree-parallel-up.ts`. All three now use `fixtureGitEnv`. Focused tests on Bun 1.4.4, with the scan and the env, doctor and lifecycle files: 478 pass, 0 fail. Typecheck, Biome and gitleaks pass. The e2e scenario change is covered only by hosted docker-e2e. ## Current state (head ba522c9, 2 Nov) Fixes the three findings of the independent review of a16f361. `origin/next` (8621d90) is merged in. The older notes below describe earlier heads. - **Scanner:** each git spawn call is now checked inside its own parentheses, ignoring brackets in string text, with inline negative controls. It also recognizes `run` from `src/lib/shell.ts` and flags Bun shell templates that start with git. An argv held in a variable is a documented gap. The stricter scan found one real unrouted spawn from `next`, in `tests/env-set-local-contract.test.ts`, now routed. - **Native stop:** the last ownership check before `compose down` is bounded by the smaller of the probe timeout and the time left, less a reserve for the child: a fifth of the budget above 1 s, at most 5 s. A slow engine is refused as `probe-timeout` before any child runs, and `hack down --recover` completes the stop. - **Budget:** `tests/fixture-hermeticity.test.ts` has a 120 s case budget, because a case outlived the 5 s default on a loaded host. No assertion changed. Verified locally with Bun 1.4.2 and a private HOME, HACK_HOME and DOCKER_CONFIG, HACK_DAEMON_AUTOSTART_DISABLE=1 and DOCKER_HOST at a missing socket, at load about 8-15: - Three runs each, all passing: `fixture-hermeticity`, `env-set-local-contract`, `checkout-write-guard`, `native-compose-stop-admission`. One run each, passing: `native-compose-storage-witness-command`, `native-compose-file-owner`. - 11 mutations of the new checks were each caught, then reverted. - `packages/cli` typecheck, Biome on the changed files and gitleaks over a16f361..ba522c9 pass. Hosted CI on this head is not yet confirmed here. Open: `tests/native-compose-down-command.test.ts` still fails under this load (HACK-1768). A paired run gave 9 failures with this change and 9 without. Owner decision from the review: with the timeout unset, a hung engine now takes up to 60 s, not 15 s, to refuse each ownership query in a native `down`. ## Current state (head f3619d8, 2 Nov) Rework after the failed verification of 0f51025. `origin/next` (ae032e7) is merged in. - **Ownership probe:** an ownership query in native `down` kept a fixed 15 s bound and ignored `HACK_COMPOSE_STARTUP_TIMEOUT_MS`, and no option or env input could change it. It now follows that budget, at least 15 s and at most the probe's 60 s ceiling. Other operations keep 15 s. On an unset host, a hung engine now takes up to 60 s, not 15 s, to refuse a native `down`. - **Docs:** `docs/env.md` now says a regular-file `.hack/.internal` gives `E_CONFIG_INVALID` for `env set` and `env unset`, which matches their real output. `docs/cli.md` describes the new bound. - **Budget:** the dependent route finalizer cases have a named budget. Verified locally with Bun 1.4.2, a private HOME, HACK_HOME and DOCKER_CONFIG, and no `docker` on PATH: - `tests/native-compose-storage-witness-command.test.ts` passed 5 of 5 runs at load about 10 and 5 of 5 at load 33-98. - A new slow-engine case reproduces the exact refusal (`effect-ownership`, `probe-timeout`) when the wiring is removed. - `packages/cli` typecheck, Biome on the changed files and gitleaks pass. Open: `tests/native-compose-down-command.test.ts` failed 10-11 of 14 cases at load 30-60 with this change. Many hit `invoke`'s 15 s kill (exit 137), including `up` calls this change does not touch; the exit 1 failures were not diagnosed. Without the wiring it failed 11 of 14 at load 30-54 and 13 of 14 at load 62-162. At load 13-20 this head failed 4 of 14: two exit 137 and two `down --recover` exit 1. This file uses `invoke`'s default 1 s budget, so the query bound stays at the old 15 s and the fix cannot change its results. The file has not been run at idle. Hosted CI at this head is still to be read. ## Summary Follow-ups from HACK-1459 (items 1-6 plus its comment) and the HACK-1460 flake. Test fixtures no longer read the caller's Git or Docker environment, load-sensitive cases get named budgets sized for their work, a timed-out case can no longer break the next one, and one env refusal gets a stable code. ## Root causes 1. **Hermeticity (HACK-1459 item 1 and comment).** Fixture `git` calls in about 50 test files inherited the runner's environment. - An exported `GIT_DIR`/`GIT_WORK_TREE` sent the fixture's `init`/`commit`/`worktree add` into that repository. `tests/native-env-metadata.test.ts` cleared those variables in `beforeEach`, but its fixture runs in `beforeAll`, before that. - Under a private HOME, git still read the contributor's `$XDG_CONFIG_HOME/git/config`, whose `core.hooksPath` guard refused fixture commits. That is the actual cause of the local-only failure of `native-compose-generation` "real linked worktree ...". The fixture already set its identity with `-c user.*`; it fails on the hook, not the identity. 2. **`down --recover` storage-witness cases fail locally.** `DOCKER_HOST` did not cause this. The cases fail the same way with and without it, and with a private or a real HOME. `invoke()` defaults `HACK_COMPOSE_STARTUP_TIMEOUT_MS` to 1 s, and `down --recover` bounds its owned stop by that budget. On a loaded host (load average 60-150 here) the stop's synthetic Docker processes take longer than 1 s, so the CLI reports `native_compose_effect_refusal {effect-execution, private-uncertain}` instead of `E_COMPOSE_FAILED`. With a 60 s budget the same run gave `E_COMPOSE_FAILED` at load average 108. Two more wall-clock bounds expired under load: the in-process carrier deadline (`Date.now() + 30_000`, which gave "witness missing ... uncertain") and `invoke`'s 15 s kill (exit 137). 3. **native-env-metadata beforeAll (items 2-3).** The template build (five git processes) had Bun's 5 s hook budget. Bun starts `afterAll` as soon as `beforeAll` times out, while the build keeps creating `native-env-metadata-template-*` directories. Probe: a 200 ms hook budget with a 300 ms body showed afterAll running while the body was still in progress. 4. **HACK-1460 file-owner.** The `up` cancellation case had an explicit 5 s budget. Other cases had 15 or 30 s. When a case times out, Bun runs `afterEach` while the body keeps running, and that body reads the module-level `store`/`root`, which the next `beforeEach` replaces. A late body can therefore act on the next case's store. That is how one timeout becomes "state unsafe" in the next case. 5. **Items 4-6.** - Item 4: since #437, a hung helper start is bounded only by the carrier's remaining budget, so it reports `storage-budget`. That is the right reason, because the remedy is the budget variable that the summary names. The code, the probe-budget test and the reference already agreed; the doc and the test now state it explicitly. - Item 5: `hack env hydrate` with a `.hack/.internal` file is refused by the earlier legacy adoption-state check (ENOTDIR counts as an input access failure, never as absence), so it reports `E_CONFIG_INVALID`. docs/env.md said `E_PATH_CONFLICT`. - Item 6: `EnvLayerLockRefusedError` was an uncoded `ClosedCliError`, so the CLI printed it without an `E_*` prefix and `--json` reported `E_UNEXPECTED`. ## Fix - New `tests/helpers/fixture-git.ts`: `fixtureGitEnv()`, `fixtureGitShellEnv()` (for `src/lib/shell.ts`), `runFixtureGit[Sync]()`. - It builds the environment from `PATH`/`TMPDIR` plus the caller's values. - It removes every `GIT_*` variable, `DOCKER_HOST`/`DOCKER_CONTEXT` and the runner's `HOME`/`XDG_CONFIG_HOME`. - It sets `GIT_CONFIG_GLOBAL=/dev/null`, `GIT_CONFIG_NOSYSTEM=1`, a fixed author and committer identity, and `GIT_TERMINAL_PROMPT=0`. - `gitEnv` lets a test set a Git variable on purpose (used for `GIT_INDEX_FILE` and `GIT_CEILING_DIRECTORIES`). - Every fixture git spawn in `tests/` goes through it (about 50 files). The e2e `runCommand` gets an `exactEnv` option. The checkout write guard drops a caller's repository variables but keeps the contributor's config. - `tests/fixture-hermeticity.test.ts`: - Exports `GIT_DIR`, the work tree, the index, the object directory, the common dir, a hostile `GIT_CONFIG_GLOBAL` and a hostile identity, then runs every fixture route. The scratch repository stays byte-for-byte unchanged, and no hostile hook runs. - A fixture HOME's own `.gitconfig` cannot add hooks, signing or identity. - An ambient `DOCKER_HOST`/`DOCKER_CONTEXT` never reaches fixture git or the private CLI env. - A source scan refuses any new fixture git spawn that does not use the helper. - `native-compose-storage-witness-command`: named `RECOVERY_DEADLINE_MS` (30 s), `CLI_COMMAND_TIMEOUT_MS` (45 s) and a 3 min case budget. The carrier deadline uses the product default. The source-unavailable recovery case also runs with an ambient `DOCKER_HOST` at a missing socket plus a `DOCKER_CONTEXT`. - `native-env-metadata`: named `TEMPLATE_BUDGET_MS` (60 s) on both hooks. `afterAll` waits for the build to settle, and a build that outlives that wait removes its own directory. - `native-compose-file-owner`: one named `FILE_OWNER_CASE_BUDGET_MS` (60 s) via `setDefaultTimeout` replaces the per-case 5/15/30 s budgets. `afterEach` waits for the running body before teardown. - `EnvLayerLockRefusedError` is now a coded `E_PATH_CONFLICT` `HackCliError`. docs/env.md is aligned on hydrate's `.internal` file and the lock refusal. The storage-carrier reference names `storage-budget` as the reason for a hung start. Assertions in the flaky cases are unchanged. Only budgets, deadlines and teardown order changed. ## Evidence In progress: local 30-run soaks under load and hosted CI at this head; this section is updated when they finish. ## Gaps Listed when the evidence above is complete. Refs HACK-1459 Refs HACK-1460 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/504?autoLogin=true&ref=codesmith_pr_footer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v3.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png" width="162" height="28"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1795474807&installation_model_id=17053&pr_number=504&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F504&signature=27b85b1220571c8b55a775f2a3ef4ffbd481011d47aec883a3beddb23deff445"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png" width="190" height="28"></picture></a> <sup>Need help on this PR? Tag <code>@codesmith-bot</code> with what you need.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Dimitri Kennedy <344842+roodboi@users.noreply.github.com>
roodboi
added a commit
that referenced
this pull request
Nov 4, 2026
Refreshes the base after #499, #504, #554 and the other merges of Nov 3. This PR and #570 made the same import repair to tests/native-compose-adoption-generation.test.ts, so the merge listed mutationCommands twice; this takes next's copy of that file. Typecheck passes, and so does that file's run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roodboi
added a commit
that referenced
this pull request
Nov 4, 2026
…-1810, HACK-1801) (#571) Deadline-driven adoption refusals now stay timeout-shaped through generation and lower binding/probe layers. Real SIGINT/SIGTERM cancellation returns `E_CANCELLED`, pending ownership stays retained, and late fixture cleanup finishes before its caller removes the mux state directory. Originally stacked on #499 (`wf/g106-product-clock-bounds`, head `3e85b9bd`). After #499 was squash-merged as `85212e6ac6`, this branch merged `origin/next` (including #569, #568, #560 and #561) without rebasing. This draft targets `next`; no merge or release is requested. ## HACK-1810 findings - The reported “retained command dispatch uses only original IDs and keeps anchors through stop and recovery” fixture creates a v1 generation. An explicit version assertion now verifies that boundary. V1 never enters `boundedMutationContext`; the public command's original controller is aborted only by its SIGINT/SIGTERM handlers. The case teardown closes the store and restores env, and does not abort this signal. This is the caller-signal path, not the mutation deadline timer or case teardown. The supplied historical failure does not identify which external sender delivered the signal; the healthy case passed locally without added load. Both direct command cancellation and store-originated cancellation now map to `E_CANCELLED`, never invalid config. - Separately, the v5+ mutation timer can fire in the rounded-down final millisecond before `Date.now() >= deadline`. Its abort previously looked like caller cancellation. A private signal-provenance set now preserves expiry in `cancelled()` and in the outer bounded catch, including failures that surface through binding/state probes. Caller cancellation still takes precedence, and observed `E_LEGACY_ADOPTION_CHANGED` keeps its code. - The v4 typed-locals case also passed locally without added load. A slow engine-proof phase could nevertheless become invalid state: the binding translator erased the known probe-timeout classification, then generation translation emitted STATE without an aggregate caller deadline. Known probe timeouts now become binding TIMEOUT and generation DEADLINE. A synthetic sixteen-second phase overrun with no caller deadline proves that path; no claim is made that the historical 20.5-second failure was reproduced. ## HACK-1801 disposition 1. Retained routing proof expiry now emits `E_LEGACY_ADOPTION_DEADLINE` and the closed `proof-deadline` diagnostic. A regression expires the clock after the real route proof returns, before the owner fence runs. The existing full-proof expiry regression now also asserts the timeout code. 2. Both publication and rollback build their transaction copy inside the `try` that closes the originals handle. Separate tests expire the live budget immediately after `holdDirectory` returns and assert that the handle closes despite the getter throwing. 3. The case harness exposes `drain()` for overrun bodies and their second cleanup. The authored fixture caller awaits it before removing retained roots. Overrun ownership is captured before initial failure cleanup, so a body that finishes during that cleanup still receives a second cleanup. A real mux regression starts a window after the body budget expires, verifies the root/state remain available through cleanup, and confirms group absence; a separate race regression checks completion during initial cleanup. 4. The removed/live/foreign/hard-canceled cases now observe fresh teardown acquisition under a separate hard signal; only hard-canceled sees that signal aborted. Unconfirmed-group must not reach acquisition. Existing effect-order and retained-binding assertions remain. ## Mutation evidence All mutations were temporary and restored before verification: - Remove the owned timer's provenance mark: the generation abort regression reports CANCELLED rather than DEADLINE. - Remove the bounded catch's provenance condition: the independent binding-layer abort regression reports STATE rather than DEADLINE. - Remove binding timeout translation: the no-caller-deadline v4 phase regression reports STATE. - Move either transaction constructor outside its close guard: its publication/rollback regression observes an unclosed handle. - Restore routing proof STATE: the post-route-check regression rejects the code. - Make `drain()` return immediately: the mux regression observes early drain completion. Check `bodyRunning` only after initial cleanup: the race regression observes one cleanup instead of two. - On M5 macOS, remove #499's `refreshPreReadyHostInputs` call from `runPreparedLifecycle`: **live**, **foreign**, and **hard-canceled** were run separately and each failed its fresh-admission assertion (expected 1, observed 0). All five unmutated pre-Ready cases passed, and the full authored file passed. ## Verification Pinned Bun 1.4.4 and frozen dependencies. No load generator and no whole-repo test suite were run on the shared host. - `bun run typecheck`: pass. - `bun run check` and explicit lint of all changed TypeScript: pass (warnings only). - `bun run build` and `./dist/hack --version`: pass. - Targeted Linux run at the final source revision: **326 pass, 61 skip, 0 fail**, 4,471 assertions across 15 files. This covers all split generation families, adoption binding/command/routing, native-fixture-cases, authored-start, closed diagnostics, CLI envelope and plugin generation. The skips are the macOS cases and the optional previous-owner artifact check. - Both timer-abort regressions and all other regressions passed within that combined run. No tracked files changed while it ran. - M5 macOS source snapshot after the `next` merge: full `native-authored-project-start.test.ts` plus `native-fixture-cases.test.ts`: **70 pass, 0 fail**. These authored/helper files and their exercised product behavior are unchanged by the later binding-abort correction. - The new error code is registered and the optional plugin error-code reference was regenerated. CLI-envelope, plugin-generation and closed adoption-diagnostic contracts are included in the local test command. - Pre-Ready tests use the file's stand-in driver/mux; this is frontend/lifecycle test evidence, not physical guest, installed artifact or release qualification. ## Independent review One persistent Claude Opus 5.5 reviewer, read-only: | Round | Revision | Result and response | | --- | --- | --- | | 1 | `d7882aa0fa3485db388faf7113d1002f867b7dd9` | CHANGES: P2 early timer abort surfaced through binding could still become STATE; P3 generic PROBE text still mentioned time. Added the bounded-catch provenance guard and independent lower-layer regression; corrected the text. | | 2 | `c403d2b8d48616dfedebed2bb781ac2ab262f3e5` | **VERDICT: CLEAN**. Both findings confirmed fixed; no new findings in the incremental or complete diff. | Reviewer thread: <t3-thread://v2/a784d2e4-ee60-4c79-b68f-439a5ba08e88/thread:delegated-task:command%3Amcp%3Ace9302ed-6cf7-46e9-ad48-7e7af31a45a7%3Adelegate-task%3Ahack-1810-1801-review-round-1-d7882aa0> The review did not rerun tests; the verification results above are the owner's recorded runs. Hosted CI and automated PR review are checked separately after opening this draft. Release intent: `fix`. No data format or cleanup authority was relaxed. No merge, publication or deployment is part of this PR. <!-- codesmith:footer --> --- <a href="https://backend.blacksmith.sh/track/run-proof?expires=1796323030&installation_model_id=17053&pr_number=571&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F571&variant=proof_this_pr&signature=a308c7fa543708cca90804ca8e0617dd4ec7c9f47563cd1c782af63748b99182"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-proof-this-pr-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-proof-this-pr-light.svg"><img alt="Proof this PR" src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-proof-this-pr-dark-3x.png" width="121" height="28"></picture></a> <sup><a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/571?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 --> <!-- hack-1810-ci-integration-ede1b8e9 --> ## CI integration update — `ede1b8e9` GitHub's first CI run tested the merge of `c403d2b8` with newer `next` commit `1f5a9054` (#570). Both branches repaired the same fixture destructure at different positions, producing a duplicate `mutationCommands` declaration in that synthetic merge. The config-compiler and test-shard failures all traced to that declaration; the aggregate test failure followed from the shards. Merged the updated `origin/next` into this branch without rebasing (`90c54bd5`) and removed the duplicate while retaining #570's slot (`ede1b8e902678a7562e25087d6e00d9f0c97aa7b`). The adoption product code is unchanged from the reviewed revision. - Same persistent Opus 5.5 reviewer, **round 3: VERDICT: CLEAN at `ede1b8e9`**. The deduplication, imports, fixture references, and intact deadline cases were checked; no new findings. - Fresh requested verification after the repair: `bun run --cwd packages/cli typecheck` passed; the full `tests/native-compose-adoption-generation.test.ts` passed **51 tests, 0 failures, 938 assertions**, including both HACK-1458 public deadline cases (105.96 seconds). - Root `bun run typecheck`, `bun run check`, and focused lint also passed after the repair. The earlier 326-test local and 70-test macOS evidence remains valid for the unchanged product paths. - Pushed normally to this PR's own branch. Draft status and base `next` are retained. Nothing was merged into `next`. - CI and Codex code re-review are being checked at the new head; results from the superseded head are not treated as new-head evidence. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Dimitri Kennedy <344842+roodboi@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Update at 3e85b9b (second
nextmerge, at c019124): this brings in #557, #564, #562 and #563. The only conflict was at the end oftests/native-compose-adoption-routing-generation.test.ts. This PR adds live caller budget cases there, and #563 adds the HACK-1359 mutation deadline refusal; both are kept. Typecheck and Biome pass on Bun 1.4.4. The five adoption generation test files and the compose-env-at-rest tests pass (235/0). The file-owner tests need a built config compiler; once it was built with Rust 1.97.1, they passed on their own (29/0).Update at 04abddb: merged
nextat 1df527b (#545, #419, #337). The one conflict was intests/native-authored-project-start.test.ts: #419 renamed the stand-in owner cap toSTAND_IN_CAP_MS, sized from the case ceiling. Both sides are kept, and the failed-case test's Bun timeout now uses the named fixture margin, which is the same 5000 ms. Typecheck and Biome pass on Bun 1.4.4.tests/native-compose-adoption-generation.test.tsrun on its own passes: 123 pass, 0 fail.E_CONFIG_INVALIDfor a cancellation, tracked as HACK-1810 and noted on HACK-1458.Refs HACK-1458 (unit G106). Product fix for the four product clocks that kept HACK-1367's loaded runs from passing. Test-side budgets stay with #419 (G52/G105); this PR adds new cases at the end of the two shared test files and edits none of #419's hunks.
Root cause
Public adoption dispatch.
tryLegacyComposeAdoptedCommandopened its adoption store without a deadline, so every store inspection phase (one probe owner) got the default 15 s aggregate clock, whateverHACK_COMPOSE_STARTUP_TIMEOUT_MSallowed. A slow engine expired it asE_NATIVE_COMPOSE_PROBE_TIMEOUT;translate()turned that intoE_LEGACY_ADOPTION_STATE, and the command reportedE_CONFIG_INVALID("state is invalid, unsafe or changed"). The command's own deadline only started afterloadActive, so inspection before it was never bound by the caller.Authored compiler calls.
acquireNativeExecutionInputsnever passed a compiler timeout, so each compiler invocation (and the laterassertFresh/value checks) kept the transport's fixed 10 s default, even with minutes of startup budget left.Source5 cancellation after readiness hang. Reproduced: after
onReadyaborts, the cancel'sdown.beforere-acquires inputs with the hard signal. That acquisition also kept the fixed 10 s compiler clock. When one compiler call took longer,down.beforefailed atacquire(no hook ran),onStopFailurefired, and the start retained the live owner and host processes, waiting for a hard cancel that the case never sends. With a scratch copy whose compiler sleeps 11 s after readiness, the case hung for its whole 420 s budget, with hook eventsdown.before:acquirethendown.before:stop-operationand no down hook, the same symptoms as the loaded report.Failed authored cases leave host process groups running. This is a product path, two of them:
stopUnstartedHostProcessescould never passhostProcesses.stop()'s freshness check (it re-reads inputs with the aborted signal), so the groups stayed up. A loaded local run of a new case showed it directly: startup expired afterhost-process-ready.jsonwas written, the start failed, and the mux window group was still alive afterwards.createNativeAuthoredHostProcesses().start()had no failure path. A failure after the launch intent (cancel, deadline or refused check during the launch) left the mux session running behind an intent that recovery never converts into authority.Failures after reservation still retain host processes on purpose, with complete owner/ready/state records that
hack downrecovery stops (retireNativeAuthoredHostProcesses). Ending those in a test is test cleanup (test: derive load-sensitive harness budgets from named constants #419).Fix
native-compose-adoption-generation.ts,native-compose-adoption-command.ts):deadline. With one, each inspection phase getslegacyAdoptionProbePhaseMs: the remaining time, capped atLEGACY_ADOPTION_PROBE_PHASE_MAX_MS(60 s). An expired deadline refuses asE_LEGACY_ADOPTION_DEADLINE, and an unclassified failure after a probe timeout or past the deadline becomesE_LEGACY_ADOPTION_DEADLINE, notE_LEGACY_ADOPTION_STATE. A store without a deadline is unchanged.HACK_COMPOSE_STARTUP_TIMEOUT_MS) before it opens the store and uses it for inspection, the retained operation, the plain container runner andpsinspection.E_LEGACY_ADOPTION_DEADLINEmaps toE_STARTUP_TIMEOUT. The message stays the store's fixed text, so the closedlegacy-deadlinediagnostic token is unchanged.native-config-compiler.ts,native-project-validation.ts,native-execution-inputs.ts): namedNATIVE_CONFIG_COMPILER_MIN_TIMEOUT_MS(1) andNATIVE_CONFIG_COMPILER_MAX_TIMEOUT_MS(60 000),nativeConfigCompilerTimeoutWithin(remainingMs), and an optionalcompilerTimeoutMsgetter that every compiler invocation of a selection reads, including later freshness checks.native-authored-project-start.ts):native-authored-host-processes.ts): a start that fails after its launch intent calls the controller'sabort(), which ends the session through the ownership token it created. Owner bookkeeping is cleared only when every launched group was recorded and is proven absent within 5 s. Otherwise it stays retained.docs/reference/native-compose-adoption.md,docs/reference/native-authored-commands.md.Tests
New cases, each proven by mutation (product change reverted in a scratch copy):
HACK-1458: public dispatch inspection outlives the former fixed 15 s phase clock while the caller deadline remainsDate.nowjump of 16 s after the first engine probe, 120 s deadlineE_CONFIG_INVALID"state is invalid, unsafe or changed"HACK-1458: an expired public dispatch deadline ends inspection as a startup timeout, not invalid config0(inspection ignored the expired deadline and started the container)HACK-1458: a startup compiler call may outlast the compiler's 10 s default while the startup deadline remainscompilesleeps 10.5 sstage inputs (E_COMPILER_TIMEOUT)after 11.4 sHACK-1458: Source5 cancellation after readiness settles when its down acquisition compiler is slowHACK-1458: cancellation after host processes start and before reservation stops themfrontend-planheld until cancelledprocess-orderisstartedonly and the host group stays aliveHACK-1458: cancellation during the host process launch ends the launched grouplist-panesdelayed 1 sabandonLaunchmade a no-op: the owned mux session (mux.json) staysEvidence
In progress: 10-consecutive loaded runs of both whole files are running locally (M5, Bun 1.4.2, private HOME/HACK_HOME/DOCKER_CONFIG, keychain fallback disabled, unreachable DOCKER_HOST, added CPU load stopped in a trap), on this branch plus #419's test-side budgets. Hosted CI at the exact head is the full-suite evidence. This section will be updated with results.
Gates
dirover agit log -p origin/next..HEADexport: no leaks.bun run check(includesprivacy:check): passed.bun run --cwd packages/cli typecheck: 0 errors. Biome on the changed files: no new warnings (the 8 existing complexity warnings innative-compose-adoption-generation.tsremain).docs:cli-referenceand plugin regeneration do not apply.origin/nextmerged at 246f1b4.Gaps
To be completed with the evidence.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.