Skip to content

fix(env): the automatic mux sweep keeps files configuration reads (HACK-2181) - #804

Merged
roodboi merged 49 commits into
nextfrom
claude/hack-2181-sweep-live-inputs
Nov 14, 2026
Merged

roodboi merged 49 commits into
nextfrom
claude/hack-2181-sweep-live-inputs

Conversation

@roodboi

@roodboi roodboi commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

The automatic stale terminal-session payload sweep now uses the same live-input removal guard as hack doctor --fix. Before each removal it resolves current configuration strictly and keeps payloads whose env.json or directory is live, retired, or cannot be resolved. Unreadable configuration prevents cleanup.

Shared removal guard

src/lib/live-inputs.ts shares path/realpath and retired-store decisions between both cleanup paths. The live set includes configured stores/keys, shared and project environment inputs, and the global configuration file itself—even when HACK_GLOBAL_CONFIG_PATH points to a stale payload's env.json. Doctor fixes retain both inspected and current inputs; automatic sweeps re-resolve current inputs before each candidate. Existing ownership, file-type, single-link and age checks remain in place.

Validation at 6e767f5a513ea43d6028c3fb627f40839635e1c6:

  • 59 focused tests pass: mux live inputs 5, private environments 6, secrets hygiene 42, hygiene scope 5 and private tmux integration 1. All use isolated fixture homes/temp state; the tmux test uses its own short socket path.
  • New global-configuration regression first failed on inherited code because the configured file was deleted, then passed with the shared guard addition. Ordinary stale payload beside it is still removed. Existing tests cover configured store keys, default project discovery and unreadable configuration preserving payloads.
  • Fresh CLI typecheck/check, build, docs prepare/check, privacy, changed-file lint and diff checks pass. No local Rust builds, real Docker or owner runtime changes.
  • The changed test file is in the Linux CI pool; macOS filesystem behavior is not qualified by these Linux runs. No full local suite.
  • Security documentation and the v5 short worktree page describe the behavior. Native legacy discovery still conservatively skips automatic cleanup when scope cannot be resolved; this existing limitation remains.

HACK-2181. Persistent second-family review, exact-head Codex and hosted CI remain pending.

roodboi and others added 30 commits November 13, 2026 06:49
…rotation advice (HACK-2165)

Audit F1 and lead item 2:
- A private write (.hack/.env files, the project key, the encrypted
  store and its key) staged its complete contents in a
  `.<name>.<uuid>.tmp` sibling that no ignore entry covers, so a crash
  could leave a copy git would stage. Staging now happens in
  `.hack-staging/` next to the target: a private (0700) directory
  whose `.gitignore` of `*` exists before any staging file, so git
  never lists a leftover. The next write there sweeps leftovers older
  than ten minutes, and staging siblings from earlier versions of the
  same target. A linked or shared staging directory is refused.
  Store-internal writers (background commands, shared-host claims,
  the .internal compose override) keep sibling staging.
