@junghanacs/entwurf 0.41.1 → 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.
Files changed (82) hide show
  1. package/AGENTS.md +1 -1
  2. package/BASELINE.md +7 -5
  3. package/CHANGELOG.md +185 -0
  4. package/DELIVERY.md +37 -20
  5. package/README.md +70 -65
  6. package/VERIFY.md +9 -9
  7. package/docs/external-mcp-host.md +1 -1
  8. package/docs/setup-clean-host.md +59 -33
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +14 -11
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +10 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +23 -2
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +7 -1
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +3 -0
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +21 -10
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +4 -2
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +5 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +6 -4
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +13 -2
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +2 -2
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +1 -1
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-receive.js +25 -17
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-send.js +94 -28
  23. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +57 -7
  24. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +2 -2
  25. package/mcp/entwurf-bridge/dist/scripts/remote-pair-receive.js +12 -12
  26. package/mcp/entwurf-bridge/src/index.ts +14 -11
  27. package/native/win32-x64/entwurf_win.node +0 -0
  28. package/native/win32-x64/manifest.json +2 -2
  29. package/package.json +4 -4
  30. package/pi-extensions/lib/entwurf-self-address.ts +13 -0
  31. package/pi-extensions/lib/entwurf-v2-contract.ts +25 -2
  32. package/pi-extensions/lib/entwurf-v2-decider.ts +7 -0
  33. package/pi-extensions/lib/entwurf-v2-surface.ts +3 -0
  34. package/pi-extensions/lib/fresh-call-composition.ts +21 -10
  35. package/pi-extensions/lib/herdr-fresh-call.ts +4 -2
  36. package/pi-extensions/lib/meta-sender-identity.ts +4 -0
  37. package/pi-extensions/lib/mux-fresh-call.ts +6 -4
  38. package/pi-extensions/lib/native-push/register.ts +17 -2
  39. package/pi-extensions/lib/omp-fresh-preflight.ts +2 -2
  40. package/pi-extensions/lib/pi-durable-fresh-preflight.ts +1 -1
  41. package/pi-extensions/lib/remote-pair-receive.ts +27 -19
  42. package/pi-extensions/lib/remote-pair-send.ts +117 -30
  43. package/pi-extensions/meta-bridge-omp.ts +69 -7
  44. package/pi-extensions/meta-bridge-pi-durable.ts +2 -2
  45. package/run.sh +173 -22
  46. package/scripts/check-agy-sender-identity.ts +6 -4
  47. package/scripts/check-entwurf-self-address.ts +34 -3
  48. package/scripts/check-entwurf-v2-contract.ts +24 -2
  49. package/scripts/check-entwurf-v2-production.ts +45 -31
  50. package/scripts/check-gate-qualification.ts +10 -8
  51. package/scripts/check-native-push-adapter.ts +4 -0
  52. package/scripts/check-native-push-register.ts +32 -82
  53. package/scripts/check-remote-pair-installed.ts +2 -2
  54. package/scripts/dev-bin.sh +112 -1
  55. package/scripts/lib/chain-terminus-publication.ts +58 -0
  56. package/scripts/lib/codex-fresh-live-protocol.ts +30 -0
  57. package/scripts/lib/codex-fresh-source-receipts.ts +112 -3
  58. package/scripts/lib/pi-durable-fresh-live-receipts.ts +29 -1
  59. package/scripts/mutants/chain-terminus-publication.json +17 -0
  60. package/scripts/mutants/codex-native.json +98 -0
  61. package/scripts/mutants/control-send-receipt.json +2 -2
  62. package/scripts/mutants/mux-fresh-call.json +16 -1
  63. package/scripts/mutants/native-push-paused.json +17 -0
  64. package/scripts/mutants/omp-fresh.json +13 -2
  65. package/scripts/mutants/pack-install.json +46 -0
  66. package/scripts/mutants/remote-pair-display.json +3 -3
  67. package/scripts/mutants/remote-pair-receive.json +41 -11
  68. package/scripts/mutants/remote-pair-roundtrip.json +67 -7
  69. package/scripts/mutants/remote-pair-send.json +156 -17
  70. package/scripts/mutants/remote-pair-transport.json +4 -4
  71. package/scripts/mutants/source-install.json +66 -0
  72. package/scripts/remote-pair-receive.ts +12 -12
  73. package/scripts/smoke-agy-install-state.sh +121 -0
  74. package/scripts/smoke-agy-native-push-live.ts +13 -0
  75. package/scripts/smoke-codex-fresh-live.ts +50 -27
  76. package/scripts/smoke-entwurf-chain-live.ts +7 -9
  77. package/scripts/smoke-herdr-fresh-call-live.ts +4 -4
  78. package/scripts/smoke-herdr-plugin-build-live.ts +179 -50
  79. package/scripts/smoke-mux-lifecycle-live.ts +140 -8
  80. package/scripts/smoke-omp-fresh-live.ts +5 -4
  81. package/scripts/smoke-pi-durable-fresh-live.ts +29 -7
  82. 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 # 봉인 8 LIVE acceptance for the native-push (agy) rail — OUT of pnpm check, needs LIVE=1 + AGY_CONVERSATION_ID (a live agy conversation). Drives the REAL antigravity adapter + register core + runEntwurfV2 (production deps): doctor-static preflight (dangling→FAIL, the ③ gate), probe route, register create/attach idempotency, fire→native-push delivered, post-send re-probe (D7 partial), bogus-conv→native-push-probe-indeterminate. Meta-store isolated to a temp dir (only the agy round-trip is real; no real-store residue). COST FENCE: open that agy conversation on gemini-3.6-flash (free account) — never a Pro tier; entwurf never selects the agy model and no assertion reads it. LIVE=1 AGY_CONVERSATION_ID=<convId> ./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
