Skip to content

train b59 integration gate (do not merge) - #498

Closed
roodboi wants to merge 15 commits into
nextfrom
train/b59
Closed

roodboi wants to merge 15 commits into
nextfrom
train/b59

Conversation

@roodboi

@roodboi roodboi commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Integration gate for merge batch b59: origin/next + #420 (HACK-1362) + #468 (HACK-1377) + #437 (HACK-1369) + #494 (HACK-1440). Tree 9154ec0f. Closed after the batch squashes.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

roodboi and others added 15 commits October 22, 2026 09:02
…m tracked-local fixture

The hosted macos-latest Config compiler job failed "tracked local filename
compatibility..." at bun's 5s default test timeout. Bun then killed the
in-flight Git inspection and afterEach removed the fixture, so the still
running metadata call surfaced a generic closed refusal with no cause.

- resolveProjectEnvMetadataForNativeSelection keeps the closed, value-free
  message but records a non-enumerable diagnosticCause: the underlying
  error's class name and identifier-shaped code only (for example
  HackCliError:E_CONFIG_INVALID), exported via nativeEnvMetadataDiagnostic.
- Test helpers print that diagnostic when a success path is refused, and
  refuses() asserts each metadata refusal's diagnostic is value-free and
  non-enumerable, pinning it for Git-linkage and selected-input refusals.
- The tracked-local test needs only index state at an exact Git root, so it
  uses a plain repository instead of a commit plus linked worktree. Fixture
  commits disable auto maintenance (no detached background git process)
  and fixture Git ignores global/system configuration.

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

Native storage helper probes kept fixed 15 s (reads, target observation,
helper create/start) and 10 s (cleanup) caps although each carrier has a
90 s HACK_NATIVE_STORAGE_TIMEOUT_MS budget. On loaded hosted runners a slow
`docker start -ai` of the helper refused at 15 s as storage-helper-start
probe-timeout and failed `hack exec`/`up`.

Each probe and command now takes its timeout from
nativeComposeStorageProbeTimeoutMs: daemon commands get the remaining carrier
budget, reads the remaining budget up to the probe's 60 s ceiling, and
cleanup keeps its own 10-60 s bound that is never clipped to the deadline.
A timeout before the deadline still reports probe-timeout; one at the
deadline reports storage-budget.

Document the fail-closed saved exec contract: a closing storage proof
refusal fails exec after its command ran.

Refs HACK-1369

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… helper start

The probe-budget test drove only the unrecorded root proof, so a 15 s cap on
the recorded original-command child (the path exec and up storage proofs take)
survived. Add a case that builds the carrier with originalCommandRecords and
sends a readonly verify request with a 20 s virtual helper start, asserts every
helper command was published and settled as an original command, and apply the
helper's daemon-side state change when its child exits so recorded admission
re-checks see the created helper. Document that recorded commands share the
remaining-budget bound.

Refs HACK-1369

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native env metadata file still flaked at bun's 5 s test budget on loaded
runners. Per-test fixture writes were the cost: git init, add, commit and
worktree add each create many files, and under I/O contention one fixture
step could take over a second (one test timed out inside its first git init), while the
product's read-only inspections stayed at tens of milliseconds.

- Build the plain and linked Git fixtures once per file in beforeAll and copy
  them into each test root with fs.cp. The copy rewrites the two linkage
  files, the only absolute paths Git keeps. Templates skip hook samples.
- Reuse one qa result in the six-layer test instead of resolving twice, and
  split the host exclusion loop into one test per exclusion.
- The cancellation test waits until the fake Git marker exists or the call
  settles, instead of a fixed 100 x 5 ms poll budget; it needs only a plain
  repository.

No test timeout was widened, no retries were added and no assertion was
removed or weakened.

Refs HACK-1362

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…out hard links

On a filesystem without hard links (ExFAT, FAT) every env write failed
with a raw ENOTSUP from the lock receipt's and the first project key's
link(2) publish, so the key could never be created there. The exclusive
publish now falls back to an O_CREAT|O_EXCL|O_NOFOLLOW empty reservation
that the complete, fsynced sibling is renamed over, keeping the
no-overwrite and no-follow guarantees.

The other refusals that were still raw on next are now one value-free
line with an E_* code and no stack:

- hydrate with a symlinked (dangling or live) or non-directory
  .hack/.internal is E_PATH_CONFLICT; nothing is created through it
- an --env overlay name over 128 characters is refused up front as
  E_USAGE, and ENAMETOOLONG is classified as E_PATH_CONFLICT
- a project env key lock that stays held is E_LOCKED, naming the lock
  (and its recovery guard when that is held) and the remedy
- a .hack/.gitignore directory is E_PATH_CONFLICT, as docs/env.md said

Adds mutation-proven tests for these and for the previously untested
lock-unavailable codes, atomic-write refusal codes and the staging
EISDIR mapping.

Refs HACK-1377

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rnal completion

The recorded exec/up case called finish() with a synthetic completion. The
finalizer consumes the completion before its try/finally, so the refusal left
the held invocation directories open; hosted CI's full run then garbage
collected them and failed the file with ERR_INVALID_STATE. Journal the intent
like the witness owner does, complete it, and let finish() retire the
invocation files. Collect garbage after each test so any future leak is
reported against this file.

Refs HACK-1369

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One `up` with one directory-xattr storage witness ran ~3.1k held-directory
rechecks (~19k lstat, ~13k realpath, ~4.5k open). Two reductions keep every
check and refusal path:

- recheckDirectories runs realpath only for a held directory with no other
  held directory beneath it in the same batch. realpath(child) === child
  proves every prefix canonical at that instant; each directory keeps its own
  lstat identity, owner and mode checks.
- A material-authority assertion already opens and closes with a full store
  check (lease.assertHeld), so its generation load no longer adds two more.
  The generation directory hold/recheck and manifest/document identity checks
  still run.

Second `up` of the xattr same-birth case: lstat 18,834 -> 13,452, realpath
12,821 -> 3,685, open 4,542 -> 3,944; median system CPU 2.9 s -> 1.9 s.

Refs HACK-1440

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roodboi roodboi closed this Oct 24, 2026
@roodboi
roodboi deleted the train/b59 branch October 24, 2026 21:07
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