- doctor's weak-key remedy said `mv .hack.secret.key
  .hack.secret.key.old` (a name git does not ignore) and to re-add
  secrets as argv values. It now keeps a 0600 copy of the old key
  outside the worktree until every secret is re-added, and re-adds
  with --value-stdin or the hidden prompt.

Co-Authored-By: Claude <noreply@anthropic.com>
… read (HACK-2165)

Audit S1 and lead item 1: a machine-local layer that predates private
creation, or was made by hand, kept mode 0644 through writes, and its
staging copy took that mode before the contents were written. A
machine-local write now drops group and other bits from an existing
layer, before the staging copy holds any content, and a write that
changes nothing tightens the file in place. Shared layers keep their
mode. Commands that read env layers (env, up/run paths, session) warn
once per file on stderr about a loose machine-local file, after a
successful read so a refusal stays one line. HACK-1680's keep-mode
test now asserts the tightening.

Co-Authored-By: Claude <noreply@anthropic.com>
…K-2165)

Lead item 3: values staged in $TMPDIR/hack-mux-env-*/env.json stayed
there when the pane never ran its command. A payload now expires after
ten minutes: the pane refuses and removes an expired one, the staging
process removes its payload when the limit passes (if it still runs),
and the next staging sweeps this user's older payloads. Tests stage
in a private directory, never the host's temporary directory.

Co-Authored-By: Claude <noreply@anthropic.com>
Lead items 2 and 5 and the migration path: `hack doctor` reports, for
the project and the global Hack home, secret-bearing files (local
layers, .hack/.env files, project keys, encrypted store and key) that
are loose, linked, owned by another user, tracked, or unignored;
staging copies left by interrupted writes; terminal-session payloads
that never ran; and "store present, key missing, cannot be read".
`hack doctor --fix` tightens modes, adds missing ignore entries and
removes Hack's own leftovers, printing each change; it never deletes a
store, a key or a user's file, and never untracks. A doctor hint no
longer suggests a secret value in argv. Docs: the env guide, the
threat model, and an "after upgrading" step in the v5 upgrade guide.

Co-Authored-By: Claude <noreply@anthropic.com>
…ACK-2165)

Keeps writeTextFileAtomicIfChanged under the complexity limit after
tightenExisting; no behavior change.

Co-Authored-By: Claude <noreply@anthropic.com>
…e layer staging (HACK-2165)

Own-reviewer round on d74187c:
- An existing `.hack-staging/.gitignore` (for example one a repository
  committed, checked out 0700 under umask 077) was trusted unread. It
  is now accepted only as a regular file of the user's holding exactly
  `*`; anything else refuses the write, so no staging copy can be
  visible to git.
- The rotation remedy's `install` into a fixed name overwrote an
  earlier retired key. It now copies to a unique mktemp name and
  removes the key only once the copy is written.
- Machine-local layer writes (writeTextFileAtomicIfChanged with
  tightenExisting) still staged as `.<name>.<uuid>.tmp` siblings, which
  only Hack's managed block ignores. They now stage in the private
  directory too; shared layers keep sibling staging.
- Committed dotenv templates (.env.example, .sample, .template, .dist)
  are no longer reported as secret-bearing.
- Tightening an unchanged layer is best effort (another user's file
  keeps working), and a missing store key is a warning on macOS while
  the keychain may still hold it.

Co-Authored-By: Claude <noreply@anthropic.com>
…oject stores (HACK-2165)

Bot review on d8719bd:
- Concurrent first private writes in one directory could read the new
  `.hack-staging/.gitignore` before its creator wrote `*` and refuse.
  The ignore file is now staged complete and linked into place, so it
  never exists partially and a crash cannot leave an empty one.
- An encrypted store or key configured inside the project checkout
  skipped the git checks. Such files are now checked like the
  project's own secrets (tracked is an error; unignored gets an
  anchored root .gitignore entry); files outside it stay exempt.

Co-Authored-By: Claude <noreply@anthropic.com>
…ene refuses a linked .hack (HACK-2165)

Bot review on 9e060a3:
- On ExFAT/FAT, chmod cannot make the staging directory 0700, so every
  private write there was refused, regressing the documented first
  secret on such a drive. A staging directory of the user's own is now
  made 0700, and accepted at the mount-wide mode when the filesystem
  ignores chmod; a link or another user's directory is still refused,
  and the identity is re-checked before publishing.
- doctor's secrets hygiene followed a `.hack` linked outside the
  project, so --fix could chmod or delete files there. A linked or
  non-directory `.hack` is now reported and not inspected, and every
  fix carries the identity of the directory it changes, checked again
  before the change (an ignore entry is never appended through a
  directory swapped after inspection).

Co-Authored-By: Claude <noreply@anthropic.com>
…ct (HACK-2165)

Bot security review on 9e060a3: a configured store or key under an
in-project directory whose name begins with `..` (for example
`..secrets/`) gave a relative path starting with "..", which was read
as outside the project, so its git checks were skipped. Outside now
means a `..` path segment or an absolute path.

Co-Authored-By: Claude <noreply@anthropic.com>
…out or Hack home (HACK-2165)

Bot security review on 9ff7fb0: a cloned repository's committed
hack.config.json can point encryptedFile.path/keyPath at any file of
the user's, and `hack doctor --fix` would then chmod it or remove old
`.<name>.<uuid>.tmp` files beside it. Paths that only the project's
configuration chose are now fixed, and their leftovers swept, only when
their directory resolves (links followed) inside the checkout or the
Hack home; elsewhere the finding is reported without a fix. The global
configuration's paths are the user's own and keep their fixes.
inspectSecretsHygiene is split into per-part helpers (no behavior
change) to stay under the complexity limit.

Co-Authored-By: Claude <noreply@anthropic.com>
…165)

Bot security review on 553731f: a project-configured store or key
inside the checkout but spelled through an alias (a link to the
checkout, or another case on a case-insensitive disk) gave a relative
path leaving the root, so its git checks were skipped. Containment now
compares the resolved file directory with the resolved root, and git
is asked about the resolved spelling.

Co-Authored-By: Claude <noreply@anthropic.com>
…ectory (HACK-2165)

Own-reviewer round on f00c17c: on a case-insensitive disk a store or
key named `Store.key` in the configuration while git tracks
`store.key` kept the configured case, so git's exact-case tracked
check missed it. A regular file is now resolved itself (realpath of the
file), so git is asked about its stored name; a link at the final
component is still not followed.

Co-Authored-By: Claude <noreply@anthropic.com>
… opens (HACK-2165)

Bot review on 40d6f8e:
- A configured in-project path with gitignore metacharacters (for
  example `secrets[prod]/store.key`) produced an entry git reads as a
  pattern, so the file stayed unignored while --fix reported it
  repaired. Entries now escape `\ * ? [ ]`, a leading `#` or `!` and a
  trailing space, and an ignore fix counts as applied only when git
  then ignores the file.
- A FIFO in place of `.hack-staging/.gitignore` made the read-only
  no-follow open block, hanging every private write there. That open
  (and the two other no-follow opens this PR adds) now uses
  O_NONBLOCK; the regular-file check then refuses it.

Co-Authored-By: Claude <noreply@anthropic.com>
…HACK-2165)

Own-reviewer round on 41b0727: the ignore-file writer trims entries,
which drops an escaped trailing space and would leave a pattern that
never matches. Such a store or key is now reported with an "add it by
hand" note and no fix. The message also names the ignore file by its
absolute path when the project root was reached through a link.

Co-Authored-By: Claude <noreply@anthropic.com>
Bot review on 9861948: under a restrictive umask the staged
`.hack-staging/.gitignore` could be created without owner read, so
the read-back check refused every private write in that directory. Its
mode is now set to 0600 through the open handle before it is written,
as the other private files already are.

Co-Authored-By: Claude <noreply@anthropic.com>
… (HACK-2165)

Bot security review on e0cbce3: a committed configuration could name
an in-project store path containing a newline and `!`, so --fix wrote
a second, negating ignore line that un-ignored a real key (verification
then failed but the line stayed). A name with any control character
now gets no ignore fix, only an "add it by hand" report, so an entry is
always exactly one literal pattern line.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
computer pr review-status reported an overlapping base file.

Co-Authored-By: Claude <noreply@anthropic.com>
…e control characters (HACK-2165)