@@ -4215,6 +4247,106 @@ check_pack_pin_matcher() {
4215
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)"
4216
4248
  }
4217
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
+
4218
4350
  # #130 — the pi-durable carrier proved on ACTUAL npm consumers of the candidate tarball.
4219
4351
  # $1 tarball $2 the gate's npm sandbox $3 an existing Entwurf-only npm consumer root inside it.
4220
4352
  # Cells: L1s (Entwurf alone, $3), L1 (project-local beside an aligned host pi-coding-agent at the
@@ -4531,6 +4663,7 @@ pack_install_sentinel_untouched() {
4531
4663
 
4532
4664
  _check_pack_install_impl() {
4533
4665
  check_pack_pin_matcher || return 1
4666
+ check_pack_argv_matcher || return 1
4534
4667
  check_pack_consumer_roots || return 1
4535
4668
 
4536
4669
  # Heavy publish gate. Runs the remaining three checks in #13's
@@ -5939,11 +6072,9 @@ JS
5939
6072
  return 1
5940
6073
  fi
5941
6074
  done
5942
- if printf '%s' "$op_out" | grep -qF 'ARG<copilot>'; then
5943
- fail "[check-pack-install] installed 'entwurf copilot' leaked the dispatcher verb into the vendor's argv:"
5944
- echo "$op_out" | tail -8 | sed 's/^/ /' >&2
5945
- return 1
5946
- 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
5947
6078
  echo "[check-pack-install] installed 'entwurf copilot' reached the vendor with the scan flag and the managed argv"
5948
6079
 
5949
6080
  # #95 — the managed app-server SPELLING, from the INSTALLED package. Same packaging risk as
@@ -5990,11 +6121,7 @@ process.stdout.write(resolveCodexDefaultSocketPath(process.env));
5990
6121
  return 1
5991
6122
  fi
5992
6123
  done
5993
- if printf '%s' "$op_out" | grep -qF 'ARG<codex-app-server>'; then
5994
- fail "[check-pack-install] installed 'entwurf codex-app-server' leaked the dispatcher verb into the vendor's argv:"
5995
- echo "$op_out" | tail -8 | sed 's/^/ /' >&2
5996
- return 1
5997
- fi
6124
+ pack_install_refuse_argv_leak codex-app-server "$op_out" 'ARG<codex-app-server>' || return 1
5998
6125
  echo "[check-pack-install] installed 'entwurf codex-app-server' reached the vendor at the INSTALLED resolver's address ($cx_want)"
5999
6126
 
6000
6127
  # The generation verb must reach its verdict from under node_modules. On the
@@ -6641,7 +6768,11 @@ setup_all() {
6641
6768
  else
6642
6769
  bins_rc=0; expose_dev_bin || bins_rc=$?
6643
6770
  if [ "$bins_rc" -eq 0 ]; then
6644
- setup_result bins PASS "source operator + helper bins exposed and certified (PATH winner: this checkout)"
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"
6645
6776
  elif [ "$bins_rc" -eq 3 ]; then
6646
6777
  setup_result bins FAIL "foreign helper bin(s) refused (named above; every unit was attempted) — repair them, then re-run setup"
6647
6778
  else
@@ -7030,7 +7161,13 @@ expose_dev_bin() {
7030
7161
  return 1
7031
7162
  fi
7032
7163
 
7033
- [ "$rc" -eq 0 ] && return 0
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"
7034
7171
  if [ "$rc" -eq 3 ]; then
7035
7172
  echo "[setup] dev-bin: foreign helper bin path(s) refused, never clobbered — the refused names are in the summary above." >&2
7036
7173
  echo "[setup] Every unit was attempted independently; the source operator itself is certified." >&2
@@ -7594,6 +7731,12 @@ case "$cmd" in
7594
7731
  check-entwurf-v2-native-push)
7595
7732
  check_entwurf_v2_native_push
7596
7733
  ;;
7734
+ check-native-push-paused)
7735
+ check_native_push_paused
7736
+ ;;
7737
+ check-chain-terminus-publication)
7738
+ check_chain_terminus_publication
7739
+ ;;
7597
7740
  check-entwurf-control-rpc)
