@junghanacs/entwurf 0.41.0 → 0.41.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/BASELINE.md +7 -5
- package/CHANGELOG.md +426 -0
- package/DELIVERY.md +37 -20
- package/README.md +83 -81
- package/VERIFY.md +10 -10
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +1 -1
- package/docs/setup-clean-host.md +95 -29
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +14 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +10 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +23 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +3 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +21 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +4 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +5 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +6 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +13 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-receive.js +25 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-send.js +94 -28
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +57 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +2 -2
- package/mcp/entwurf-bridge/dist/scripts/remote-pair-receive.js +12 -12
- package/mcp/entwurf-bridge/src/index.ts +14 -11
- package/native/win32-x64/entwurf_win.node +0 -0
- package/native/win32-x64/manifest.json +2 -2
- package/package.json +15 -14
- package/pi/pi-durable/carrier/tui.js +18 -3
- package/pi/pi-durable/overlay/upstream-pin.json +12 -12
- package/pi-extensions/lib/acp/backend-adapter.ts +5 -3
- package/pi-extensions/lib/acp/backend.ts +12 -9
- package/pi-extensions/lib/entwurf-self-address.ts +13 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +25 -2
- package/pi-extensions/lib/entwurf-v2-decider.ts +7 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +3 -0
- package/pi-extensions/lib/fresh-call-composition.ts +21 -10
- package/pi-extensions/lib/herdr-fresh-call.ts +4 -2
- package/pi-extensions/lib/meta-sender-identity.ts +4 -0
- package/pi-extensions/lib/mux-fresh-call.ts +6 -4
- package/pi-extensions/lib/native-push/register.ts +17 -2
- package/pi-extensions/lib/omp-fresh-preflight.ts +2 -2
- package/pi-extensions/lib/pi-durable-fresh-preflight.ts +1 -1
- package/pi-extensions/lib/remote-pair-receive.ts +27 -19
- package/pi-extensions/lib/remote-pair-send.ts +117 -30
- package/pi-extensions/meta-bridge-omp.ts +69 -7
- package/pi-extensions/meta-bridge-pi-durable.ts +3 -3
- package/run.sh +218 -49
- package/scripts/check-agy-sender-identity.ts +6 -4
- package/scripts/check-entwurf-self-address.ts +34 -3
- package/scripts/check-entwurf-v2-contract.ts +24 -2
- package/scripts/check-entwurf-v2-production.ts +45 -31
- package/scripts/check-gate-qualification.ts +11 -9
- package/scripts/check-native-push-adapter.ts +4 -0
- package/scripts/check-native-push-register.ts +32 -82
- package/scripts/check-remote-pair-installed.ts +2 -2
- package/scripts/dev-bin.sh +112 -1
- package/scripts/lib/chain-terminus-publication.ts +58 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +33 -2
- package/scripts/lib/codex-fresh-source-receipts.ts +112 -3
- package/scripts/lib/pi-durable-fresh-live-receipts.ts +29 -1
- package/scripts/mutants/chain-terminus-publication.json +17 -0
- package/scripts/mutants/codex-native.json +98 -0
- package/scripts/mutants/control-send-receipt.json +3 -3
- package/scripts/mutants/mux-fresh-call.json +16 -1
- package/scripts/mutants/native-push-paused.json +17 -0
- package/scripts/mutants/omp-fresh.json +13 -2
- package/scripts/mutants/pack-install.json +50 -4
- package/scripts/mutants/pi-durable.json +60 -0
- package/scripts/mutants/pi-floor.json +5 -5
- package/scripts/mutants/remote-pair-display.json +3 -3
- package/scripts/mutants/remote-pair-receive.json +41 -11
- package/scripts/mutants/remote-pair-roundtrip.json +67 -7
- package/scripts/mutants/remote-pair-send.json +156 -17
- package/scripts/mutants/remote-pair-transport.json +4 -4
- package/scripts/mutants/source-install.json +66 -0
- package/scripts/remote-pair-receive.ts +12 -12
- package/scripts/smoke-agy-install-state.sh +121 -0
- package/scripts/smoke-agy-native-push-live.ts +13 -0
- package/scripts/smoke-codex-fresh-live.ts +52 -28
- package/scripts/smoke-entwurf-chain-live.ts +7 -9
- package/scripts/smoke-herdr-fresh-call-live.ts +4 -4
- package/scripts/smoke-herdr-plugin-build-live.ts +179 -50
- package/scripts/smoke-herdr-raw-install-live.sh +10 -3
- package/scripts/smoke-mux-lifecycle-live.ts +140 -8
- package/scripts/smoke-omp-fresh-live.ts +5 -4
- package/scripts/smoke-pi-durable-fresh-live.ts +29 -7
- package/scripts/smoke-setup-verdict.sh +27 -2
package/run.sh
CHANGED
|
@@ -184,6 +184,7 @@ Usage:
|
|
|
184
184
|
./run.sh check-pi-durable-beside # #129 mutant execution coordinate (VERIFY rule 3): run_vitest over four pi-durable beside tests (adapter, carrier/SDK-set verifier, preflight, owner join) — a pi-durable qualification lane gate argv. Same files check-tests-beside-behavior already runs.
|
|
185
185
|
./run.sh check-pi-durable-carrier # #144 mutant execution coordinate (VERIFY rule 3): run_vitest over the carrier test alone (relocation/resolver, owned-source emission and typecheck fence, package file list, task footer, the real bootstrap on the 1.2 SDK, stream transport, skills prompt) — the gate argv of the carrier claims, whose QKs live only in that file. Same file check-tests-beside-behavior already runs.
|
|
186
186
|
./run.sh check-pi-durable-native-module # #144 mutant execution coordinate (VERIFY rule 3): run_vitest over the bootstrap's native-module file and directory ingress test alone — the gate argv of the ingress claims, whose QKs live only in that file. Same file check-tests-beside-behavior already runs.
|
|
187
|
+
./run.sh check-remote-pair-beside # #149 mutant execution coordinate (VERIFY rule 3): run_vitest over the five remote-pair beside tests (send, receive, roundtrip, transport, mailbox body) — the gate argv of the remote-pair claims. Same files check-tests-beside-behavior already runs.
|
|
187
188
|
./run.sh check-pi-durable-receive # #129 L-receive FIRST CELL, CHECKOUT-ONLY. Same input (the bundle must carry the pi-durable-host owner join). The host driver gives the app NO input; a seeded claude-code sender (marker owned by a separate idle child, handed to a gate-owned sending bridge through ENTWURF_META_SENDER_MARKER) enqueues one message, the host's doorbell admits its notice to the ROOT conversation, and the scripted model drains it with entwurf_inbox_read. S withholds response #1 until the ENQUEUE receipt, the .delivered bytes, the signal, the host-owned receiver marker and the notice are captured. Oracles: receiver() admission, native view, raw archive (.delivered.read + lastReadAt), wire (exactly two requests, drain result = view), and after a green reap a forensic read-only SQLite copy (submission row by request id = reported id, root, input, done, placed entry = the notice). V NOT run. Missing inputs → SKIP (97)
|
|
188
189
|
./run.sh check-copilot-receive-arm # #82 RAIL 5 gate: the REAL receiver installer + the REAL extension.mjs forked with a stubbed SDK. Arms only after birth, marker owned by the WATCHER pid, self-fetch dispatch answer, doorbell carries the garden id and NOT the body, id-drift/foreign-parent refusals. Hermetic; no Copilot, no model turn
|
|
189
190
|
./run.sh check-copilot-launch # #82 RAIL 7 gate: the MANAGED launch `entwurf copilot`, driven through its public address against a FAKE VENDOR on a sandbox PATH. Receiver precondition refusals, EXTENSIONS token + operator token preservation, injected defaults before the `--` terminator, byte-identical argv, the 11 explicit permission/surface policy overrides that suppress `--yolo`, exec (not fork) pid identity, exit passthrough, recursion refusal. Hermetic; no Copilot, no model turn
|
|
@@ -221,10 +222,10 @@ Usage:
|
|
|
221
222
|
./run.sh check-typing-call-fence # deterministic gate for the boundary nobody has broken: this product composes ARGUMENTS and LETTERS, never keystrokes. Scans every tracked production source under pi-extensions/ and mcp/ — comments blanked, string literals kept — for tmux send-keys/paste-buffer/load-buffer and herdr's PTY verbs (agent.prompt, agent.send_keys, pane.send_text, pane.input.set). Prose is exempt on purpose: the sentence stating the rule names the very calls it forbids, and a scanner that read prose could be made green by deleting the law. Carries its own oracle — the detector is proven on planted code, proven blind to comments, and the scanned inventory is measured
|
|
222
223
|
./run.sh check-resume-launch-identity # deterministic gate for resume-launch-identity.ts, the record-authoritative launch-identity leaf preserved through the visible-first cut (spawn-bg and all its callers are gone; this leaf answers "which being is this, and which conversation is theirs"). Temp meta-store fixture: gardenId→record.transcriptPath happy path with header cwd/provider/model; C3 integrity (header id ≠ record.nativeSessionId → refused, never resumed); #52 ADDRESSABLE read (a gid that no longer holds its nativeSessionId alone is refused from EITHER side — the plain targeted read would resume one transcript twice under two locks); cause fidelity per impossible resume incl. the F7 pin (recorded-but-deleted transcript → MISSING, not "no recorded model"); header↔gate SSOT. No spawn/socket/timer
|
|
223
224
|
./run.sh smoke-entwurf-v2-matrix-live # LIVE sentinel (0.11 Stage 0 step 5d-5, D4-b) — OUT of pnpm check, needs LIVE=1. Drives REAL production runEntwurfV2 deps over REAL OS objects, 4 cells: C1 control-socket (real pi --entwurf-control resident → RPC send → lock acquire→release ×1), C1b record-less socket (#50 C4: live record-less pi → EVERY intent rejected pre-probe record-less-socket, no lock, rendered hint names record authority + fresh-cut), C2 meta-mailbox deliverable (armed self-fetch citizen → real .msg enqueue, lock-free), C3 meta-mailbox guard (no armed receiver → reject, no garbage). Model-in-loop OUT (transport/lock/enqueue gate, GPT Q2); negative/timeout stay deterministic. Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.6-luna). LIVE=1 ./run.sh smoke-entwurf-v2-matrix-live
|
|
224
|
-
./run.sh smoke-agy-native-push-live #
|
|
225
|
+
./run.sh smoke-agy-native-push-live # PAUSED (#152): exits 2 with [entwurf:paused] before it reads LIVE or AGY_CONVERSATION_ID — not a PASS and not a SKIP; OUT of pnpm check. Open no agy conversation for it while the pause holds. Its 봉인 8 native-push round trip (real antigravity adapter + register core + runEntwurfV2) runs only after a separate change lifts the pause.
|
|
225
226
|
./run.sh smoke-codex-native-push-live # on-demand LIVE acceptance for Codex native-push — needs LIVE=1 + CODEX_LIVE_THREAD_ID loaded by a visible TUI attached to the default app-server; probes the real UDS, routes through production runEntwurfV2, queues one exact-token turn without retry, re-probes, and leaves the visible TUI to show the model result
|
|
226
227
|
./run.sh smoke-codex-fresh-live # #95 RELEASE MUST: record-backed receipt fixture -> PUBLIC initial Pi fresh/callback in a session S that is NOT the app-server's -> Pi PUBLIC omitted-placement Codex fresh/exact callback, also in S -> Pi-to-Codex addressed native-push v2 -> Codex PUBLIC omitted-placement AND omitted-cwd fresh Pi/exact callback IN S beside its own TUI (lane B claim: the app-server env names another session, so S can only come from the caller's pane title; lane C claim: no cwd was asked for, so the directory can only come from the Codex caller's own record — and the Codex thread's own rollout session_meta.cwd, its pane and its record must all be the requested scratch, not the app-server's repo) -> Codex final v2 evidence. Needs LIVE=1 + ENTWURF_CODEX_APP_SERVER_PID + ENTWURF_CODEX_FRESH_MODEL + ENTWURF_CODEX_FRESH_PI_MODEL, and its ONE stable launch directory answered 'Trust' once in a plain codex -C there: codex records its direct consent per exact directory, so a directory with no answer at all opens a consent screen instead of a first turn. Only THIS gate treats that as a precondition and fails up front as codex-launch-cwd-undecided rather than timing out on a callback — an ordinary entwurf_fresh_call only prints the note and opens the window, because a human can answer the screen. The smoke PRINTS that directory as 'launch-cwd <dir>' and repeats it in the failure as a ready-to-run repair command — do not retype it from memory, and do not write it as \$TMPDIR/... (os.tmpdir() falls back to /tmp when TMPDIR is unset, so that spelling names a different directory in the filesystem root). The PID names the operator-owned app-server, which must sit in a DIFFERENT session from S; the smoke checks/prints all four coordinates, never starts/stops/guesses the app-server/session, never reads screen text, interrupts only its exact still-running Codex turn, and cleans only receipt-named window ids
|
|
227
|
-
./run.sh smoke-mux-lifecycle-live # RELEASE MUST integrated LIVE lifecycle acceptance for mux, through the REAL MCP surface — OUT of pnpm check, needs LIVE=1 and spends model turns (two pi siblings: native + recorded-ACP provider, each resumed once; one Claude Code sibling). tools/call fresh_call -> nonce callback sender envelope -> v2 control send landing in the sibling's own transcript -> resume_call REFUSED while live (window count unchanged) -> stable-handle close (pane gone, socket dead, record kept) -> dormant delivery refused honestly -> public entwurf_resume_call with LAUNCH and OBSERVATION receipts kept apart, same-gid socket alive, zero new citizens, zero lock residue, resumed pane_start_path == RECORD cwd (separate tmux query), transcript byte-identical across the resume -> v2 recall of the pre-close fact. claude-code resume of the still-live sibling refused target-live, no window opened and no lock residue (its dormant same-id resume is deterministic-only, #147 L2). LIVE=1 ./run.sh smoke-mux-lifecycle-live
|
|
228
|
+
./run.sh smoke-mux-lifecycle-live # RELEASE MUST integrated LIVE lifecycle acceptance for mux, through the REAL MCP surface — OUT of pnpm check, needs LIVE=1 and spends model turns (two pi siblings: native + recorded-ACP provider, each resumed once; one Claude Code sibling). tools/call fresh_call (the native pi cell names a caller-distinct seat and tmux is asked where the pane landed, #108) -> nonce callback sender envelope -> v2 control send landing in the sibling's own transcript -> resume_call REFUSED while live (window count unchanged) -> stable-handle close (pane gone, socket dead, record kept) -> dormant delivery refused honestly -> public entwurf_resume_call with LAUNCH and OBSERVATION receipts kept apart, same-gid socket alive, zero new citizens, zero lock residue, resumed pane_start_path == RECORD cwd (separate tmux query), transcript byte-identical across the resume -> v2 recall of the pre-close fact. claude-code resume of the still-live sibling refused target-live, no window opened and no lock residue (its dormant same-id resume is deterministic-only, #147 L2). LIVE=1 ./run.sh smoke-mux-lifecycle-live
|
|
228
229
|
./run.sh check-meta-facts # deterministic gate for the meta-facts projection (#65): drives the REAL CLI — full-record join, parse-before-uniqueness, no-winner duplicates, drift/symlink/invalid-UTF-8 defects in-band, deterministic bytes, exit contract 0/2/3, dispatch+emit reachability
|
|
229
230
|
./run.sh check-herdr-plugin # deterministic gate for the #116 M2-b herdr plugin (`plugins/herdr/`): STATIC manifest shape for herdr 0.9.0 + the forbidden sections ([[startup]]/[[events]]/[[actions]]/[[link_handlers]]) asserted absent ([[build]] is check-herdr-plugin-build's subject since #116 M3-b3); BEHAVIOURAL drive of the REAL pane entry against a stub `entwurf` and stub HERDR_BIN_PATH that LOG every call — exactly one `herdr integration status` + one `entwurf peer-facts` + one `herdr agent list` per open, in that order (counted, not claimed), through ONE spawn call site; the four blocks each naming their own owner/observation time with no aggregate verdict; the D3=C fallback reading the activation ledger from the path its WRITER owns (XDG state, never the runtime's data root) and only when the phase is `active`, with ENTWURF_BIN and PATH still winning outright; the citizen axis alone skipping by name when no binary is reachable; every broken-evidence state a named red rather than a crash or an empty table, and a selected herdr atom that is `outdated`/`needs repair` as block [1]'s OWN red (`not installed` stays a reported skip); ambiguous never first-wins, diagnostics shown, activity in its own column, and zero writes to the plugin state/config dirs. No herdr binary, no Entwurf install
|
|
230
231
|
./run.sh check-herdr-runtime-bootstrap # deterministic gate for the #116 M3-b1 runtime leaf (`plugins/herdr/lib/runtime-bootstrap.mjs`): the Entwurf-owned stable active root as a REAL directory (nothing is put on PATH — the scoped wiring above names ABSOLUTE commands under it), ownership decided BEFORE the first mkdir, disk facts from lstat (a dangling symlink is not 'absent' and a link into another tree is not a directory), exact name@version + compiled entry + all three required bins present AND executable + a real `check-bridge`, the plugin-owned artifact lock coherent with the checkout, the owned npm cache and --ignore-scripts, a CERTIFIED journal (non-object/array/scalar/blank-identity/phase-contradicting-digest all refused) as the only ownership proof, all EIGHT active/staging/previous combinations named, the last good runtime never lost (torn swap AND corrupt-active beside a good backup), prior provenance carried across an install that may not finish, a failed candidate leaving the running runtime byte-identical, idempotent same-spec reinstall, a journal believed only while the disk backs it, a preflight-then-mutate inverse taking runtime last, and the refusal to record Herdr's commit as ours. NETWORK ZERO, npm ZERO — it drives a FIXTURE package, so the ACTUAL package proof lives in check-pack-install
|
|
@@ -240,6 +241,8 @@ Usage:
|
|
|
240
241
|
./run.sh check-entwurf-deliverability # deterministic gate (SE-1/SE-2 slice 2c): conversational-mailbox deliverability predicate — computeMetaReceiverActive (recordBacked ∧ ownerAlive ∧ watchArmed) + mailboxConversationalDeliverable (self-fetch AND active); direct-inject pi refused (SE-1), self-fetch dead/unarmed refused (SE-2); self-address shares the same atom
|
|
241
242
|
./run.sh check-native-push-adapter # deterministic gate (봉인 3/8): native-push adapter leaf (antigravity) via a FAKE runner — FULL pid scan (not head -1), dead vs indeterminate, VOLATILE route re-discovery (no cache), send argv+ANTIGRAVITY_LS_ADDRESS env, non-zero exit throws, NO adapter-level retry (executor-owned), resolveNativePushAdapter fail-fast
|
|
242
243
|
./run.sh check-native-push-register # deterministic gate (봉인 5): registerNativeConversation (entwurf_register_native core) via fake adapter + isolated mkdtemp store — live probe→CREATE, re-register→ATTACH (same gid, cwd refreshed, no dup), not-live probe→REFUSE (throws, no record), receiver-marker abstinence (보정① source guard)
|
|
244
|
+
./run.sh check-native-push-paused # #152 mutant execution coordinate: run_vitest over paused.test.ts alone — dispatch, sender replyable and entwurf_register_native refuse a paused backend (antigravity) before any probe. Same file check-tests-beside-behavior already runs.
|
|
245
|
+
./run.sh check-chain-terminus-publication # mutant execution coordinate: run_vitest over test/chain-terminus-publication.test.ts alone — smoke-entwurf-chain-live's terminus wait ends only on a body AND inbox.signal, inside the same deadline.
|
|
243
246
|
./run.sh check-agy-sender-identity # deterministic gate (#46 sender lane): WHO is calling the bridge — real agy hook as a child process writes an antigravity sender marker keyed by its PARENT pid (never on upsert failure), and resolveTrustedMetaSenderIdentity over isolated stores yields 0→null / 1→identity on EITHER backend / two distinct live identities on one owner pid→THROW (never guess, never downgrade to anonymous). This is what turns an agy send from external-mcp/unknown-host into a replyable garden citizen
|
|
244
247
|
./run.sh check-package-source-routing # deterministic gate (#29): package-source -> install-root mapping + fail-fast routing (local/git/npm/missing/project/no-source × local+remote, self-root, resume), no backend
|
|
245
248
|
./run.sh new-session-id # print one fresh garden id from the generateSessionId SSOT (#50 C2: no launcher injection — the record layer is the consumer; pi mints its own session id)
|
|
@@ -338,6 +341,7 @@ Usage:
|
|
|
338
341
|
./run.sh check-node-floor-coherence # binds the Node floor (24+, single axis) across engines.node, run.sh setup preflight, meta-bridge install/doctor judgment logic, clean-host docs, the bridge launcher header, and the CI runner node-version — engines.node is the SSOT, everything else is derived; sweeps tracked contract text for an unregistered declaration
|
|
339
342
|
./run.sh check-pack # publish gate (dry-run): npm pack --dry-run + tarball invariants (runtime-critical present, dev residue absent)
|
|
340
343
|
./run.sh check-pack-pin-matcher # pure self-test of check-pack-install's pin-leak matcher against synthetic .pnpm lookalikes, one cell per property: version boundary (a prefix-extended @0.86.0-beta.1 and an off-pin @0.85.1 must leak, @0.86.0 bare or with any measured peer-hash must pass) and closure prefix (an off-pin @earendil-works/chord must leak — it carries no `pi-` prefix); snapshot-safe qualification oracle, also run first inside check-pack-install
|
|
344
|
+
./run.sh check-pack-argv-matcher # pure self-test of check-pack-install's dispatcher-verb leak refusal (the copilot and codex-app-server cells): a front-loaded or trailing leak in ~260 KB is refused where the retired printf | grep -qF shape misses it (teeth control measured each run), clean output passes silently, a failing grep is refused by name, and both cells still return through it; snapshot-safe qualification oracle, also run first inside check-pack-install
|
|
341
345
|
./run.sh check-pack-consumer-roots # pure self-test of check-pack-install's consumer sandbox: under a poisoned inherited HOME/XDG/PI_CODING_AGENT_DIR every writable root a consumer subcall sees resolves inside its own consumer home; snapshot-safe qualification oracle, also run first inside check-pack-install
|
|
342
346
|
./run.sh check-fresh-cut-gate # SOURCE cell of the generation-boundary proof (IN pnpm run check:full): drives real install/setup/fresh-cut in a sandbox; certification refusal is pre-write, quiescence is fail-closed, archives preserve bytes, and the #54 exit matrix distinguishes complete / no-move / usage / incomplete transition / complete-with-cleanup-residue. No model/network/cost
|
|
343
347
|
./run.sh check-pack-install # heavy publish gate (prepublishOnly): actual npm pack + tar -tf + fresh-temp install smoke + the #116 M3-b1 herdr-plugin RUNTIME VERIFIER run against that actual installed tarball (the focused check-herdr-runtime-bootstrap drives a fixture; THIS is where the real package is proven) with the pinned pi SDK (pins derived from the package.json exact production dependency; check-dep-versions binds them) + the npm-installed bridge BOOTS (tools/list) and DELIVERS (tools/call entwurf_v2 → .msg lands) + the installed all-absent and copilot-present (four-unit fake-vendor) `entwurf setup` rows + the INSTALLED generation lifecycle on a seeded previous-generation host (REFUSE before activation writes / zero Claude invocations → installed fresh-cut archives + opens empty → install-meta-bridge PASSES) + the INSTALLED-PACKAGE branch of the Copilot and OMP birth installers actually RUN (compiled entry selected, no raw .ts, and a real birth edge mints a citizen — the half a required-artifact list can never stand in for) + the INSTALLED #129 durable bootstrap (pi/pi-durable/bootstrap.mjs) imported from node_modules: main/openDurableCitizen exported and PACKAGED_BRIDGE_ENTRY = the installed package's own dist entry — import only, no runtime/TUI/birth/bridge started + the #130 pi-durable CARRIER on actual npm consumers (Entwurf-only / aligned host / isolated global): the installed verifier, a consumer-contained resolution oracle with a same-sandbox neighbour control, every physical SDK edge at the pin, a mixed tree refused as pi-durable-sdk-mismatch though it still imports, and the public `entwurf pi-durable` reaching the app's own explicit-model refusal before any birth, also with one explicit `--native-module` (the synthetic fixture, initialized first; a reserved extension name refused before anything opens) (offline, sandbox HOME)
|
|
@@ -1402,6 +1406,26 @@ check_entwurf_v2_native_push() {
|
|
|
1402
1406
|
run_vitest pi-extensions/lib/entwurf-v2-native-push.test.ts
|
|
1403
1407
|
}
|
|
1404
1408
|
|
|
1409
|
+
check_native_push_paused() {
|
|
1410
|
+
# MUTANT EXECUTION COORDINATE, not a discovery path — paused.test.ts is found by
|
|
1411
|
+
# check-tests-beside-behavior like every other beside-behaviour lane. This case exists
|
|
1412
|
+
# because the AGY-NATIVE-PUSH-PAUSED mutant (#152) names it as gate argv; the narrow file
|
|
1413
|
+
# filter keeps that mutant from re-running every beside-behaviour test. It stays inside
|
|
1414
|
+
# check:contracts for the same reason as check-entwurf-v2-native-push above.
|
|
1415
|
+
section "native-push pause policy (#152, mutant execution coordinate)"
|
|
1416
|
+
run_vitest pi-extensions/lib/native-push/paused.test.ts
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
check_chain_terminus_publication() {
|
|
1420
|
+
# MUTANT EXECUTION COORDINATE for the CHAIN-TERMINUS-WAITS-FOR-SIGNAL mutant: run_vitest over
|
|
1421
|
+
# test/chain-terminus-publication.test.ts alone — the terminus wait of smoke-entwurf-chain-live
|
|
1422
|
+
# (scripts/lib/chain-terminus-publication.ts) driven offline through the two-write publication
|
|
1423
|
+
# enqueueMetaMessage produces (.msg first, inbox.signal last). It stays inside check:contracts
|
|
1424
|
+
# because a gate a mutant names must be reachable outside qualification.
|
|
1425
|
+
section "chain terminus publication wait (mutant execution coordinate)"
|
|
1426
|
+
run_vitest test/chain-terminus-publication.test.ts
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1405
1429
|
check_entwurf_v2_surface() {
|
|
1406
1430
|
# Deterministic gate for 0.11 Stage 0 step 5d-3a: the ctx-free surface adapter
|
|
1407
1431
|
# (entwurf-v2-surface.ts) + the entwurf-control.ts wiring contract. Proves the pure parts:
|
|
@@ -1693,6 +1717,14 @@ check_pi_durable_native_module() {
|
|
|
1693
1717
|
run_vitest pi-extensions/lib/pi-durable-native-module.test.ts
|
|
1694
1718
|
}
|
|
1695
1719
|
|
|
1720
|
+
check_remote_pair_beside() {
|
|
1721
|
+
# #149: the execution coordinate for the declared remote pairs (VERIFY 「Four rules」 rule 3). Not a
|
|
1722
|
+
# discovery path — check-tests-beside-behavior already finds these files. Every remote-pair claim
|
|
1723
|
+
# carries its QK in one of them, and the qualification runner re-invokes a gate argv once per
|
|
1724
|
+
# mutant, so the narrow filter keeps one mutant from re-running every beside test.
|
|
1725
|
+
run_vitest pi-extensions/lib/remote-pair-send.test.ts pi-extensions/lib/remote-pair-receive.test.ts pi-extensions/lib/remote-pair-roundtrip.test.ts pi-extensions/lib/remote-pair-transport.test.ts pi-extensions/lib/meta-mailbox-body.test.ts
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1696
1728
|
smoke_mux_fresh_call_live() {
|
|
1697
1729
|
# LIVE acceptance for entwurf_fresh_call — OUT of pnpm check, needs LIVE=1, spends two model
|
|
1698
1730
|
# turns. The one axis no deterministic gate reaches: a real window, a real runtime, a real first
|
|
@@ -4021,6 +4053,10 @@ check_pack() {
|
|
|
4021
4053
|
# JS for installed entrypoints. The files array lists pi/pi-durable per FILE, so nothing admits these
|
|
4022
4054
|
# today; this tripwire is what fails loud the day an allowlist entry would.
|
|
4023
4055
|
local durable_source_pattern='^pi/pi-durable/(src/|tsconfig\.json$|overlay/runtime-contacts\.patch$)'
|
|
4056
|
+
# #148 S1b: the goldens and generator a beside test reads (pi-extensions/lib/fixtures/) are test input,
|
|
4057
|
+
# not product. `pi-extensions/` ships whole, so the `!pi-extensions/**/fixtures/**` negation is the only
|
|
4058
|
+
# thing keeping them out, and this is its tripwire (same 결합 규칙 as the `.test.ts` pattern above).
|
|
4059
|
+
local test_fixture_pattern='^pi-extensions/(.*/)?fixtures/'
|
|
4024
4060
|
|
|
4025
4061
|
local pass=1 f pat hit
|
|
4026
4062
|
|
|
@@ -4047,6 +4083,13 @@ check_pack() {
|
|
|
4047
4083
|
pass=0
|
|
4048
4084
|
fi
|
|
4049
4085
|
|
|
4086
|
+
hit=$(grep -E "$test_fixture_pattern" <<<"$file_list" || true)
|
|
4087
|
+
if [ -n "$hit" ]; then
|
|
4088
|
+
fail "[check-pack] a beside test's fixtures (pi-extensions/**/fixtures/) ride the tarball — test input is not product; restore the files-array negation:"
|
|
4089
|
+
echo "$hit" | sed 's/^/ /' >&2
|
|
4090
|
+
pass=0
|
|
4091
|
+
fi
|
|
4092
|
+
|
|
4050
4093
|
# #78 — a pack carries the Windows addon not at all, or as exactly a verified addon + manifest
|
|
4051
4094
|
# pair (pack_win32_carrier_verdict, proven on owned fixtures by check-pack-win32-carrier).
|
|
4052
4095
|
# "present" means the carrier verified, never that the build was approved for publication.
|
|
@@ -4157,7 +4200,7 @@ check_pack_win32_carrier() {
|
|
|
4157
4200
|
# which is exactly what property (1)'s `(_|$)` absorbs; all three shapes are fixtures
|
|
4158
4201
|
# below so a future suffix change cannot pass vacuously.)
|
|
4159
4202
|
pack_install_leaked_pi() {
|
|
4160
|
-
grep '^@earendil-works+' | grep -Ev '@1\.
|
|
4203
|
+
grep '^@earendil-works+' | grep -Ev '@1\.4\.0(_|$)' || true
|
|
4161
4204
|
}
|
|
4162
4205
|
|
|
4163
4206
|
# Matcher self-test on SYNTHETIC lookalikes: a healthy install tree cannot exercise either
|
|
@@ -4174,18 +4217,18 @@ check_pack_pin_matcher() {
|
|
|
4174
4217
|
# Cell 1 — the version boundary. Every measured peer-hash shape is a fixture: the
|
|
4175
4218
|
# 0.84.4-era `_@modelcontextprotocol+sdk@…`, the `_ws@8.21.3` observed on a real
|
|
4176
4219
|
# 0.85.1 tree, and `[측정 2026-09-20]` the combined suffix a 0.86.0 install carries.
|
|
4177
|
-
# None may leak; the two lookalikes must — a PREFIX-EXTENDED version (`
|
|
4220
|
+
# None may leak; the two lookalikes must — a PREFIX-EXTENDED version (`1.4.0-beta.1`,
|
|
4178
4221
|
# the prerelease shape that an unanchored match would bless) and an off-pin version.
|
|
4179
4222
|
matcher_probe=$(printf '%s\n' \
|
|
4180
|
-
'@earendil-works+pi-ai@1.
|
|
4181
|
-
'@earendil-works+pi-ai@1.
|
|
4182
|
-
'@earendil-works+pi-ai@1.
|
|
4183
|
-
'@earendil-works+pi-ai@1.
|
|
4184
|
-
'@earendil-works+pi-ai@1.
|
|
4223
|
+
'@earendil-works+pi-ai@1.4.0' \
|
|
4224
|
+
'@earendil-works+pi-ai@1.4.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6' \
|
|
4225
|
+
'@earendil-works+pi-ai@1.4.0_ws@8.21.3' \
|
|
4226
|
+
'@earendil-works+pi-ai@1.4.0_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__ws@8.21.3_zod@4.3.6' \
|
|
4227
|
+
'@earendil-works+pi-ai@1.4.0-beta.1' \
|
|
4185
4228
|
'@earendil-works+pi-agent-core@0.87.1' | pack_install_leaked_pi)
|
|
4186
|
-
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.
|
|
4229
|
+
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.4.0-beta.1
|
|
4187
4230
|
@earendil-works+pi-agent-core@0.87.1' ]; then
|
|
4188
|
-
fail "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED] the pin-leak matcher must flag the prefix-extended 1.
|
|
4231
|
+
fail "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED] the pin-leak matcher must flag the prefix-extended 1.4.0-beta.1 and the off-pin 0.87.1 lookalikes, and pass 1.4.0 bare or with any measured peer-hash — got: ${matcher_probe:-<nothing leaked>}"
|
|
4189
4232
|
return 1
|
|
4190
4233
|
fi
|
|
4191
4234
|
|
|
@@ -4193,9 +4236,9 @@ check_pack_pin_matcher() {
|
|
|
4193
4236
|
# (0.85.0 onward, still true at 0.99.1). An off-pin chord MUST leak; the pinned one must not. A matcher narrowed
|
|
4194
4237
|
# back to `^@earendil-works+pi-` sees nothing here and dies at this signature.
|
|
4195
4238
|
matcher_probe=$(printf '%s\n' \
|
|
4196
|
-
'@earendil-works+chord@1.
|
|
4239
|
+
'@earendil-works+chord@1.4.0' \
|
|
4197
4240
|
'@earendil-works+chord@0.87.1' \
|
|
4198
|
-
'@earendil-works+pi-ai@1.
|
|
4241
|
+
'@earendil-works+pi-ai@1.4.0' | pack_install_leaked_pi)
|
|
4199
4242
|
if [ "$matcher_probe" != '@earendil-works+chord@0.87.1' ]; then
|
|
4200
4243
|
fail "[QK:PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE] the pin-leak matcher must cover every @earendil-works closure member, not just the pi-* families — an off-pin @earendil-works/chord has to leak (it was a runtime dependency of pi-coding-agent, pi-agent-core, pi-client and pi-protocol — `[측정 2026-09-20]` at 0.86.0, re-measured `[측정 2026-09-22]` at 0.87.0, `[측정 2026-09-23]` at 0.87.1 and `[측정 2026-09-30]` at 0.99.1, where pi-coding-agent adds pi-codemode and pi-mcp beside them; `[측정 2026-10-13]` at 1.2.0 pi-durable alone declares it) — got: ${matcher_probe:-<nothing leaked>}"
|
|
4201
4244
|
return 1
|
|
@@ -4204,12 +4247,112 @@ check_pack_pin_matcher() {
|
|
|
4204
4247
|
echo "[check-pack-pin-matcher] ok — the pin-leak matcher is version-bounded (lookalikes leak, pinned version passes bare and with either measured peer-hash) and covers the whole @earendil-works closure (chord included)"
|
|
4205
4248
|
}
|
|
4206
4249
|
|
|
4250
|
+
# The dispatcher-verb leak refusal of check-pack-install's copilot and codex-app-server cells: the
|
|
4251
|
+
# vendor stand-in prints one `ARG<…>` line per argument, and the dispatcher verb among them means it
|
|
4252
|
+
# leaked into the vendor's argv. The search it replaces, `printf '%s' "$op_out" | grep -qF …`,
|
|
4253
|
+
# refused only when that pipeline exited 0: bash's printf writes a multi-line value a line at a
|
|
4254
|
+
# time, `-q` closes the pipe at the first match, and pipefail turned the producer's 141 into a pass
|
|
4255
|
+
# (pipefail audit, 2026-10-23: latent, no false green observed in CI). A here-string has no
|
|
4256
|
+
# producer to kill, and the verdict reads the search's own rc: 1 (clean) passes, 0 (leaked) and any
|
|
4257
|
+
# other rc (the search itself failed) refuse with the cell's diagnostic.
|
|
4258
|
+
pack_install_refuse_argv_leak() {
|
|
4259
|
+
local label="$1" out="$2" token="$3" argv_search_rc=0
|
|
4260
|
+
grep -qF -- "$token" <<<"$out" || argv_search_rc=$?
|
|
4261
|
+
case "$argv_search_rc" in
|
|
4262
|
+
1) return 0 ;;
|
|
4263
|
+
0)
|
|
4264
|
+
fail "[check-pack-install] installed 'entwurf $label' leaked the dispatcher verb into the vendor's argv:"
|
|
4265
|
+
echo "$out" | tail -8 | sed 's/^/ /' >&2
|
|
4266
|
+
;;
|
|
4267
|
+
*) fail "[check-pack-install] installed 'entwurf $label': the dispatcher-verb search itself failed (rc=$argv_search_rc) — refused, never read as no leak" ;;
|
|
4268
|
+
esac
|
|
4269
|
+
return 1
|
|
4270
|
+
}
|
|
4271
|
+
|
|
4272
|
+
# Self-test of pack_install_refuse_argv_leak — the SAME verdict both cells return through, never a
|
|
4273
|
+
# re-typed predicate — on synthetic stand-in output: its pass/refuse result and the diagnostic that
|
|
4274
|
+
# names why, one QK per verdict, plus a text check that both cells still return through it.
|
|
4275
|
+
# Snapshot-safe like check-pack-pin-matcher, and run first inside check-pack-install. The large
|
|
4276
|
+
# fixtures put the leak ahead of ~260 KB, past the default 64 KiB pipe buffer. The teeth control
|
|
4277
|
+
# measures, on THIS host, that the retired pipe shape misses it there (grep matched, the pipeline
|
|
4278
|
+
# still failed); a fixture that stops biting is a red of its own, not a vacuous green.
|
|
4279
|
+
check_pack_argv_matcher() {
|
|
4280
|
+
local cop_leak cop_clean cx_leak cx_clean big_tail big_leak_front big_leak_end big_clean
|
|
4281
|
+
local rc out label fx token missed shim bound_copilot bound_codex red=0 teeth=()
|
|
4282
|
+
cop_leak=$'FLAG=[EXTENSIONS]\nARG<copilot>\nARG<-p>\nARG<hi>\nARG<--model>\nARG<auto>\nARG<--yolo>'
|
|
4283
|
+
cop_clean=$'FLAG=[EXTENSIONS]\nARG<-p>\nARG<hi>\nARG<--model>\nARG<auto>\nARG<--yolo>'
|
|
4284
|
+
cx_leak=$'ARG<codex-app-server>\nARG<app-server>\nARG<--listen>\nARG<unix:///h/.codex/app-server.sock>\nARG<--config>\nARG<probe=1>'
|
|
4285
|
+
cx_clean=$'ARG<app-server>\nARG<--listen>\nARG<unix:///h/.codex/app-server.sock>\nARG<--config>\nARG<probe=1>'
|
|
4286
|
+
big_tail=$(seq 1 24000 | sed 's/^/ARG<x/; s/$/>/')
|
|
4287
|
+
big_leak_front=$'FLAG=[EXTENSIONS]\nARG<copilot>\n'"$big_tail"
|
|
4288
|
+
big_leak_end="$big_tail"$'\nARG<codex-app-server>'
|
|
4289
|
+
big_clean=$'FLAG=[EXTENSIONS]\n'"$big_tail"
|
|
4290
|
+
|
|
4291
|
+
# Teeth control: the defect's own signature — grep matched (its PIPESTATUS is 0) yet the pipeline
|
|
4292
|
+
# failed. A grep error is not teeth, and an exact 141 is not required (an inherited ignored
|
|
4293
|
+
# SIGPIPE still makes the producer fail, and the miss is just as real).
|
|
4294
|
+
{ printf '%s' "$big_leak_front" | grep -qF -- 'ARG<copilot>'; teeth=("$?" "${PIPESTATUS[@]}"); } || true
|
|
4295
|
+
if [ "${teeth[0]}" -eq 0 ] || [ "${teeth[2]:-unset}" != 0 ]; then
|
|
4296
|
+
fail "[check-pack-argv-matcher] the planted fixture has no teeth here: the retired printf | grep -qF shape did not miss a leak it matched (pipeline=${teeth[0]} PIPESTATUS=${teeth[*]:1}), so the cells below would prove nothing — enlarge it"
|
|
4297
|
+
return 1
|
|
4298
|
+
fi
|
|
4299
|
+
|
|
4300
|
+
missed=""
|
|
4301
|
+
for fx in "copilot cop_leak ARG<copilot>" "codex-app-server cx_leak ARG<codex-app-server>" "copilot big_leak_front ARG<copilot>" "codex-app-server big_leak_end ARG<codex-app-server>"; do
|
|
4302
|
+
read -r label fx token <<<"$fx"
|
|
4303
|
+
rc=0; out=$(pack_install_refuse_argv_leak "$label" "${!fx}" "$token" 2>&1) || rc=$?
|
|
4304
|
+
{ [ "$rc" -eq 1 ] && [[ "$out" == *"leaked the dispatcher verb"* ]]; } || missed+=" $fx(rc=$rc)"
|
|
4305
|
+
done
|
|
4306
|
+
if [ -n "$missed" ]; then
|
|
4307
|
+
fail "[QK:PACK-INSTALL-ARGV-LEAK-CAUGHT] a leaked dispatcher verb must be refused as a leak wherever it sits and however long the output — passed or misnamed:$missed"
|
|
4308
|
+
red=1
|
|
4309
|
+
fi
|
|
4310
|
+
|
|
4311
|
+
missed=""
|
|
4312
|
+
for fx in "copilot cop_clean ARG<copilot>" "codex-app-server cx_clean ARG<codex-app-server>" "copilot big_clean ARG<copilot>"; do
|
|
4313
|
+
read -r label fx token <<<"$fx"
|
|
4314
|
+
rc=0; out=$(pack_install_refuse_argv_leak "$label" "${!fx}" "$token" 2>&1) || rc=$?
|
|
4315
|
+
{ [ "$rc" -eq 0 ] && [ -z "$out" ]; } || missed+=" $fx(rc=$rc)"
|
|
4316
|
+
done
|
|
4317
|
+
if [ -n "$missed" ]; then
|
|
4318
|
+
fail "[QK:PACK-INSTALL-ARGV-CLEAN-PASSES] stand-in output without the verb must pass silently, small or large — refused:$missed"
|
|
4319
|
+
red=1
|
|
4320
|
+
fi
|
|
4321
|
+
|
|
4322
|
+
# A search that fails is refused, never read as clean: a `grep` that exits 2 on PATH.
|
|
4323
|
+
shim=$(mktemp -d "${TMPDIR:-/tmp}/entwurf-argv-shim.XXXXXX")
|
|
4324
|
+
printf '#!/bin/sh\n: > "%s/reached"\nexit 2\n' "$shim" > "$shim/grep"
|
|
4325
|
+
chmod +x "$shim/grep"
|
|
4326
|
+
rc=0; out=$(PATH="$shim:$PATH"; pack_install_refuse_argv_leak copilot "$cop_clean" 'ARG<copilot>' 2>&1) || rc=$?
|
|
4327
|
+
if [ ! -e "$shim/reached" ]; then
|
|
4328
|
+
rm -rf "$shim"
|
|
4329
|
+
fail "[check-pack-argv-matcher] the failing grep stand-in was never reached, so the search-error cell would prove nothing"
|
|
4330
|
+
return 1
|
|
4331
|
+
fi
|
|
4332
|
+
rm -rf "$shim"
|
|
4333
|
+
if [ "$rc" -ne 1 ] || [[ "$out" != *"search itself failed (rc=2)"* ]]; then
|
|
4334
|
+
fail "[QK:PACK-INSTALL-ARGV-SEARCH-ERROR-REFUSED] a search that fails (grep rc=2) must refuse the cell and say so, never pass it as clean — got rc=$rc: ${out:-<silent>}"
|
|
4335
|
+
red=1
|
|
4336
|
+
fi
|
|
4337
|
+
|
|
4338
|
+
# Both cells must return through this verdict; a reverted cell would leave the cells above green.
|
|
4339
|
+
bound_copilot=$(grep -cxF " pack_install_refuse_argv_leak copilot \"\$op_out\" 'ARG<copilot>' || return 1" "$REPO_DIR/run.sh" || true)
|
|
4340
|
+
bound_codex=$(grep -cxF " pack_install_refuse_argv_leak codex-app-server \"\$op_out\" 'ARG<codex-app-server>' || return 1" "$REPO_DIR/run.sh" || true)
|
|
4341
|
+
if [ "$bound_copilot" != 1 ] || [ "$bound_codex" != 1 ]; then
|
|
4342
|
+
fail "[QK:PACK-INSTALL-ARGV-CELLS-BOUND] the copilot and codex-app-server leak refusals of check-pack-install must each return through pack_install_refuse_argv_leak once (copilot=$bound_copilot codex=$bound_codex)"
|
|
4343
|
+
red=1
|
|
4344
|
+
fi
|
|
4345
|
+
|
|
4346
|
+
[ "$red" -eq 0 ] || return 1
|
|
4347
|
+
echo "[check-pack-argv-matcher] ok — the dispatcher-verb refusal refuses a leak at the front or end of ~260 KB (where the retired pipe shape misses it), passes clean output silently, refuses a failed search by name, and both check-pack-install cells return through it"
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4207
4350
|
# #130 — the pi-durable carrier proved on ACTUAL npm consumers of the candidate tarball.
|
|
4208
4351
|
# $1 tarball $2 the gate's npm sandbox $3 an existing Entwurf-only npm consumer root inside it.
|
|
4209
4352
|
# Cells: L1s (Entwurf alone, $3), L1 (project-local beside an aligned host pi-coding-agent at the
|
|
4210
4353
|
# pinned SDK version), L2 (an isolated `npm -g --prefix`), each through (a) the INSTALLED verifier
|
|
4211
4354
|
# (exit 0, prints its own carrier-resolver) and (b) an independent consumer oracle; then the L3
|
|
4212
|
-
# NEGATIVE (an override binds pi-durable's pi-
|
|
4355
|
+
# NEGATIVE (an override binds pi-durable's pi-codemode edge to an older published version: the installed verifier must
|
|
4213
4356
|
# refuse it by name, while a bare import still succeeds); then (c) the public launch on L1s.
|
|
4214
4357
|
# The oracle observes RESOLUTIONS (a resolve hook), not every filesystem read; it asserts each
|
|
4215
4358
|
# resolved product file lies inside THIS consumer's node_modules — a sandbox ancestor is not the
|
|
@@ -4304,13 +4447,18 @@ ORACLE
|
|
|
4304
4447
|
echo "[check-pack-install] pi-durable $cell: installed verifier PASS; consumer oracle $out"
|
|
4305
4448
|
done
|
|
4306
4449
|
|
|
4307
|
-
|
|
4450
|
+
# The wrong edge must still IMPORT, or the control proves a crash rather than a refusal. `[측정 2026-10-22]`
|
|
4451
|
+
# SDK 1.4 pi-durable imports pi-ai's new `utils/identity`, absent from the older pi-ai control versions
|
|
4452
|
+
# checked here (1.0.3 and 1.3.0 both fail to load); pi-telemetry 1.0.3/1.3.0 and chord 1.3.0 lack exports
|
|
4453
|
+
# it imports. pi-codemode 1.3.0 loads, and depends on no SDK member, so this tree carries exactly one
|
|
4454
|
+
# depth-2 mismatch (L4 keeps depth 3).
|
|
4455
|
+
printf '%s\n' "{\"name\":\"pd-mismatch\",\"version\":\"1.0.0\",\"private\":true,\"overrides\":{\"@earendil-works/pi-durable\":{\"@earendil-works/pi-codemode\":\"1.3.0\"}}}" > "$box/pd-mismatch/package.json"
|
|
4308
4456
|
out=$(cd "$box/pd-mismatch" && npm install "$tgz" --no-audit --no-fund 2>&1) || {
|
|
4309
4457
|
fail "[check-pack-install] pi-durable L3 (mismatch control) install failed:"; echo "$out" | tail -10 | sed 's/^/ /' >&2; return 1; }
|
|
4310
4458
|
pkg="$box/pd-mismatch/node_modules/@junghanacs/entwurf"
|
|
4311
4459
|
rc=0; out=$(cd "$box" && node "$pkg/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js" resolve 2>&1) || rc=$?
|
|
4312
|
-
if [ "$rc" -ne 3 ] || ! grep -q "pi-durable-sdk-mismatch: @earendil-works/pi-durable → @earendil-works/pi-
|
|
4313
|
-
fail "[QK:PACK-INSTALL-DURABLE-MISMATCH-REFUSED] [check-pack-install] pi-durable L3: an installed tree whose pi-durable binds pi-
|
|
4460
|
+
if [ "$rc" -ne 3 ] || ! grep -q "pi-durable-sdk-mismatch: @earendil-works/pi-durable → @earendil-works/pi-codemode wants $pin_ver, binds 1.3.0" <<<"$out"; then
|
|
4461
|
+
fail "[QK:PACK-INSTALL-DURABLE-MISMATCH-REFUSED] [check-pack-install] pi-durable L3: an installed tree whose pi-durable binds pi-codemode 1.3.0 must be refused by name as pi-durable-sdk-mismatch (rc=$rc): $out"
|
|
4314
4462
|
return 1
|
|
4315
4463
|
fi
|
|
4316
4464
|
rc=0; out=$(cd "$box" && node --input-type=module -e "import { pathToFileURL } from 'node:url'; await import('$pkg/pi/pi-durable/carrier-resolver.mjs'); const m = await import(pathToFileURL('$pkg/pi/pi-durable/carrier/runtime.js').href); console.log(typeof m.openDurable);" 2>&1) || rc=$?
|
|
@@ -4515,6 +4663,7 @@ pack_install_sentinel_untouched() {
|
|
|
4515
4663
|
|
|
4516
4664
|
_check_pack_install_impl() {
|
|
4517
4665
|
check_pack_pin_matcher || return 1
|
|
4666
|
+
check_pack_argv_matcher || return 1
|
|
4518
4667
|
check_pack_consumer_roots || return 1
|
|
4519
4668
|
|
|
4520
4669
|
# Heavy publish gate. Runs the remaining three checks in #13's
|
|
@@ -4835,19 +4984,21 @@ _check_pack_install_impl() {
|
|
|
4835
4984
|
# `[측정 2026-10-16]` at 1.3.0 the constellation is unchanged: the installed manifests give the
|
|
4836
4985
|
# same member edges as at 1.2.0, now every one exact 1.3.0 (upstream #10865), and the consumer
|
|
4837
4986
|
# oracle walked 10 member edges with 0 mismatches (.tmp-verify/145-stage1/08-pack-install.log).
|
|
4838
|
-
|
|
4987
|
+
# `[측정 2026-10-22]` at 1.4.0 the nine members are again exact 1.4.0 edges (registry manifests; #148 S0),
|
|
4988
|
+
# and pi-tui 1.4.0 adds one third-party dependency (marked-cjk-friendly 0.1.2) outside the closure.
|
|
4989
|
+
echo "[check-pack-install] pnpm add into $tmp (with the aligned 1.4.x SDK + chord + codemode + mcp + durable + typebox)"
|
|
4839
4990
|
local install_log
|
|
4840
4991
|
install_log=$(cd "$tmp" && pnpm add \
|
|
4841
4992
|
"$tgz_path" \
|
|
4842
|
-
"@earendil-works/pi-ai@1.
|
|
4843
|
-
"@earendil-works/pi-coding-agent@1.
|
|
4844
|
-
"@earendil-works/pi-tui@1.
|
|
4845
|
-
"@earendil-works/pi-agent-core@1.
|
|
4846
|
-
"@earendil-works/pi-telemetry@1.
|
|
4847
|
-
"@earendil-works/chord@1.
|
|
4848
|
-
"@earendil-works/pi-codemode@1.
|
|
4849
|
-
"@earendil-works/pi-mcp@1.
|
|
4850
|
-
"@earendil-works/pi-durable@1.
|
|
4993
|
+
"@earendil-works/pi-ai@1.4.0" \
|
|
4994
|
+
"@earendil-works/pi-coding-agent@1.4.0" \
|
|
4995
|
+
"@earendil-works/pi-tui@1.4.0" \
|
|
4996
|
+
"@earendil-works/pi-agent-core@1.4.0" \
|
|
4997
|
+
"@earendil-works/pi-telemetry@1.4.0" \
|
|
4998
|
+
"@earendil-works/chord@1.4.0" \
|
|
4999
|
+
"@earendil-works/pi-codemode@1.4.0" \
|
|
5000
|
+
"@earendil-works/pi-mcp@1.4.0" \
|
|
5001
|
+
"@earendil-works/pi-durable@1.4.0" \
|
|
4851
5002
|
"typebox@latest" \
|
|
4852
5003
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
4853
5004
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -4863,11 +5014,11 @@ _check_pack_install_impl() {
|
|
|
4863
5014
|
local leaked_pi
|
|
4864
5015
|
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | pack_install_leaked_pi)
|
|
4865
5016
|
if [ -n "$leaked_pi" ]; then
|
|
4866
|
-
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.
|
|
5017
|
+
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.4.0):"
|
|
4867
5018
|
printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
|
|
4868
5019
|
return 1
|
|
4869
5020
|
fi
|
|
4870
|
-
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.
|
|
5021
|
+
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.4.0 (chord and pi-durable included)"
|
|
4871
5022
|
|
|
4872
5023
|
# Resolve the installed package.json and confirm pi.extensions
|
|
4873
5024
|
# arrived intact. If pi.extensions is empty or missing, the
|
|
@@ -5921,11 +6072,9 @@ JS
|
|
|
5921
6072
|
return 1
|
|
5922
6073
|
fi
|
|
5923
6074
|
done
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
return 1
|
|
5928
|
-
fi
|
|
6075
|
+
# A refusal on a match whose search cannot read a SIGPIPE as "no leak"; the verdict is the
|
|
6076
|
+
# leaf check-pack-argv-matcher drives.
|
|
6077
|
+
pack_install_refuse_argv_leak copilot "$op_out" 'ARG<copilot>' || return 1
|
|
5929
6078
|
echo "[check-pack-install] installed 'entwurf copilot' reached the vendor with the scan flag and the managed argv"
|
|
5930
6079
|
|
|
5931
6080
|
# #95 — the managed app-server SPELLING, from the INSTALLED package. Same packaging risk as
|
|
@@ -5972,11 +6121,7 @@ process.stdout.write(resolveCodexDefaultSocketPath(process.env));
|
|
|
5972
6121
|
return 1
|
|
5973
6122
|
fi
|
|
5974
6123
|
done
|
|
5975
|
-
|
|
5976
|
-
fail "[check-pack-install] installed 'entwurf codex-app-server' leaked the dispatcher verb into the vendor's argv:"
|
|
5977
|
-
echo "$op_out" | tail -8 | sed 's/^/ /' >&2
|
|
5978
|
-
return 1
|
|
5979
|
-
fi
|
|
6124
|
+
pack_install_refuse_argv_leak codex-app-server "$op_out" 'ARG<codex-app-server>' || return 1
|
|
5980
6125
|
echo "[check-pack-install] installed 'entwurf codex-app-server' reached the vendor at the INSTALLED resolver's address ($cx_want)"
|
|
5981
6126
|
|
|
5982
6127
|
# The generation verb must reach its verdict from under node_modules. On the
|
|
@@ -6623,7 +6768,11 @@ setup_all() {
|
|
|
6623
6768
|
else
|
|
6624
6769
|
bins_rc=0; expose_dev_bin || bins_rc=$?
|
|
6625
6770
|
if [ "$bins_rc" -eq 0 ]; then
|
|
6626
|
-
setup_result bins PASS "source operator + helper bins exposed and certified
|
|
6771
|
+
setup_result bins PASS "source operator + helper bins exposed and certified; no other root in this PATH or the npm/pnpm global bin dir (other shells not covered)"
|
|
6772
|
+
elif [ "$bins_rc" -eq 5 ]; then
|
|
6773
|
+
setup_result bins FAIL "another entwurf root is still selectable (named above; nothing removed) — remove it, then re-run setup"
|
|
6774
|
+
elif [ "$bins_rc" -eq 6 ]; then
|
|
6775
|
+
setup_result bins FAIL "the package manifest or a package manager's global bin dir could not be inspected (named above) — refused, not read as clean"
|
|
6627
6776
|
elif [ "$bins_rc" -eq 3 ]; then
|
|
6628
6777
|
setup_result bins FAIL "foreign helper bin(s) refused (named above; every unit was attempted) — repair them, then re-run setup"
|
|
6629
6778
|
else
|
|
@@ -7012,7 +7161,13 @@ expose_dev_bin() {
|
|
|
7012
7161
|
return 1
|
|
7013
7162
|
fi
|
|
7014
7163
|
|
|
7015
|
-
|
|
7164
|
+
# A certified winner is not yet a developer install: a later PATH entry or a package manager's
|
|
7165
|
+
# global bin dir may still hold another root under the same names, which a shell with another
|
|
7166
|
+
# PATH order (non-interactive SSH) selects. exclusive names it (5) or refuses an uninspectable
|
|
7167
|
+
# package manifest or package manager (6); nothing is removed.
|
|
7168
|
+
local ex_rc=0
|
|
7169
|
+
bash "$REPO_DIR/scripts/dev-bin.sh" exclusive || ex_rc=$?
|
|
7170
|
+
[ "$rc" -eq 0 ] && return "$ex_rc"
|
|
7016
7171
|
if [ "$rc" -eq 3 ]; then
|
|
7017
7172
|
echo "[setup] dev-bin: foreign helper bin path(s) refused, never clobbered — the refused names are in the summary above." >&2
|
|
7018
7173
|
echo "[setup] Every unit was attempted independently; the source operator itself is certified." >&2
|
|
@@ -7576,6 +7731,12 @@ case "$cmd" in
|
|
|
7576
7731
|
check-entwurf-v2-native-push)
|
|
7577
7732
|
check_entwurf_v2_native_push
|
|
7578
7733
|
;;
|
|
7734
|
+
check-native-push-paused)
|
|
7735
|
+
check_native_push_paused
|
|
7736
|
+
;;
|
|
7737
|
+
check-chain-terminus-publication)
|
|
7738
|
+
check_chain_terminus_publication
|
|
7739
|
+
;;
|
|
7579
7740
|
check-entwurf-control-rpc)
|
|
7580
7741
|
check_entwurf_control_rpc
|
|
7581
7742
|
;;
|
|
@@ -7630,6 +7791,9 @@ case "$cmd" in
|
|
|
7630
7791
|
check-pi-durable-native-module)
|
|
7631
7792
|
check_pi_durable_native_module
|
|
7632
7793
|
;;
|
|
7794
|
+
check-remote-pair-beside)
|
|
7795
|
+
check_remote_pair_beside
|
|
7796
|
+
;;
|
|
7633
7797
|
check-mux-resume-call)
|
|
7634
7798
|
check_mux_resume_call
|
|
7635
7799
|
;;
|
|
@@ -7976,12 +8140,14 @@ case "$cmd" in
|
|
|
7976
8140
|
(cd "$REPO_DIR" && bash scripts/smoke-pi-provider-state.sh)
|
|
7977
8141
|
;;
|
|
7978
8142
|
smoke-agy-native-push-live)
|
|
7979
|
-
#
|
|
7980
|
-
#
|
|
7981
|
-
#
|
|
7982
|
-
#
|
|
7983
|
-
#
|
|
7984
|
-
#
|
|
8143
|
+
# PAUSED (#152): the script exits 2 [entwurf:paused] before it reads LIVE or
|
|
8144
|
+
# AGY_CONVERSATION_ID — not a PASS and not a SKIP. The body after that exit is the 봉인 8
|
|
8145
|
+
# LIVE acceptance for the native-push (agy) rail and runs only once a separate change lifts
|
|
8146
|
+
# the pause: REAL antigravity adapter + register core + runEntwurfV2 (production deps)
|
|
8147
|
+
# against a live agy conversation (probe route, register create/attach idempotency,
|
|
8148
|
+
# fire→native-push delivered, bogus-conv probe-indeterminate reject), meta-store isolated
|
|
8149
|
+
# to a temp dir, honest SKIP when LIVE!=1, doctor-static preflight FAIL before the agy
|
|
8150
|
+
# bridge is wired (③).
|
|
7985
8151
|
run_ts scripts/smoke-agy-native-push-live.ts
|
|
7986
8152
|
;;
|
|
7987
8153
|
smoke-codex-native-push-live)
|
|
@@ -8517,8 +8683,8 @@ case "$cmd" in
|
|
|
8517
8683
|
run_ts scripts/check-remote-pair-installed.ts "$@"
|
|
8518
8684
|
;;
|
|
8519
8685
|
remote-pair-receive)
|
|
8520
|
-
# #107 rail 1: the receiving host's entry for
|
|
8521
|
-
# check runs before the v2 dispatch, so a claim outside
|
|
8686
|
+
# #107 rail 1 / #149: the receiving host's entry for its declared remote pairs. The pair
|
|
8687
|
+
# check runs before the v2 dispatch, so a claim outside every declared pair mutates nothing;
|
|
8522
8688
|
# a match reaches the same record/owner/deliverability checks every local send does.
|
|
8523
8689
|
# Installed, run_ts runs its compiled twin; the sending host's ssh reaches it through the bin.
|
|
8524
8690
|
shift || true
|
|
@@ -8705,6 +8871,9 @@ case "$cmd" in
|
|
|
8705
8871
|
check-pack-pin-matcher)
|
|
8706
8872
|
check_pack_pin_matcher
|
|
8707
8873
|
;;
|
|
8874
|
+
check-pack-argv-matcher)
|
|
8875
|
+
check_pack_argv_matcher
|
|
8876
|
+
;;
|
|
8708
8877
|
check-pack-win32-carrier)
|
|
8709
8878
|
check_pack_win32_carrier
|
|
8710
8879
|
;;
|
|
@@ -442,7 +442,7 @@ try {
|
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
ok(
|
|
445
|
-
"antigravity
|
|
445
|
+
"antigravity stays a native-push backend (its reply rail is native-push; while #152 pauses it, that rail answers replyable:false by policy)",
|
|
446
446
|
nativePushSupported("antigravity"),
|
|
447
447
|
);
|
|
448
448
|
ok(
|
|
@@ -455,10 +455,12 @@ try {
|
|
|
455
455
|
// probe can only be a broken registry or a probe that could not run at all. Folding that into
|
|
456
456
|
// replyable:false would tell the receiver a lie about this sender AND bury the defect — the
|
|
457
457
|
// exact Crash-Don't-Warn shape this lane exists to remove. It must propagate.
|
|
458
|
+
// The mapping is exercised on codex, the native-push backend that is not paused: antigravity is
|
|
459
|
+
// paused (#152) and answers false by policy without resolving an adapter (paused.test.ts).
|
|
458
460
|
{
|
|
459
461
|
const identity: Pick<MetaIdentity, "backend" | "nativeSessionId"> = {
|
|
460
|
-
backend: "
|
|
461
|
-
nativeSessionId: "
|
|
462
|
+
backend: "codex",
|
|
463
|
+
nativeSessionId: "thread-x",
|
|
462
464
|
};
|
|
463
465
|
const adapterWith = (probe: NativePushAdapter["probe"]) => ({ resolveAdapter: () => ({ probe }) });
|
|
464
466
|
|
|
@@ -466,7 +468,7 @@ try {
|
|
|
466
468
|
"probe alive → replyable true",
|
|
467
469
|
(await probeNativeSenderAlive(
|
|
468
470
|
identity,
|
|
469
|
-
adapterWith(async () => ({ status: "alive", route: { backend: "
|
|
471
|
+
adapterWith(async () => ({ status: "alive", route: { backend: "codex", socketPath: "/tmp/gate-codex.sock" } })),
|
|
470
472
|
)) === true,
|
|
471
473
|
);
|
|
472
474
|
|
|
@@ -112,7 +112,7 @@ function row(facts: SelfAddressabilityFacts): { replyable: boolean; socketState:
|
|
|
112
112
|
ok("meta/self-fetch + record but undefined owner/watch → fail-closed NOT replyable", partial.replyable === false);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
// meta-session / NATIVE-PUSH rail (antigravity): a SEPARATE axis — recordBacked ∧ probeAlive.
|
|
115
|
+
// meta-session / NATIVE-PUSH rail (Codex; antigravity is paused, #152): a SEPARATE axis — recordBacked ∧ probeAlive.
|
|
116
116
|
// The two rails must not be able to borrow each other's facts (보정①): a mailbox signal
|
|
117
117
|
// deciding an agy reply, or a probe deciding a Claude reply, is a category error.
|
|
118
118
|
{
|
|
@@ -124,8 +124,8 @@ function row(facts: SelfAddressabilityFacts): { replyable: boolean; socketState:
|
|
|
124
124
|
const reachable = row(push({ recordBacked: true, probeAlive: true }));
|
|
125
125
|
ok("meta/native-push + record + probe-alive → replyable", reachable.replyable === true);
|
|
126
126
|
|
|
127
|
-
// THE ROW THIS RAIL EXISTS FOR:
|
|
128
|
-
// self-fetch atom it would be un-replyable forever; on its own rail it is reachable.
|
|
127
|
+
// THE ROW THIS RAIL EXISTS FOR: a native-push citizen never arms a mailbox watch. Under
|
|
128
|
+
// the self-fetch atom it would be un-replyable forever; on its own rail it is reachable.
|
|
129
129
|
ok(
|
|
130
130
|
"meta/native-push + record + probe-alive + watch NEVER armed → STILL replyable (no mailbox axis leak)",
|
|
131
131
|
row(push({ recordBacked: true, probeAlive: true, watchArmed: false })).replyable === true,
|
|
@@ -156,6 +156,37 @@ function row(facts: SelfAddressabilityFacts): { replyable: boolean; socketState:
|
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
// #152 policy row: a PAUSED native-push backend is decided BEFORE the pure record+probe
|
|
160
|
+
// predicate. Record-backed + paused → not replyable with a reason naming the pause, even if
|
|
161
|
+
// a probe fact says alive (none ran for this answer). The record axis keeps precedence: a
|
|
162
|
+
// record-less citizen keeps its own reason and is never relabelled as paused.
|
|
163
|
+
{
|
|
164
|
+
const paused = computeSelfAddressability({
|
|
165
|
+
origin: "meta-session",
|
|
166
|
+
metaDeliveryDomain: "native-push",
|
|
167
|
+
recordBacked: true,
|
|
168
|
+
probeAlive: true,
|
|
169
|
+
nativePushPaused: true,
|
|
170
|
+
});
|
|
171
|
+
ok(
|
|
172
|
+
"meta/native-push + record + PAUSED (#152) → NOT replyable, socket none",
|
|
173
|
+
paused.replyable === false && paused.socketState === "none",
|
|
174
|
+
);
|
|
175
|
+
ok("meta/native-push + record + PAUSED (#152) → the reason names the pause", /paused \(#152\)/.test(paused.reason));
|
|
176
|
+
const recordless = computeSelfAddressability({
|
|
177
|
+
origin: "meta-session",
|
|
178
|
+
metaDeliveryDomain: "native-push",
|
|
179
|
+
recordBacked: false,
|
|
180
|
+
nativePushPaused: true,
|
|
181
|
+
});
|
|
182
|
+
ok(
|
|
183
|
+
"meta/native-push + NO record + paused → the record-less reason wins (pause never masks it)",
|
|
184
|
+
recordless.replyable === false &&
|
|
185
|
+
/no backing meta-record/.test(recordless.reason) &&
|
|
186
|
+
!/paused/.test(recordless.reason),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
159
190
|
// meta-session / NONE rail: no inbound transport at all. Mailbox facts and a live probe
|
|
160
191
|
// cannot buy replyability — there is nothing to land on. Distinct from the unsupplied
|
|
161
192
|
// (undefined) domain row below, which stays fail-closed for a caller that forgot the axis.
|