Bot security review on bc1b493: the read-time loose-layer warning
suggested `chmod 600 .hack/<name>` with the name unquoted, so a
force-added name such as `hack.env.;cmd;.local.yaml` turned the
remedy into command execution when copied. The warning now recommends
only `hack doctor --fix`. Every path doctor's secrets hygiene and the
warning print has control and formatting characters shown as
`\u{..}`, and the one remaining command (`git rm --cached`) shell-
quotes the name, or is omitted when the name holds control
characters. (Also closes the own-reviewer note about terminal
sequences in configured paths.)

Co-Authored-By: Claude <noreply@anthropic.com>
Own-reviewer round on 1fdf767: for a store configured through an
alias of the checkout, the untrack command used the alias spelling
relative to the resolved root (`../alias/...`), which git rejects. It
now uses the resolved path git was asked about.

Co-Authored-By: Claude <noreply@anthropic.com>
…use (HACK-2165)

Bot security review on bcc9648: a repository can configure the
encrypted store and key at in-checkout paths that do not exist yet, and
the hygiene check only looked at existing files, so doctor reported
clean and the first secret write created both files unignored. A
configured store or key path inside the checkout now gets the git
checks even before the file exists (resolved through its nearest
existing ancestor), so `hack doctor --fix` adds the ignore entry ahead
of first use. Protecting the writer itself belongs to the encrypted
store backend work (HACK-2169).

Co-Authored-By: Claude <noreply@anthropic.com>
…it will be created (HACK-2165)

Own-reviewer round on c08593c: fixAllowed resolved the store file's
directory with realpath, which fails for a directory that does not
exist yet, so a project-configured in-checkout store lost its ignore
fix with a false "outside the project" note. It now resolves through
the nearest existing ancestor, like the in-checkout scoping.

Co-Authored-By: Claude <noreply@anthropic.com>
next (021b16b) conflicts in docs/security/env-secrets-threat-model.md:
#760 (HACK-2167) edited the same three rows. Both edits are kept: the
staging and hygiene text from this branch, and #760's "mutation paths"
and gap-18 notes plus its Compose wording. The attacker model for
values at rest (accidental collection by git and other OS users; a
same-user process out of scope) is added to the Scope section, as the
lead asked once #760 merged.

Co-Authored-By: Claude <noreply@anthropic.com>
…HACK-2165)

Own-reviewer round on 6e636a9: the threat model's key-provisioning
row still said the key is staged as a sibling (it is staged in
`.hack-staging/`), and the `.hack/.gitignore` fix step's doc comment sat
above maybeFixSecretsHygiene instead of its own function.

Co-Authored-By: Claude <noreply@anthropic.com>
next edf23ae (the squash of #762, plus #767 and #769) conflicts in
src/lib/fs.ts and src/lib/project-env-config.ts. Both sides are kept:
- writeTextFileAtomicIfChanged has #762's noFollowTarget (destination
  never resolved through a link) and this branch's tightenExisting and
  private staging; machine-local writes pass all of createMode 0600,
  noFollowTarget and tightenExisting, with #762's link recheck before
  the rename. The in-place tighten for an unchanged write honours
  noFollowTarget too.
- #769's live-input guard and #767's value-free listing are untouched
  (auto-merged).
docs/env.md no longer says an existing layer keeps its mode.

Co-Authored-By: Claude <noreply@anthropic.com>
tests/env-backend-command.test.ts parses `env list --json` from a run
that shares one terminal stream for stdout and stderr; its fixture
wrote a 0644 plaintext `.hack/.env.qa`, which env commands now warn
about on stderr. The fixture writes it 0600, as Hack does.

Co-Authored-By: Claude <noreply@anthropic.com>
…ds; fail closed on inspection (HACK-2165)

Second-family review of 66e28c5 (1 blocker, 4 should-fix):
- Blocker: the leftover scan could offer a configured, live store key
  for removal when its name looked like a staging sibling (for example
  `..hack.secret.key.<uuid>.tmp` chosen during recovery). Every
  configured store and key, the project key and the shared key, as
  given and resolved, is now excluded from removal. Writers no longer
  sweep legacy siblings beside a target at all (they cannot know what
  is configured); they sweep only their own staging copies inside
  `.hack-staging/`, and legacy siblings are left to doctor.
- F1 commands: the rotation command checks, when it runs, that
  `~/.hack/retired-keys` is not in a git work tree and stops before
  copying if it is; the symlink repair no longer uses a `.new`
  intermediate (resolve, remove the link, copy in under umask 077).
  Tests run both commands in sandboxes with git controls.
- Ignore repair refuses an existing ignore file it cannot read, instead
  of rewriting it with one entry.
- Inspection errors other than "absent" (an unsearchable directory, an
  unlistable `.hack`) are error findings without fixes, never a clean
  result; a key that cannot be inspected is not reported missing.
- The tmux backend tests stage in a private temporary directory, with a
  control showing an unrelated stale payload outside it is untouched.

Co-Authored-By: Claude <noreply@anthropic.com>
…not a repository"; ignore repair merges its own read (HACK-2165)

Second-family re-review of 9e97246 (1 blocker, 2 should-fix):
- Blocker: the writer's staging sweep matched by name prefix, so a
  write of `.env` could delete a live key kept at
  `.hack-staging/.env.key.<uuid>.tmp`. Writers now remove nothing:
  they cannot tell a leftover from a file configured at a staging-shaped
  path. `hack doctor --fix` removes leftovers, excluding every configured
  store and key.
- The rotation command copied whenever `git rev-parse` failed. It now
  copies only when git (LC_ALL=C) answers "not a git repository";
  inside a work tree, with git missing, or on any other failure it stops
  before copying.
- The ignore repair re-read the file through a reader that turns a
  failure into "absent". It now merges into the bytes it read through
  a no-follow handle and writes with a compare-and-swap against them,
  so a failed read can never replace the user's rules.
Regressions: a live `.env.key.<uuid>.tmp` survives staging for `.env`;
a git that fails otherwise stops the rotation; a failing path read
during the merge leaves the ignore rules intact. All three fail on
9e97246. Docs updated: writes no longer sweep.

Co-Authored-By: Claude <noreply@anthropic.com>
…r never writes through a link (HACK-2165)

The printed rotation command now runs its "is this a checkout" probe with
GIT_DIR, GIT_WORK_TREE, GIT_COMMON_DIR and GIT_CEILING_DIRECTORIES removed
and discovery across file systems on, so a stale GIT_DIR or a ceiling in
the shell can no longer produce the "not a git repository" answer for a
directory inside a home checkout.

Ignore repair publishes with noFollowTarget, so a link put at the admitted
.gitignore after its read (by another user, in a shared directory) is
refused instead of written through.

Regressions: a home checkout with a stale GIT_DIR, a discovery ceiling or a
stray GIT_WORK_TREE in the shell; a link swapped in between admission and
publication. The first two and the swap fail without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ore its checkout probe (HACK-2165)

The probe now unsets the set git itself clears when it enters another
repository (git rev-parse --local-env-vars: GIT_DIR, GIT_OBJECT_DIRECTORY,
GIT_WORK_TREE, GIT_COMMON_DIR, GIT_INDEX_FILE, config parameters and the
rest) plus GIT_CEILING_DIRECTORIES, instead of a hand-picked four. A stale
GIT_OBJECT_DIRECTORY no longer turns a home checkout into "not a git
repository". If git cannot list the variables, the command stops.

Regressions: a stale GIT_OBJECT_DIRECTORY, alone and with a stale GIT_DIR;
both fail with the previous command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
roodboi and others added 9 commits November 13, 2026 16:00
…ictly (HACK-2165)

The scope doctor resolves again before a removal tolerated what it could
not read: discovery and shared-key errors became missing entries, a config
parseError fell back to the default store paths, and a config file that
existed but could not be read was an empty layer. Any of these could make
an unknown configuration look like one naming nothing, and approve the
unlink of a file it now names.

readControlPlaneConfig and resolveFileSecretStorePaths take an opt-in
strict mode (only a missing file is an empty layer; a read or parse
failure rejects), and resolveSecretsHygieneScope({ strict: true }) lets
every discovery, read and parse failure reject. doctor's removal check
uses it; a rejection refuses the removal. The report keeps its tolerant
resolution.

Regressions (tests/secrets-hygiene-scope.test.ts, through the production
resolver): a malformed and an unreadable global configuration reject in
strict mode; an absent one resolves; --fix removes nothing while the
configuration is unreadable, and removes the leftover once it is readable
and unchanged. Three fail without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…git probes read paths literally (HACK-2165)

Project discovery decided whether a present Compose entry supplies a
project with the tolerant pathExists, so a stat failure (EACCES, EIO)
dropped the project instead of raising, against inspectProjectInputsAtRoot's
own rule that only ENOENT means absence. A missing target (a dangling link)
is still absent; any other failure is now a project input access fault, so
a strict hygiene scope rejects and no removal proceeds.

projectEnvLiveInputPaths throws when a .git marker shows a checkout but git
cannot name its shared location, so the live set is unknown rather than
missing the shared and primary-worktree inputs; a project outside git is
unaffected.

The tracked and ignored probes pass a ./-prefixed path (ls-files also with
--literal-pathspecs), so a configured name such as ':(literal)legacy.key'
is never pathspec magic: check-ignore no longer exits 128 for it and
ls-files matches the file itself, not a glob.

The production-scope test now points TMPDIR at its fixture and asserts no
finding lies outside it.

Regressions: an uninspectable Compose target rejects discovery and the
strict scope, while a dangling one stays absent; a checkout whose git cannot
be read removes no leftover; a pathspec-magic name gets ignore fixes and is
reported when tracked. Each fails without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iling closed (HACK-2165)

projectEnvLiveInputPaths checked git first and then let the collector look
the family up again; a later git failure silently dropped the shared key and
the primary worktree's inputs. The collector now takes the family from a
single lookup (liveInputGitFamily): the shared key location, and the
primary worktree derived from the same common directory, as
resolveGitPrimaryWorktreeRoot derives it. With strictGit (the hygiene path)
a checkout whose family git cannot name throws. Legacy cleanup's callers
keep their behaviour.

Regression: with git answering its first two calls and failing every later
one, the set still names the shared key (or the call rejects). It fails
with the previous collector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict in docs/security/env-secrets-threat-model.md gaps 16-19 only:
next's wording for gaps 17 (#766) and 19 (#768, HACK-2171) is kept; gap 18
takes next's #762 text plus this branch's mode tightening, read warning,
ACL/umask limits and markerless-work-tree note; gap 16 keeps the doctor
reference, and the two table rows that pointed at gaps 17/18 say
"narrowed". #768's cleanup receipts merge cleanly with this branch's
strictGit live-input collector (its new caller keeps the non-strict path).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tracked store is a warning (HACK-2165)

A configured store or key outside the project root but inside another git
work tree (a home directory kept in git, say) got no git check, so doctor
reported it clean. Hygiene now finds the containing work tree (the
fail-closed marker walk, then git rev-parse from the nearest existing
directory) and asks git there; an unignored file is reported for the user
to ignore by hand (hygiene never edits another repository), a tracked one
as tracked, and a checkout git cannot name is an error. A path inside a git
directory itself is in no work tree.

A tracked encrypted store is now a warning rather than an error: it holds
ciphertext only, the key's own check stays an error, and projects may
commit the store (next's HACK-1715 cleanup test tracks one; with the
error, doctor --migrate-env-config exited 1 there after the merge).

Regressions: a store and key in another work tree (unignored, ignored by
hand, tracked, unnameable); a store inside a bare git directory; the
'..secrets' test now expects an error for the tracked key and a warning
for the tracked store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd use the nearest work tree (HACK-2165)

- toGitRelativePath rewrites only the platform separator: on POSIX a
  backslash is part of a name, and turning it into "/" asked git about a
  different (possibly ignored) file.
- The nearest-directory walks (resolveExisting, nearestExistingDirectory)
  climb only past a directory confirmed missing; any other realpath
  failure is unknown, so a containing repository whose root cannot be
  resolved is reported, not skipped.
- The printed untrack command is git --literal-pathspecs rm --cached, so a
  name that looks like a pathspec untracks only that file.
- In another work tree an existing regular key is checked under its
  stored case (realpath of the file), as in the project.
- A store or key in a repository nested inside the project is checked
  against that repository (report only); a project inside a larger
  repository keeps its own ignore repair.
- Discovery's Compose target check goes through Bun.file(...).stat() as
  pathExists did, so callers that observe file access (the adoption
  probes) see the same access; only ENOENT/ENOTDIR are absence.

Regressions: a tracked key\prod.key with an ignored slash-spelled decoy;
realpath EIO at the containing repository root; the printed command run
against a ':(glob)*.key' name next to another tracked key; a nested
repository; a monorepo project; a case-folding check that runs on
case-insensitive filesystems. Each new one fails without the change
(the case-folding one needs such a filesystem).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No conflicts: brings #783 (HACK-2179 store-pointer reconcile), #778 and #780.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…CK-2181)

The sweep of stale terminal-session payloads before each staging now
applies the same live-input check as `hack doctor --fix`, through one
shared implementation (src/lib/live-inputs.ts): it never removes a
payload directory that is, or holds, a path current resolution reads,
and removes nothing when that configuration cannot be read.

Regression with real files: a store key configured at a stale
payload's env.json survives the sweep while an ordinary stale payload
is removed; an unreadable configuration removes nothing. Both fail
against the previous sweep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#764 landed with a stricter guard than the branch was cut from (a path
that cannot be resolved for a reason other than absence counts as live,
and retired stores are never removed). Took next's versions of the
files #764 owns and moved that final code into src/lib/live-inputs.ts
unchanged: realpathOrMissing, inRetiredStore, livePaths, isLive, plus
one decision, removalAllowed, that both `hack doctor --fix`
(removalStillSafe) and the automatic payload sweep call before each
removal. For a payload the targets are its env.json and its directory.

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

vercel Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hack-docs Ready Ready Preview Nov 14, 2026 4:47am UTC

Request Review

@linear-code

linear-code Bot commented Nov 14, 2026

Copy link
Copy Markdown

HACK-2181

@roodboi

roodboi commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 14, 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-14T04:48:57.710855Z 6e767f5 Manual request
🔒 Security Review ✅ Completed 2026-11-14T04:52:28.856800Z 6e767f5 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

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: d43116aa8a

ℹ️ 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: d43116aa8a

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.

…HACK-2181)

Review follow-ups: two tests run the sweep with no injected scope from a
project directory (a key named by the project's own configuration is
kept; an unparsable project configuration removes nothing), which fail if
the default stops resolving strictly or from the current directory. The
threat model and the sweep comment now name the exact targets (env.json
and the directory) instead of anything inside the directory.

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

roodboi commented Nov 14, 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: 5b83c7c65a

ℹ️ 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: 5b83c7c65a

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

roodboi commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 6e767f5a51

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

@roodboi

roodboi commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

Second-family review: Claude Opus CLEAN at 6e767f5. Parent verification: 59 focused tests pass, including private tmux with an isolated short socket path; reviewer ran 104 affected tests. Fresh CLI typecheck/check, build, docs/privacy/lint/diff checks pass. The global-configuration regression failed before the fix and now preserves the configured file while removing an ordinary stale payload. No local Rust build or owner runtime changes. Exact-head Codex and Linux CI remain pending; not Ready for lead yet.

@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: 6e767f5a51

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

roodboi commented Nov 14, 2026

Copy link
Copy Markdown
Contributor Author

Ready for lead: 6e767f5

Automatic stale mux-payload cleanup now shares doctor's live-input guard and preserves the global configuration itself, including a configuration stored at a stale payload's env.json. Unknown configuration, live inputs and retired stores prevent removal.

  • Persistent Claude Opus CLEAN and Codex no-findings receipt at this exact head. No open bot threads; review status CLEAR at 6e767f5.
  • CI43558387537 completed successfully at this head: all five selected Linux shards, test fan-in, secret scan and docs site pass. An old cancelled-run matrix-placeholder check remains visible from43558363408; the replacement run and its real shards are green.
  • Local59 focused tests pass; reviewer104 affected tests pass. Fresh CLI typecheck/check, root gates, build, docs/privacy/lint/diff checks pass. The new global-configuration regression failed before the fix and passes after, retaining an ordinary-payload removal control.
  • Current next merged normally; later base moves touch unrelated paths and freshness remains CLEAR.
  • Touched tests/mux-sweep-live-inputs.test.ts is in Linux CI, with no Mac-only cases deferred. No Mac run claimed; lead can run this file for macOS temporary-path/realpath behavior. No full local suite, local Rust builds, real Docker or owner runtime changes.
  • Nonblocking scope limits: only current-project configuration is consulted, and the shared helper assumes callers supply scopes (all production callers do). Existing native-discovery refusal conservatively skips automatic cleanup.

No merge performed. Task scratch cleaned; handing this head to the lead.

@roodboi
roodboi merged commit 56d1d0f into next Nov 14, 2026
22 of 34 checks passed
@roodboi
roodboi deleted the claude/hack-2181-sweep-live-inputs branch November 14, 2026 07:04
roodboi added a commit that referenced this pull request Nov 14, 2026
The next.17 section omitted the tmux breaking-change warning that
already existed at the page tail. Move it into the release section and
put its v4 stop procedure before the v5 trial. The env breaking entry
was already correct; keep its scoped single-key/terminal/stdin migration
guidance.

Audit all **71 commits** from `v5.0.0-next.16` (`b21c3b1898`) through
candidate **`5002cf87bb50686b17ceae8a4c835f524ee1b3a5`** against merged
code and PR text. Add missing upgrade-assistant, activity,
observe/plan/version, interactive exec, recovery, background-command and
host/secret-custody notes. Preserve the complete native env-file
behavior table and mark the four new JSON contracts **shape may change
before 5.0.0**, with the planned HACK-2238 envelope migration.

Correct stale native interactive-exec/network/metadata/Ctrl-C claims and
the short upgrade assistant wording. Credit the publisher-shutdown fix
to #719, already in next.16; keep next.17 lifecycle-command retirement
separate. Retake a private stopped-state backup after v4 stops zellij,
keeping the first copy too. Keep next.16 warnings scoped to that bundle.
Keep original-key backups before older Doctor migrations and distinguish
file rollback from runtime/data recovery.

Only eight Markdown files change. Runtime, tests, workflows, generated
CLI reference, diagrams, immutable snapshots and the site pin are
unchanged. No diagram changed, so a new visual would add nothing. The
site re-pin remains a separate release follow-up.

Merge timing: respect the lead's candidate freeze; intended for the
batch immediately after next.17 publication and the site re-pin. The
moved tmux breaking-change notice is called out for the lead's pre-cut
decision. This PR does not merge or publish anything.

Validation at **`d95cfc554fabc4a0d70e3ba6caeb6746f63a198c`**:
- Bun 1.4.4, frozen dependencies. Docs prepare/check/typecheck/build and
site tests (2 passed, 25 assertions) pass. Production-mode HTTP smoke:
97 docs, 82 SVGs, 217 local links/anchors; task server stopped.
- All 50 Hack commands named anywhere in the notes exist in the current
generated CLI reference; 19 option contracts checked. CLI-reference
regeneration has no diff.
- All 71 commits have one row below, including the test commit and merge
for #786. All 70 source evidence paths exist at the fixed candidate.
Source release-note local links/anchors pass.
- Privacy and complete reachable-history Gitleaks pass (1,330 commits,
no findings). Persistent Claude Opus second-family review is CLEAN at
this exact head. Hosted run 43585059152 passed docs site, secret scan
and every planned Linux unit shard (4–8), plus the required test fan-in.
Typecheck/privacy/quality ran on shard 8. Focus had no selected tests.
Compiler, native core, runtime images/models, process-lifetime and
Docker execution were out of scope; a green Docker fan-in is not Docker
execution evidence. All bot comments were read; CLEAR at d95cfc5,
zero unresolved threads/change requests. Codex code/security reviews
found no issues.
- No real install, migration, daemon/DNS/trust change, Docker or native
VM run was performed for this documentation audit. Native acceptance and
the candidate's hosted release qualification remain separate.

## Candidate commit coverage

`entry present` means the behavior already had an entry within the
next.17 section (some now have fuller detail). `added` means missing
behavior or migration guidance was added there; #824 moves the existing
warning into that section. `not user-visible` means no shipped
CLI/runtime change: documentation, test/CI/repository housekeeping or
the internal desktop preview. Source links pin the candidate, rather
than a moving branch.