7598
7741
  check_entwurf_control_rpc
7599
7742
  ;;
@@ -7648,6 +7791,9 @@ case "$cmd" in
7648
7791
  check-pi-durable-native-module)
7649
7792
  check_pi_durable_native_module
7650
7793
  ;;
7794
+ check-remote-pair-beside)
7795
+ check_remote_pair_beside
7796
+ ;;
7651
7797
  check-mux-resume-call)
7652
7798
  check_mux_resume_call
7653
7799
  ;;
@@ -7994,12 +8140,14 @@ case "$cmd" in
7994
8140
  (cd "$REPO_DIR" && bash scripts/smoke-pi-provider-state.sh)
7995
8141
  ;;
7996
8142
  smoke-agy-native-push-live)
7997
- # 봉인 8 LIVE acceptance gate for the native-push (agy) delivery rail. Drives the REAL
7998
- # antigravity adapter + register core + runEntwurfV2 (production deps) against a live agy
7999
- # conversation (AGY_CONVERSATION_ID): probe route, register create/attach idempotency,
8000
- # fire→native-push delivered, bogus-conv probe-indeterminate reject.
8001
- # Meta-store is isolated to a temp dir (only the agy round-trip is real); honest SKIP when
8002
- # LIVE!=1. doctor-static preflight FAILs before the agy bridge is wired (③).
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 (③).
8003
8151
  run_ts scripts/smoke-agy-native-push-live.ts
8004
8152
  ;;
8005
8153
  smoke-codex-native-push-live)
@@ -8535,8 +8683,8 @@ case "$cmd" in
8535
8683
  run_ts scripts/check-remote-pair-installed.ts "$@"
8536
8684
  ;;
8537
8685
  remote-pair-receive)
