beehive: preserve missing-setup receipts and atomic helper test readiness

Signed-off-by: Logan Johnson <loganj@squareup.com>
This commit is contained in:
Logan Johnson
2026-09-10 13:39:06 -04:00
parent 1bf0d11749
commit 2f3d4755ef
3 changed files with 33 additions and 2 deletions

View File

@@ -63,9 +63,34 @@ wrong identity, standby addition, retained deletion refusing recovery/recreation
and byte-identical sibling journal. These are isolated fixtures, no OS operations.
Independent async semantic review and actual owner-present OS verification remain.
No new v3 local provisioning CLI process journey is claimed yet (API tests only).
Workspace `cli-journey.ts` additionally exercises actual v3 CLI processes with the
existing explicit isolated-file credential loader: first-provision reconciliation,
new agent, hidden standby import, removal, refusal to recover an active manifest,
and hidden same-key import. Three public slots and unchanged original journal.
Its initial harness omitted import confirmation (`cli-first.log`); the corrected
harness passes (`cli-second.log`) without changing production to conceal failure.
Existing installed owner-TUI private-wire reply journey remains separate evidence.
Direct ordinary membership is approved; source contract is now available in
`WORK_LOGS/BEEHIVE_DESIGN_183FFAF0/DIRECT_MEMBER_EVIDENCE_AA0B3F26.md`; runtime
implementation remains. Private profile distribution, reconnect and new-wire Move
also remain. This is not the completed usable milestone or an install candidate.
## Failed full gate and targeted repair (do not erase this result)
One default-concurrent installed-enabled full suite at exact
`1bf0d11749909c1fc1b0a15e58d212bd8fb05fa7` exited naturally after 321723.795417ms:
**137 passed / 4 failed / 0 skipped**, strict passed. Assignment/Restart expected
the existing missing-key/setup receipt, but the new async path leaked raw ENOENT;
Move recovery waits on that same receipt. Repair restores only filesystem-missing
classification, preserving distinct credential unavailable/timeout/cancel errors.
The new helper-host test failed its PID-absence assertion. Its readiness file was
published before PID bytes were written, allowing cancellation to observe an empty
file as PID 0. Repair publishes the fixture PID atomically and explicitly rejects
invalid/PID-0 observations. The old failure did not capture the PID, so its exact
runtime cause is not retrospectively proven. Both the failed full log and the
original test remain available in commit history.
After these changes strict and the focused assignment/Move/Restart/helper set pass
12/12, default concurrency. No deadline increase, serialized suite, forced exit,
or second full rerun-to-green. **The repaired source has not passed a full suite.**
The full run did pass the installed owner-public v3 TUI signed-reply journey.

View File

@@ -226,6 +226,11 @@ function slot(setup: Setup, path: string, agent: string, currentSetup: (id: stri
controller.signal.throwIfAborted();
if (closing || retracting(revision) || state.revision !== revision || hash(state.assignment) !== assignment || hash(state.selected) !== selectionBefore) throw Error('Credential admission invalidated');
if (semanticHash(fresh) !== semanticHash(setup)) throw Error('Local agent key/setup missing or changed; repair locally without resetting assignment');
} catch (error) {
// Keep the existing missing-setup receipt contract without hiding a native
// unavailable/denied/timeout result as an absent key. Never relay FS paths.
if (['ENOENT', 'ENOTDIR'].includes(String((error as NodeJS.ErrnoException)?.code))) throw Error('Local agent key/setup missing or changed; repair locally without resetting assignment');
throw error;
} finally { if (credentialRead === controller) credentialRead = undefined; }
accessSync(setup.runner, constants.X_OK);
if (realpathSync(selected.workspace) !== selected.workspace || !statSync(selected.workspace).isDirectory()) throw Error('Workspace changed');

View File

@@ -21,11 +21,12 @@ function blocker(directory: string) {
const pidFile = join(directory, 'helper.pid'), script = join(directory, 'helper.mjs');
// PID-only fixture evidence, never credential material. Blocking JS cannot run
// an abort callback, approximating a native call's event-loop unresponsiveness.
writeFileSync(script, `import {writeFileSync} from 'node:fs';\nwriteFileSync(${JSON.stringify(pidFile)},String(process.pid));\nAtomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0);\n`);
writeFileSync(script, `import {writeFileSync,renameSync} from 'node:fs';\nwriteFileSync(${JSON.stringify(pidFile + '.pending')},String(process.pid));\nrenameSync(${JSON.stringify(pidFile + '.pending')},${JSON.stringify(pidFile)});\nAtomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0);\n`);
return { pidFile, helper: pathToFileURL(script) };
}
function gone(pidFile: string) {
const pid = Number(readFileSync(pidFile, 'utf8'));
assert.ok(Number.isSafeInteger(pid) && pid > 1, 'Atomic fixture readiness must contain the owned PID, not an empty file/process group');
assert.throws(() => process.kill(pid, 0), (e: NodeJS.ErrnoException) => e.code === 'ESRCH');
}