Skip to content

fix(native): name and release a run mapping another native home left - #642

Merged
roodboi merged 4 commits into
nextfrom
claude/hack-1952-cross-home-run-mapping
Nov 7, 2026
Merged

roodboi merged 4 commits into
nextfrom
claude/hack-1952-cross-home-run-mapping

Conversation

@roodboi

@roodboi roodboi commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Each launcher version has its own native home, but the run mapping lives in the project. A mapping that a cleanly stopped run left under one home made every command from another home (ps, up, down, doctor --native-cleanup inspect) refuse with the generic "Native project run mapping is unsafe, changed, or owned by another run". A candidate upgrade therefore stranded the worktree's default instance.

Final behavior

When the stored mapping differs from this checkout only in its native home (same canonical project root and directory, their exact identities, same instance), commands refuse with a line that names the owning home and the way out, based on that home's own frontend finalization records:

  • Stopped cleanly (the run's latest hack up lifetime acknowledged confirmed graph cleanup, HTTPS retirement and down hooks): the refusal names hack doctor --native-run-mapping release --expect-selection <sha>.
  • Live (the owning frontend PID exists): the refusal names the home and PID and says to Ctrl-C that hack up or run hack down with the version that owns that home. Release refuses.
  • Interrupted / unproven (frontend exited without acknowledging cleanup, legacy token, explicitly recovered dead owner, or a home that was moved or replaced): named refusal pointing to that version's doctor --native-cleanup inspect and hack down. Release refuses.

hack doctor --native-run-mapping inspect reports state: "foreign-home", owner, ownerHome, ownerPid and, for a stopped owner only, selectionSha256. The new release action:

  • re-proves the selection, holds the project mapping lock, the restart operation lock and the owning home's finalization operation lock (so that home cannot begin a new lifetime for the run meanwhile), and refuses held locks, a pending restart intent or a down-hook journal;
  • keeps the exact mapping bytes in an audit file beside it, then removes only the project mapping. The owning home's graph, volumes and frontend history are untouched. This home's next hack up starts the instance fresh.

Any other scope difference keeps the existing generic refusal and the legacy device-rebind path. No runtime is invoked by the foreign-home path.

Validation

  • New tests/native-project-run-foreign-home.test.ts with two isolated native homes: stopped (named refusal, inspect, wrong-selection refusal, release, fresh publish from home B, audit bytes, owner history kept), live (named refusal with PID, release refused), interrupted, unrecorded, recovered dead owner, stale selection after the owner home starts again, replaced owner home, pending down hooks / held project lock / held owner-home lock, and a non-home scope difference that keeps the generic refusal.
  • tests/native-refusal-cli.test.ts: real CLI with two homes; ps, up, down and doctor --native-cleanup inspect print the one closed line naming the release; doctor --native-run-mapping release then frees home B (down exits 0); a live owner prints the live line with no runtime request.
  • tests/native-project-mapping-command.test.ts: release option parsing.
  • Gates, at head (base origin/next e19e0b1):
    • Focused: 68 pass, 0 fail across native-project-run-foreign-home, native-project-run, native-project-finalization, native-project-mapping-command, native-project-run-filesystem and native-refusal-cli.
    • Full tests/ suite (all 664 files, through the isolated bounded runner): the first run reached its 2400 s budget after 397 files (5399 pass, 39 fail), and a second run covered the remaining 268 files (4095 pass, 29 fail). Every named failure (39 + 26) fails the same way on a clean origin/next worktree, in git-info-exclude, native-compose-file-cold-home, native-compose-vm-file-*, native-vm-file-acceptance, pre-commit-hook, runtime-turbo-inputs, bun-version-guard, e2e/run-dependency-cache, native-ca-doctor-cli, native-compose-file-command, native-compose-inputs and test-config-compiler. The one other failure was the checkout write guard: it flagged that I staged this change in the checkout while the run was going, not a test write.
    • bun run --cwd packages/cli typecheck: only the existing tests/fixtures/atomic-write-foreign-owner-worker.ts(39,25) error, which is identical on origin/next.
    • biome check on the changed files: clean. bun run docs:cli-reference regenerated docs/reference/cli.md.
    • gitleaks protect --staged and gitleaks detect --log-opts=origin/next..HEAD: no leaks.

Remaining gaps

  • Not yet verified with an installed candidate (upgrade, then up in the same worktree's default instance). That acceptance item stays open.
  • Release does not carry data across homes: the previous home's named volumes stay there, and this home starts with fresh data. Migrating retained data between homes is not part of this change.
  • A mapping whose owning home was deleted (for example after uninstalling the old version) is reported as unproven and is not releasable; whether an absent home should count as proof is a product decision.

Refs HACK-1952

🤖 Generated with Claude Code


Start Proof
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

Each launcher version has its own native home, but the run mapping lives in
the project, so a mapping a cleanly stopped run left under one home made
every command from another home refuse with the generic unsafe-mapping
error, stranding the default instance after an upgrade.

A mapping that differs from this checkout only in its native home now gets
a named refusal based on that home's frontend finalization records: a
clean stop names `hack doctor --native-run-mapping release`, a live owner
names its home and PID and how to stop it, and an interrupted or unproven
owner points to that home's own cleanup. The release action re-proves the
selection under the project locks and the owning home's finalization lock,
refuses pending restart or down-hook state, keeps the exact mapping bytes
in an audit file and removes only the project mapping.

Refs HACK-1952

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Nov 7, 2026

Copy link
Copy Markdown

HACK-1952

@roodboi

roodboi commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T17:18:51.003619Z 71804c0 Manual request
🔒 Security Review ✅ Completed 2026-11-07T17:21:47.963409Z 71804c0 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c32c804cbd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread src/backends/native-project-run.ts Resolved
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: c32c804cbd

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

…tartup

A retained `hack up` in the owning home passed its mapping checks and began
runtime effects while that home's finalization records still described the
previous completed lifetime, so a release from another home could delete
the mapping mid-startup.

A retained startup now records an admission under the owning home's
finalization lock before its last mapping check and any runtime effect, and
retires it once it registers its own frontend lifetime (or immediately when
it ends before any runtime effect). Release reads the admission under the
same lock and refuses: a live startup is reported as live, an exited one as
interrupted. A release that wins first makes the startup's last mapping
check refuse before runtime up.

Refs HACK-1952

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roodboi

roodboi commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abe4c9ab0a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread src/backends/native-project-run.ts Resolved
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: abe4c9ab0a

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

A successful stop keeps the down-hook journal's terminal `complete` record
instead of removing it, so requiring the journal to be absent refused
every cleanly stopped run of a project with `lifecycle.down` hooks.

Release now accepts a journal that is this run's completed record and
still refuses an owed, started (unknown), failed, unreadable or another
run's record, with a named refusal.

Refs HACK-1952

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roodboi

roodboi commented Nov 7, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 71804c0a69

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 71804c0a69

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ 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.

roodboi added a commit that referenced this pull request Nov 7, 2026
`provider::publication::port_probe_tests::loopback_probe_refuses_exact_and_wildcard_listeners_and_accepts_a_free_port`
fails intermittently on `next` CI with `published_port_in_use`. It has
been seen on macOS-latest and on ubuntu-latest, the latter on #642,
which changes no Rust.

**Cause:** the free-port half of the test released a listener and then
probed that same port. A parallel test can bind the ephemeral port in
between, and a loaded runner can time out the 250 ms connect. The probe
treats either case as "in use", which is correct for the product but
makes this test flaky.

**Change:** test only. The test now releases up to 20 fresh ephemeral
ports and passes as soon as the probe clears one. It still fails if the
probe never accepts a free port. The exact-listener, wildcard-listener
and port-0 assertions are unchanged, and `require_loopback_port_free` is
untouched.

**Validation:** `cargo +1.97.1 fmt --check`, `cargo +1.97.1 clippy
--all-targets -D warnings`, and the focused test pass locally on macOS.
Gitleaks found no leaks. CI on this PR covers Linux.

**Also in this PR (HACK-1721):** three `doctor --fix` tests in
`tests/doctor-fix-noninteractive.test.ts` used Bun's 5 s default, while
the rest of the file already allows 30 s. They now allow 30 s too. On
this PR's first CI run, the stale-daemon-pid case finished about 60 ms
after the 5 s limit. Locally, all 27 tests in that file pass.

Refs HACK-1946, HACK-1721

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- codesmith:footer -->
---
<a
href="https://backend.blacksmith.sh/track/run-proof?expires=1796663712&installation_model_id=17053&pr_number=644&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F644&variant=prove_it_works&signature=ad5b049327830a436c0d638c45e703b640dcfc2a57962ffb34920922c09a9eee"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-prove-it-works-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-prove-it-works-light.svg"><img
alt="Prove it works"
src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-prove-it-works-dark-3x.png"
width="129" height="28"></picture></a>
<sup><a
href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/644?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
roodboi merged commit 82e2ee4 into next Nov 7, 2026
27 checks passed
@roodboi
roodboi deleted the claude/hack-1952-cross-home-run-mapping branch November 7, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant