From 2f3d4755ef8a75f25630ef503060ce25fa033026 Mon Sep 17 00:00:00 2001 From: Logan Johnson Date: Thu, 10 Sep 2026 13:39:06 -0400 Subject: [PATCH] beehive: preserve missing-setup receipts and atomic helper test readiness Signed-off-by: Logan Johnson --- beehive/CREDENTIAL_ASYNC_707E.md | 27 +++++++++++++++++++++++++- beehive/src/host.ts | 5 +++++ beehive/test/credential-helper.test.ts | 3 ++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/beehive/CREDENTIAL_ASYNC_707E.md b/beehive/CREDENTIAL_ASYNC_707E.md index 61f041f120..e2f74c978e 100644 --- a/beehive/CREDENTIAL_ASYNC_707E.md +++ b/beehive/CREDENTIAL_ASYNC_707E.md @@ -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. diff --git a/beehive/src/host.ts b/beehive/src/host.ts index a3f9f914aa..32e4330609 100644 --- a/beehive/src/host.ts +++ b/beehive/src/host.ts @@ -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'); diff --git a/beehive/test/credential-helper.test.ts b/beehive/test/credential-helper.test.ts index 2a309a8146..3814f4a711 100644 --- a/beehive/test/credential-helper.test.ts +++ b/beehive/test/credential-helper.test.ts @@ -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'); }