Skip to content

test: fabricate HOME in the prelaunch-interrupt lease case - #5

Merged
elkaix merged 1 commit into
mainfrom
fix/t48-hermetic-home
Aug 12, 2026
Merged

test: fabricate HOME in the prelaunch-interrupt lease case#5
elkaix merged 1 commit into
mainfrom
fix/t48-hermetic-home

Conversation

@elkaix

@elkaix elkaix commented Aug 12, 2026

Copy link
Copy Markdown
Member

Fixes the CI failure on main (run 31548589527): tests/lease.sh case
t48_prelaunch_interrupt_releases_without_poison, which also took
tests/shared-git-dir.sh down with it because that suite re-runs the lease suite.
One root cause, two red suites.

Root cause

t48 launches the real implementer-loop.sh to prove review finding 4's guarantee —
an interrupt arriving before any companion job exists releases the lease instead of
poisoning it. It did that without fabricating HOME, so what the loop found on
disk depended on the host:

  • Developer machine — the Codex companion is installed, write_lock_workspace_writers
    returns an empty list, write_lock_release removes the lock, the case passes.
  • CI runner — no companion exists, that enumeration returns rc 4, and
    write_lock_release correctly refuses to release a lease whose writer liveness it
    cannot determine, printing a message containing lease retained. The case greps the
    whole output for that substring and fails.

Reproduced deterministically by running the case under an empty HOME:

MAESTRO_LOCK: job liveness could not be determined; write lease retained (job=unknown ...)
MAESTRO_FINAL: LOOP INTERRUPTED rc=4

The interrupt path was never wrong — the case's rc=4 and MAESTRO_FINAL: LOOP INTERRUPTED rc=4 assertions passed even on CI. The conservative retention in
write_lock_release is also correct and deliberate: liveness unknown must never
release a lease. No product code is changed by this PR.

Fix

Give the case the fabricated HOME the rest of the suite already uses (the
run_clear_lease pattern): a fake companion symlinked at the canonical plugin path, a
node forwarder built from REAL_NODE so the nvm shim is never invoked under an
overridden HOME, and an empty status document. The existing git shim stays first on
PATH, so the digest window the case opens is unaffected. All four assertions are
unchanged.

Verification

bash tests/lease.sh passes on a developer host with the bug present, so every check
was run under a fabricated empty HOME as well — otherwise the verification cannot fail.

Environment Before After
Empty HOME (emulates CI) 53 passed, 1 failed 54 passed, 0 failed
Developer HOME 54 passed, 0 failed 54 passed, 0 failed

shared-git-dir.sh also green under empty HOME. Scope: tests/lease.sh only.

Separately worth noting: liveness.sh, which had kept main red since c2f2ea9 on
Aug 2, passes on CI as of b3adebc — the write-path refactor fixed it.

t48 launches the real implementer-loop to prove that an interrupt arriving
before any companion job exists releases the lease instead of poisoning it.
It did so without fabricating HOME, so what the loop found on disk depended
on the host.

On a developer machine the Codex companion is installed, workspace-writer
enumeration returns an empty list, and the lease releases cleanly. On the
CI runner no companion exists, that enumeration reports liveness unknown,
and write_lock_release correctly refuses to release a lease it cannot prove
quiescent — printing a message containing "lease retained", which the case
greps for. The case failed on CI and passed everywhere it was authored.

Give it the same fabricated HOME the rest of the suite uses: a fake
companion at the canonical plugin path, a node forwarder built from
REAL_NODE so the nvm shim is never invoked under the overridden HOME, and
an empty status document. The git shim stays first on PATH so the digest
window it opens is unaffected. All four assertions are unchanged.

The interrupt path and the conservative retention in write_lock_release are
both correct and untouched; only the test's environment was uncontrolled.

Verified in both environments: 54 passed, 0 failed under an empty HOME
(53/1 before this change) and under the developer HOME.
@elkaix
elkaix merged commit 37b53fd into main Aug 12, 2026
1 check passed
@elkaix
elkaix deleted the fix/t48-hermetic-home branch August 12, 2026 00:57
elkaix added a commit that referenced this pull request Aug 12, 2026
… suite (#6)

CI failed on 37b53fd with two suites red, neither a product defect. The same
content had passed as PR #5's check minutes earlier.

t14_midpoint_warning_continues_same_job asked for a job to complete inside a
window of (ceiling/2, ceiling) and then spent seven serialized poll cycles
crossing it, each spawning a node process, against an 8-second ceiling. Every
unit of runner slowness ate the margin until the loop cancelled at its deadline
— behaving exactly as designed — and the case read that as failure. It had
already failed this way on c2f2ea9 nine days earlier.

Drive completion from the event instead of from the clock. The fixture's
MAESTRO_TEST_JOB_TERMINAL_FLAG, which tests/job-lock.sh already uses, reports
the job as running until a named file exists. The case now waits for the halfway
warning, then creates that file, so completion is causally after the warning and
one poll cycle away rather than seven. The ceiling lives in a single variable the
assertion pattern derives from, so the two can no longer drift apart. All four
assertions are unchanged.

tests/shared-git-dir.sh re-ran the entire lease suite that tests/run.sh had
already run and passed in the same job, piping it through `tail -1` so a failure
inside it could not be diagnosed at all. It added no coverage, cost ~55s, and
doubled the chance that any timing-sensitive lease case failed the build. Its
other checks stay; the re-run goes. 42.87s to 2.07s.

The remaining changes widen nine event waits from 5s to 30s across liveness,
lease, and provenance-edge. These are preventive, not fixes for anything
observed: each loop breaks as soon as its event arrives, so a larger bound costs
nothing when the host is healthy and removes a false negative when it is not. A
genuinely absent event still fails, only later.

t19 is deliberately unchanged. It fails in the Codex sandbox because ps reports
no process start identity there, so the contender fails closed instead of
waiting; it passes on the GitHub runner and on developer hosts.

Verified with the full suite under a fabricated empty HOME and /bin/bash 3.2,
which is what the runner actually provides: 18 passed, 0 failed.
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