| Commit / PR | Coverage | Entry or reason | Audited source |
| --- | --- | --- | --- |
|
[70d328e](70d328e)
[#743](#743) | added | Host
setup: privileged/NSS safeguards |
[src/lib/linux-trust-setup.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/linux-trust-setup.ts)
|
|
[51f15c8](51f15c8)
[#746](#746) | not user-visible |
Docs-only upgrade checklist and site generation; no installed behavior |
[scripts/docs/prepare.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/prepare.ts)
|
|
[c14f3f5](c14f3f5)
[#744](#744) | added | Native
setup JSON accounting |
[packages/runtime-core/src/provider/setup.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/setup.rs)
|
|
[b0c6bcd](b0c6bcd)
[#705](#705) | added | Retained
background exec/run and cursor tools |
[src/commands/background-command-start.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/background-command-start.ts)
|
|
[c89f4fd](c89f4fd)
[#745](#745) | added | Linux
daemon query/home refusals |
[src/commands/daemon-systemd.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/daemon-systemd.ts)
|
|
[cce4b59](cce4b59)
[#752](#752) | not user-visible |
Site pin/snapshots and editorial pages only |
[scripts/docs/versions.json](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/versions.json)
|
|
[56676fc](56676fc)
[#754](#754) | added | Setup
reuse/offline accounting; pin-watch changes are internal |
[packages/runtime-core/src/provider/setup.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/setup.rs)
|
|
[7a496f1](7a496f1)
[#755](#755) | added | MCP
registered selectors and background tool guidance |
[src/mcp/server.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mcp/server.ts)
|
|
[e7a7039](e7a7039)
[#747](#747) | entry present |
Native follow text shape; added session ends/restart recovery |
[src/backends/native-log-follow.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-log-follow.ts)
|
|
[87a6df5](87a6df5)
[#758](#758) | added | Compose
short one-shot startup |
[src/lib/compose-startup-state.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/compose-startup-state.ts)
|
|
[2afb5c4](2afb5c4)
[#761](#761) | added | Native
Hack networks and inert generated labels |
[src/lib/native-hack-compose-conventions.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/native-hack-compose-conventions.ts)
|
|
[342a585](342a585)
[#771](#771) | not user-visible |
Docs-only next.16 trial record |
[docs/versions/v5/guides/upgrade-from-v4.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/versions/v5/guides/upgrade-from-v4.md)
|
|
[6f0acf1](6f0acf1)
[#769](#769) | entry present |
Migration live-key/alias preservation |
[src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts)
|
|
[c96c444](c96c444)
[#756](#756) | added | Child key
filtering, fixed diagnostics, legacy ignore/YAML API refusals |
[src/lib/child-environment.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/child-environment.ts)
|
|
[e2c73c6](e2c73c6)
[#748](#748) | not user-visible |
Contributor CI selection/coalescing, outside product release notes |
[scripts/ci-change-scope.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/ci-change-scope.ts)
|
|
[ebf794e](ebf794e)
[#760](#760) | added |
Agent/output custody warning; runtime unchanged |
[src/agents/instruction-source.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/agents/instruction-source.ts)
|
|
[021b16b](021b16b)
[#763](#763) | added | One-pass
background redaction scan; no public benchmark claim |
[src/lib/background-command/output-scanner.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/background-command/output-scanner.ts)
|
|
[8564ec4](8564ec4)
[#765](#765) | added | Shared
preflight/start admission and detached failure reporting |
[src/backends/native-project-review.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-review.ts)
|
|
[0c0fba2](0c0fba2)
[#767](#767) | entry present |
Breaking env exposure/protect/stdin/scope/API guidance |
[src/commands/env.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/env.ts)
|
|
[9435da9](9435da9)
[#762](#762) | added | Local
Git/link refusals and no-follow dotenv |
[src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts)
|
|
[edf23ae](edf23ae)
[#753](#753) | added | Daemon
stop proves the live Hack home |
[src/commands/daemon-systemd.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/daemon-systemd.ts)
|
|
[573ceec](573ceec)
[#766](#766) | entry present |
Doctor layer/integrity error; added store/key write refusals |
[src/lib/secret-store.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secret-store.ts)
|
|
[a0e9760](a0e9760)
[#757](#757) | added | Orphan
output truncation and final-sync evidence |
[src/lib/background-command/recovery.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/background-command/recovery.ts)
|
|
[10e1958](10e1958)
[#759](#759) | added | Private
lifecycle logs/FIFO and expiring mux payloads |
[src/lib/private-file.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/private-file.ts)
|
|
[bd899ee](bd899ee)
[#775](#775) | not user-visible |
Portable test fixtures only |
[tests/single-file-tar.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/single-file-tar.test.ts)
|
|
[80dae3d](80dae3d)
[#776](#776) | added | Candidate
missing-daemon diagnosis is optional/healthy |
[src/commands/doctor.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/doctor.ts)
|
|
[5b2a2d0](5b2a2d0)
[#772](#772) | added | Bounded
attaching-network retry; strict saved reads remain |
[src/lib/native-compose-ownership.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/native-compose-ownership.ts)
|
|
[ab29d49](ab29d49)
[#777](#777) | not user-visible |
CI scheduling only |
[docs/reference/ci-test-selection.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/reference/ci-test-selection.md)
|
|
[31339c7](31339c7)
[#770](#770) | entry present |
Native inferred readiness, 240 s, HTTP/service_healthy limits |
[packages/runtime-core/src/project/compose/service.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/project/compose/service.rs)
|
|
[156ee7f](156ee7f)
[#773](#773) | entry present |
Loopback proxy port/Doctor/open checks |
[src/lib/proxy-loopback.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/proxy-loopback.ts)
|
|
[a7ec3c7](a7ec3c7)
[#768](#768) | entry present |
Cleanup receipts/partial outcomes and tracked-file wording |
[src/lib/project-env-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-env-config.ts)
|
|
[ceb3e23](ceb3e23)
[#778](#778) | entry present |
Native bridge socket readiness |
[packages/runtime-core/src/provider/bridge.rs](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/packages/runtime-core/src/provider/bridge.rs)
|
|
[af91049](af91049)
[#783](#783) | entry present |
Pointer reconciliation after partial cleanup |
[src/commands/doctor.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/doctor.ts)
|
|
[0a0bfdb](0a0bfdb)
[#780](#780) | not user-visible |
Site-only Linux guide publication; no CLI behavior |
[scripts/docs/versions.json](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/docs/versions.json)
|
|
[d0cf767](d0cf767)
[#786](#786) | not user-visible |
Consent test wording only (both commits) |
[tests/env-migration-tracked-consent.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/env-migration-tracked-consent.test.ts)
|
|
[7e2e630](7e2e630)
[#786](#786) | not user-visible |
Consent test wording only (both commits) |
[tests/env-migration-tracked-consent.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/env-migration-tracked-consent.test.ts)
|
|
[91c311e](91c311e)
[#779](#779) | entry present |
Restore or reversible retire; missing store keys scoped to readers |
[src/lib/secret-store-retire.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secret-store-retire.ts)
|
|
[6ab1ace](6ab1ace)
[#785](#785) | not user-visible |
Docs-only release/upgrade/env notes |
[docs/guides/v5-release-notes.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/v5-release-notes.md)
|
|
[25bd63c](25bd63c)
[#764](#764) | entry present |
Doctor hygiene, local modes, ignored staging and live-input protection |
[src/lib/secrets-hygiene.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/secrets-hygiene.ts)
|
|
[d9df57c](d9df57c)
[#784](#784) | not user-visible |
Resolver/proxy and consent test corrections only |
[tests/project-open-loopback.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/project-open-loopback.test.ts)
|
|
[2c1f665](2c1f665)
[#791](#791) | added | Detached
failure names, open DNS hint, init placeholder; prune guidance |
[src/commands/project.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/project.ts)
|
|
[f6fe55f](f6fe55f)
[#787](#787) | not user-visible |
Docs-only retirement/hygiene follow-up |
[docs/guides/v5-release-notes.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/v5-release-notes.md)
|
|
[7f9548c](7f9548c)
[#792](#792) | not user-visible |
Start-here docs, navigation and contributor rule only |
[docs/versions/v5/install.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/versions/v5/install.md)
|
|
[a0cfc73](a0cfc73)
[#793](#793) | added | Verified
updater publication, backups and reversible candidate removal |
[src/lib/self-update.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/self-update.ts)
|
|
[292d312](292d312)
[#782](#782) | added | Lock-free
native ps and proved failed-start down |
[src/backends/native-project-observe.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-observe.ts)
|
|
[b1e123b](b1e123b)
[#796](#796) | added | Doctor
reader count/worktree grouping in store recovery |
[src/lib/doctor-secret-integrity.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/doctor-secret-integrity.ts)
|
|
[286d00f](286d00f)
[#789](#789) | added | Foreground
command-before-wrapper retirement |
[src/lib/project-lifecycle-processes.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-lifecycle-processes.ts)
|
|
[bb6a7d1](bb6a7d1)
[#788](#788) | not user-visible |
Linux qualification runbook only |
[docs/guides/linux-host-qualification.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/docs/guides/linux-host-qualification.md)
|
|
[a262d42](a262d42)
[#800](#800) | not user-visible |
Internal desktop design; outside supported CLI release scope |
[apps/desktop/DESIGN.md](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/apps/desktop/DESIGN.md)
|
|
[6b161ba](6b161ba)
[#774](#774) | added | Native
interactive exec, finite fallback and receipt recovery |
[src/backends/native-project-exec.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-project-exec.ts)
|
|
[1249272](1249272)
[#799](#799) | not user-visible |
Portable output-contract CI selection only |
[scripts/test-shard-plan.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/test-shard-plan.ts)
|
|
[fa3f03d](fa3f03d)
[#790](#790) | added | Read-only
upgrade check, snapshot and rollback |
[src/commands/upgrade.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/upgrade.ts)
|
|
[c3b79bc](c3b79bc)
[#807](#807) | added |
Observe-only global status and unknown evidence |
[src/commands/global-status-observe.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/global-status-observe.ts)
|
|
[29be043](29be043)
[#812](#812) | added | Read-only
local CA trust diagnosis |
[src/lib/ca-trust-status.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/ca-trust-status.ts)
|
|
[f0102fd](f0102fd)
[#814](#814) | not user-visible |
Prepared-base verifier test fixture only |
[tests/qualify-provider-pin.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/qualify-provider-pin.test.ts)
|
|
[b4ebfec](b4ebfec)
[#815](#815) | added | Compact
upgrade plan, snapshot-backed apply/resume |
[src/lib/upgrade-apply.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-apply.ts)
|
|
[c44b266](c44b266)
[#801](#801) | not user-visible |
Internal optional desktop preview; not shipped CLI behavior |
[apps/desktop/Cargo.toml](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/apps/desktop/Cargo.toml)
|
|
[56d1d0f](56d1d0f)
[#804](#804) | added | Automatic
mux sweep preserves live/retired config inputs |
[src/lib/live-inputs.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/live-inputs.ts)
|
|
[1958363](1958363)
[#805](#805) | added | MCP
timedOut result and Codex installer timeout |
[src/mcp/server.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mcp/server.ts)
|
|
[e6207e8](e6207e8)
[#810](#810) | added | Lifecycle
activity writes including handler refusals; activity JSON |
[src/commands/lifecycle-activity.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/lifecycle-activity.ts)
|
|
[23fe08f](23fe08f)
[#825](#825) | added | Read-only
batch review and permission-only key repair |
[src/lib/upgrade-review.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-review.ts)
|
|
[cab596c](cab596c)
[#781](#781) | entry present |
Full native env-file behavior table; added support/precedence summary |
[src/backends/native-compose-environment.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/backends/native-compose-environment.ts)
|
|
[1e84684](1e84684)
[#798](#798) | not user-visible |
Rust test process isolation/nextest; internal qualification only |
[scripts/test-runtime-core.sh](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/scripts/test-runtime-core.sh)
|
|
[518af29](518af29)
[#817](#817) | not user-visible |
Remove accidental empty checkout files; no installed CLI change |
[.gitignore](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/.gitignore)
|
|
[07192f7](07192f7)
[#824](#824) | added | BREAKING
warning moved from page tail into next.17; v4 stop procedure retained |
[src/mux/mux-config.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/mux/mux-config.ts)
|
|
[fe09a5b](fe09a5b)
[#816](#816) | added | Read-only
install/trust admin plans and exits |
[src/commands/global.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/global.ts)
|
|
[8977676](8977676)
[#827](#827) | added |
Registry-preserving project observe, runtime opt-in |
[src/commands/projects.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/commands/projects.ts)
|
|
[5965b23](5965b23)
[#828](#828) | added | Running
CLI version identity JSON |
[src/lib/version-report.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/version-report.ts)
|
|
[2922210](2922210)
[#830](#830) | added | Upgrade
safe/admin/manual action kinds |
[src/lib/upgrade-action-kind.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/upgrade-action-kind.ts)
|
|
[51b55c0](51b55c0)
[#820](#820) | not user-visible |
Archive/plan/shared-helper verification fixtures only |
[tests/python-free-download.test.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/tests/python-free-download.test.ts)
|
|
[5002cf8](5002cf8)
[#809](#809) | added | Retirement
read retry, second Ctrl-C and native cancellation cleanup |
[src/lib/project-lifecycle-processes.ts](https://github.com/hack-dance/hack/blob/5002cf87bb50686b17ceae8a4c835f524ee1b3a5/src/lib/project-lifecycle-processes.ts)
|

---------

Co-authored-by: Kit <344842+roodboi@users.noreply.github.com>
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