8538
- # #107 rail 1: the receiving host's entry for one declared remote pair. The pair
8539
- # check runs before the v2 dispatch, so a claim outside the pair mutates nothing;
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;
8540
8688
  # a match reaches the same record/owner/deliverability checks every local send does.
8541
8689
  # Installed, run_ts runs its compiled twin; the sending host's ssh reaches it through the bin.
8542
8690
  shift || true
@@ -8723,6 +8871,9 @@ case "$cmd" in
8723
8871
  check-pack-pin-matcher)
8724
8872
  check_pack_pin_matcher
8725
8873
  ;;
8874
+ check-pack-argv-matcher)
8875
+ check_pack_argv_matcher
8876
+ ;;
8726
8877
  check-pack-win32-carrier)
8727
8878
  check_pack_win32_carrier
8728
8879
  ;;
@@ -442,7 +442,7 @@ try {
442
442
  }
443
443
 
444
444
  ok(
445
- "antigravity is a native-push backend → its replyable comes from the adapter probe",
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: "antigravity",
461
- nativeSessionId: "conv-x",
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: "antigravity", lsAddress: "127.0.0.1:1" } })),
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: an agy citizen never arms a mailbox watch. Under the
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.
@@ -430,9 +430,9 @@ ok(
430
430
  // cannot enforce it — these semantic fixtures (the SSOT predicate the 5b decider
431
431
  // mints against) do.
432
432
  eq(
433
- "?6: PRE_PROBE_REJECT_REASONS = bad-target/target-locked/target-address-conflict/record-less-socket",
433
+ "?6: PRE_PROBE_REJECT_REASONS = bad-target/target-locked/target-address-conflict/record-less-socket/native-push-paused",
434
434
  [...PRE_PROBE_REJECT_REASONS],
435
- ["bad-target", "target-locked", "target-address-conflict", "record-less-socket"],
435
+ ["bad-target", "target-locked", "target-address-conflict", "record-less-socket", "native-push-paused"],
436
436
  );
437
437
  // the partition is exhaustive + disjoint: every reject reason is pre-probe XOR not.
438
438
  for (const r of ENTWURF_V2_REJECT_REASONS) {
@@ -467,6 +467,28 @@ ok(
467
467
  "taxonomy: record-less-socket is NOT a resolver reason (target-resolution stage, not a table cell)",
468
468
  !(RESOLVER_REJECT_REASONS as readonly string[]).includes("record-less-socket"),
469
469
  );
470
+
471
+ // #152: native-push-paused — a native-push backend paused by policy (antigravity: its LS
472
+ // refused entwurf's measured external agentapi calls for a missing CSRF token). The decider refuses it BEFORE
473
+ // any adapter probe, so it is pre-probe (null liveness), never a resolver table cell and
474
+ // never one of the post-probe native-push outcomes it must not impersonate (dead /
475
+ // indeterminate).
476
+ ok(
477
+ "taxonomy: native-push-paused is in the enum (#152)",
478
+ (ENTWURF_V2_REJECT_REASONS as readonly string[]).includes("native-push-paused"),
479
+ );
480
+ ok(
481
+ "?6: native-push-paused is pre-probe (#152 — refused before any adapter probe)",
482
+ isPreProbeReject("native-push-paused"),
483
+ );
484
+ ok(
485
+ "taxonomy: native-push-paused is NOT a resolver reason (#152)",
486
+ !(RESOLVER_REJECT_REASONS as readonly string[]).includes("native-push-paused"),
487
+ );
488
+ ok(
489
+ "taxonomy: native-push-paused is NOT a post-probe native-push reject (#152 — not dead, not indeterminate)",
490
+ !(NATIVE_PUSH_REJECT_REASONS as readonly string[]).includes("native-push-paused"),
491
+ );
470
492
  ok(
471
493
  "taxonomy: the retired socket-only-no-resume-authority is GONE from the enum (#50 C4)",
472
494
  !(ENTWURF_V2_REJECT_REASONS as readonly string[]).includes("socket-only-no-resume-authority"),