@junghanacs/entwurf 0.31.0 → 0.32.0

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 (56) hide show
  1. package/AGENTS.md +3 -2
  2. package/CHANGELOG.md +82 -0
  3. package/README.md +46 -36
  4. package/VERIFY.md +35 -16
  5. package/demo/README.md +1 -1
  6. package/docs/acp-backend-rail.md +1 -1
  7. package/docs/setup-clean-host.md +112 -95
  8. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +1 -1
  9. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +1 -1
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +8 -10
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +3 -3
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js +153 -205
  13. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +6 -4
  14. package/mcp/entwurf-bridge/src/index.ts +1 -1
  15. package/package.json +14 -17
  16. package/pi/pi-durable/bootstrap.mjs +142 -19
  17. package/pi/pi-durable/carrier/LICENSE +21 -0
  18. package/pi/pi-durable/carrier/harness-setup.js +123 -0
  19. package/pi/pi-durable/carrier/prompt.js +74 -0
  20. package/pi/pi-durable/carrier/runtime.js +402 -0
  21. package/pi/pi-durable/carrier/sessions.js +56 -0
  22. package/pi/pi-durable/carrier/subagent.js +55 -0
  23. package/pi/pi-durable/carrier/tui.js +655 -0
  24. package/pi/pi-durable/carrier-relocation.mjs +160 -0
  25. package/pi/pi-durable/carrier-resolver.mjs +38 -0
  26. package/pi/pi-durable/overlay/upstream-pin.json +103 -11
  27. package/pi-extensions/lib/fresh-call-composition.ts +1 -1
  28. package/pi-extensions/lib/mux-fresh-call.ts +8 -10
  29. package/pi-extensions/lib/pi-durable-fresh-preflight.ts +3 -3
  30. package/pi-extensions/lib/pi-durable-runtime.ts +197 -263
  31. package/pi-extensions/meta-bridge-pi-durable.ts +11 -7
  32. package/run.sh +508 -235
  33. package/scripts/check-entwurf-bridge-pi-free.ts +7 -5
  34. package/scripts/check-fresh-call-dispatch.ts +1 -1
  35. package/scripts/check-gate-qualification.ts +86 -34
  36. package/scripts/check-herdr-activation.ts +5 -4
  37. package/scripts/check-pi-durable-contact.ts +26 -93
  38. package/scripts/check-pi-durable-receive.ts +22 -59
  39. package/scripts/check-pi-durable-send.ts +235 -75
  40. package/scripts/emit-pi-durable-carrier.ts +355 -0
  41. package/scripts/lib/mutation-qualify.ts +21 -45
  42. package/scripts/lib/pi-durable-operator-guard.ts +89 -0
  43. package/scripts/lib/qualification-receipt.ts +7 -11
  44. package/scripts/mutants/control-send-receipt.json +1 -1
  45. package/scripts/mutants/gate-qualification.json +13 -0
  46. package/scripts/mutants/mux-fresh-call.json +13 -13
  47. package/scripts/mutants/pack-install.json +3 -3
  48. package/scripts/mutants/pi-durable.json +442 -109
  49. package/scripts/mutants/pi-floor.json +24 -2
  50. package/scripts/pi-durable-contact-host.mjs +3 -3
  51. package/scripts/pi-durable-receive-host.mjs +3 -3
  52. package/scripts/pi-durable-send-host.mjs +76 -5
  53. package/scripts/smoke-herdr-raw-install-live.sh +1 -1
  54. package/scripts/smoke-pi-durable-fresh-live.ts +3 -3
  55. package/scripts/smoke-setup-verdict.sh +15 -15
  56. package/scripts/smoke-user-scope-citizen.sh +1 -1
package/run.sh CHANGED
@@ -132,10 +132,10 @@ Usage:
132
132
  ./run.sh check-mailbox-receipt-state # deterministic gate (0.11 Stage 0 step 3B): mailbox receipt state schema + store (stamp→persist→read-back) in a temp mailbox, strict keyset, no API
133
133
  ./run.sh check-copilot-birth-hook # #82 gate: drives the real Copilot assembler into a temp dir, fires the baked launcher with NO ARGV (the way Copilot's `exec`-string schema forces), and requires a backend:"copilot" v3 record + attach + peer row + a SENDER marker the resolver joins back to that record, and still zero mailbox/receiver marker (who-sent needs a shared parent; a receiver needs a doorbell this backend has not got). Hermetic; no Copilot, no model turn
134
134
  ./run.sh check-omp-birth-hook # #87 gate: drives the real OMP assembler into a temp dir, imports the ASSEMBLED index.ts into a MOCK omp host and fires session_start/session_switch. tui mints one backend:"omp" record + a sender marker keyed to the host's OWN pid (the one-process join) + the garden id on the status line; print/rpc/json mint NOTHING (hasUI is true on the rpc rows, as in the vendor); switch attaches on the same native id and mints the replacement on a new one; the CERTIFIED receiver reader still finds no marker. Also the four-root joint binding: extension and omp-labeled bridge child resolve the same sessions/mailbox/senders/receivers bundle against test-built literals (never the production resolver as its own oracle), under a poisoned PI_CODING_AGENT_DIR and under four distinct ENTWURF_META_* overrides; the override grammar is absolute-or-~ and both halves plus the doctor refuse anything else by name; and a drifted provenance label selects no root policy at all. Hermetic; no omp, no model turn
135
- ./run.sh check-pi-durable-contact # #129 L-identity gate, CHECKOUT-ONLY (an installed package refuses it in run_ts). Opens the REAL durable app from a provisioned overlay checkout (ENTWURF_PI_DURABLE_RUNTIME: tracked tree = pin + patch exactly, git-ignored model data = the pin's recorded digest) with the pi-durable contact, births the citizen and runs its tools adapter-direct through a privately emitted branch bridge (ENTWURF_PI_DURABLE_BRIDGE_ENTRY; its registry must match this checkout). Matrix roots {default, explicit} x {fresh, --continue}: one record keyed by the durable session dir, sender marker on the spawned host pid, exactly one bridge child whose /proc PPID is that host, poisoned identity carriers kept from it, its four root carriers bound to the roots written, the receiver ARMED (raw marker owned by the host pid + start key as pi-durable-host, joined to the sender marker; removed on close), self = the record and replyable, peers from an outside bridge, same garden id on reopen; the bundle's compiled owner join must admit pi-durable-host. Reaps only the host/bridges it owns on any failure. Harness-bypassed: no model turn, no ToolTask. Missing inputs → SKIP (97), never a pass
136
- ./run.sh check-pi-durable-send # #129 L-send FIRST CELL, CHECKOUT-ONLY. Same two inputs as check-pi-durable-contact. One native durable turn: the app's own controller input → GenerationTask → ToolTask → the contact's entwurf_v2 → the private bridge → a seeded self-fetch target (C2 recipe, owned by a separate idle child). S = a 127.0.0.1 scripted OpenAI-compatible endpoint configured through the app's documented models.json (dummy key, PI_OFFLINE); H = the native ToolTask path; V (a vendor turn) is NOT run. Oracles: the wire (tools offered, v2 schema = the bridge's tools/list, exactly two requests, the tool result + receipt in the second), the raw mailbox (.msg 1, signal, sender = the host record), the native view (one call, its settled result, root current). Not exactly-once, not recovery, not a recipient turn. Missing inputs → SKIP (97)
137
- ./run.sh check-pi-durable-beside # #129 mutant execution coordinate (VERIFY rule 3): run_vitest over the four pi-durable beside tests (adapter, runtime, preflight, owner join) — the pi-durable qualification lane's gate argv. Same files check-tests-beside-behavior already runs.
138
- ./run.sh check-pi-durable-receive # #129 L-receive FIRST CELL, CHECKOUT-ONLY. Same two inputs (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)
135
+ ./run.sh check-pi-durable-contact # #129 L-identity gate, CHECKOUT-ONLY (an installed package refuses it in run_ts). Opens the REAL durable app from THIS checkout's verified carrier (pi/pi-durable/carrier/ under its resolver, against the checkout's pinned pi SDK set — refused by name first) with the pi-durable contact, births the citizen and runs its tools adapter-direct through a privately emitted branch bridge (ENTWURF_PI_DURABLE_BRIDGE_ENTRY; its registry must match this checkout). Matrix roots {default, explicit} x {fresh, --continue}: one record keyed by the durable session dir, sender marker on the spawned host pid, exactly one bridge child whose /proc PPID is that host, poisoned identity carriers kept from it, its four root carriers bound to the roots written, the receiver ARMED (raw marker owned by the host pid + start key as pi-durable-host, joined to the sender marker; removed on close), self = the record and replyable, peers from an outside bridge, same garden id on reopen; the bundle's compiled owner join must admit pi-durable-host. Reaps only the host/bridges it owns on any failure. Harness-bypassed: no model turn, no ToolTask. Missing inputs → SKIP (97), never a pass
136
+ ./run.sh check-pi-durable-send # #129 L-send FIRST CELL, CHECKOUT-ONLY. Same input as check-pi-durable-contact. One native durable turn: the app's own controller input → GenerationTask → ToolTask → the contact's entwurf_v2 → the private bridge → a seeded self-fetch target (C2 recipe, owned by a separate idle child). S = a 127.0.0.1 scripted OpenAI-compatible endpoint configured through the app's documented models.json (dummy key, PI_OFFLINE); H = the native ToolTask path; V (a vendor turn) is NOT run. Oracles: the wire (tools offered, v2 schema = the bridge's tools/list, exactly two requests, the tool result + receipt in the second), the raw mailbox (.msg 1, signal, sender = the host record), the native view (one call, its settled result, root current). Not exactly-once, not recovery, not a recipient turn. Missing inputs → SKIP (97)
137
+ ./run.sh check-pi-durable-beside # #129 mutant execution coordinate (VERIFY rule 3): run_vitest over the five pi-durable beside tests (adapter, carrier/SDK-set verifier, preflight, owner join, carrier relocation/resolver/emitter) — the pi-durable qualification lane's gate argv. Same files check-tests-beside-behavior already runs.
138
+ ./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)
139
139
  ./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
140
140
  ./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
141
141
  ./run.sh check-codex-app-server-launch # #95 gate: the MANAGED app-server launch `entwurf codex-app-server`, driven through its public address against a FAKE VENDOR on a sandbox PATH. The injected `app-server --listen unix://<socket>` required to equal the product's own resolveCodexDefaultSocketPath over an env matrix that includes the inputs a bash transcription was MEASURED to diverge on (BOM-only CODEX_HOME, trailing slash, `..`), non-absolute and control-character addresses refused before any write, byte-identical operator argv, exec (not fork) parent identity, exit passthrough, live-socket and indeterminate-socket and second---listen and recursion refusals, dead-socket launch-over, the tmux fact line, and both identity carriers stripped. Hermetic; no Codex, no app-server, no model turn
@@ -226,7 +226,7 @@ Usage:
226
226
  ./run.sh uninstall-meta-bridge # 1.0.0 meta-bridge Phase 2: stateful GLOBAL uninstall (restore only keys/items captured in install-state)
227
227
  ./run.sh doctor-meta-bridge # THE RELEASE ORACLE (#51, Linux-certified repair axis). exit 0 = every required layer was MEASURED on this Linux host: toolchain + state + plugin/MCP + resolved-artifact launch-form classification (all 3 owner hooks + doorbell static contract) + synthetic owner join + store scan + hook errors + SessionStart evidence + REQUIRED live MCP↔marker join + writer-version parity. Missing live evidence is NOT CERTIFIED (open a Claude session and re-run), never a pass; Darwin is NOT CERTIFIED and stays nonzero, on ONE narrowed reason — start-key and ppid are portable there (`ps` fallback, same string the TS core mints), so what holds the lane closed is per-process environment DISCOVERY alone, pending physical-host evidence. Detection power is held by check-meta-doctor-oracle
228
228
  ./run.sh copilot [args...] # #82 RAIL 7: the MANAGED Copilot launch. exec()s the vendor CLI in THIS terminal (cwd/pid/exit preserved) with COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS set for that one invocation — entwurf owns no part of your shell and writes nothing to it, but it owns the process it is about to become. Without that flag Copilot skips the extension scan SILENTLY. Refuses to launch unless the receiver unit is actually installed. Injects `--model auto` when no --model was given and `--yolo` when no explicit permission/surface policy flag was given, both BEFORE any `--`; every argument you pass is forwarded byte-identical. RUNNING THIS IS YOUR CONSENT to that profile — use plain `copilot` for stock vendor behaviour. Not tmux, not fresh-call, mints no citizen (birth is still the first prompt)
229
- ./run.sh pi-durable [args...] # #129: the MANAGED durable launch. Locates the operator-provided durable runtime at its ONE fixed place ($XDG_DATA_HOME/entwurf/pi-durable/runtime, else ~/.local/share/...), refuses by name unless it is the packaged pin (HEAD, exact overlay patch, no untracked file, pinned model data), then exec()s node under THAT runtime's source resolver with the packaged bootstrap (pi/pi-durable/bootstrap.mjs) in this terminal. A new session needs --provider <p> --model <exact catalog id> --width task-wide [--entwurf-bootstrap <{v:2,task}>]; --continue takes none of them. Entwurf never installs, repairs or moves the runtime
229
+ ./run.sh pi-durable [args...] # #129/#130: the MANAGED durable launch. Verifies this package's pi-durable CARRIER (pi/pi-durable/carrier/, the pinned upstream app emitted by the maintainer) and the pi SDK set it resolves — every declared member/direct edge at exactly the pinned version — refusing by name (package-incomplete / carrier-drift / sdk-absent / sdk-mismatch, exit 3), then exec()s node under the carrier resolver with the packaged bootstrap (pi/pi-durable/bootstrap.mjs) in this terminal. A new session needs --provider <p> --model <exact catalog id> --width task-wide [--entwurf-bootstrap <{v:2,task}>]; --continue takes none of them. Nothing outside the package is located, installed or repaired
230
230
  ./run.sh install-copilot-bridge # #82: GLOBAL install of the Copilot BIRTH plugin (own marketplace root; node+entry baked into the no-argv exec string). MCP wiring and the RECEIVER extension are separate install surfaces (install-copilot-mcp, install-copilot-receive). Also retires the stale Claude unit (--keep-stale-claude-unit opts out)
231
231
  ./run.sh uninstall-copilot-bridge # #86 C3a: honest inverse of install-copilot-bridge from the package-owned install-state (exact qualified id + exact marketplace name/path + recorded assembly only; state deleted LAST; a failing vendor list is UNKNOWN and refuses; never --force, never the stale Claude unit)
232
232
  ./run.sh doctor-copilot-bridge # #82/#86: fail-loud surface for that unit — runtime axis (red = a hook that RAN and failed, or a broken/unbaked artifact; "installed with zero records" is NOT red and is reported as NOT-YET: a Copilot session is born on its FIRST PROMPT, not when the window opens, measured) + ownership axis (install-state shape/binding, marketplace path drift, UNKNOWN vendor lists; legacy no-state install = named non-green, repair = install-copilot-bridge adoption). Either axis red = red
@@ -282,13 +282,13 @@ Usage:
282
282
  ./run.sh peer-facts # #116 M2-a owner-normalized READ-ONLY peer projection: the same listEntwurfFacts provider through the same renderer entwurf_peers uses, emitted as deterministic JSON {schemaVersion:1, storeDir, peers, diagnostics} so a consumer never re-implements the placement join (whose pi half is a measured vendor floor). NOT the same bytes as an entwurf_peers call and deliberately so: that surface is a human listing (observationLimit, text over the wire), this is a machine projection with UNBOUNDED observation, because a rationed row says `unobserved` and a machine cannot tell that from "nobody could look". `placement` stays a STRUCTURED tagged union ({kind:"herdr-pane",paneId} / unobserved / none / ambiguous) — never the human `herdr <pane>` string. Publishes NO socket coordinate (ENTWURF_DIR selects what is PROBED, #50 C4) and NO herdr agent_status / interactive_ready / screen text. One placement read per listing, no watcher. EXIT: 0 readable (diagnostics in-band; missing store = empty), 2 usage, 3 unreadable ([dir])
283
283
  ./run.sh meta-bridge-managed-keys # 0.10.0 meta-bridge: print the SSOT of settings keys entwurf OWNS (consumers read this to stay disjoint — keyset-owner invariant)
284
284
  ./run.sh check-keyset-overlap <fragment.json...> # 0.10.0 meta-bridge: PREVENTIVE keyset guard — fail if a consumer fragment collides with any pi-owned key (cross-repo; not in pnpm check)
285
- ./run.sh check-dep-versions # local deterministic check that the pi pin agrees across package.json (devDeps + peer range), run.sh (peer-install pins), and the baseline docs (AGENTS/README/ROADMAP/setup-clean-host/demo)
285
+ ./run.sh check-dep-versions # local deterministic check that the pi pin agrees across the durable pin's SDK set, package.json (exact production dependencies, no Earendil dev/peer duplicate), run.sh (install pins), the workspace closure and the baseline docs (README/ROADMAP/setup-clean-host/demo/VERIFY/herdr/acp)
286
286
  ./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
287
287
  ./run.sh check-pack # publish gate (dry-run): npm pack --dry-run + tarball invariants (runtime-critical present, dev residue absent)
288
288
  ./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
289
289
  ./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
290
290
  ./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
291
- ./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 peers (pins derived from the package.json devDep; 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
291
+ ./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)
292
292
  ./run.sh check-install-container # 0.12.8 (#51 C): Linux artifact-CONSUMER gate — one candidate .tgz handed read-only to a checkout-invisible node:<engines-major>-bookworm cell. Default packs once to temp; ENTWURF_CANDIDATE_TGZ=/absolute/preserved.tgz consumes those exact bytes with no re-pack and prints canonical path+sha256 for release. Non-root global PATH install, frozen package, MCP tools/list, fake-Claude install-meta-bridge, path+sha256 fence, strict doctor, and the GENERATION host-state matrix (clean / v3-only store bytes unchanged / previous-generation REFUSE→fresh-cut→retry PASS) seeded inline. Docker missing = honest SKIP; ENTWURF_REQUIRE_DOCKER=1 makes that RED (required CI)
293
293
  ./run.sh install [project-dir] # INTERNAL part of `setup` (project .pi/settings.json wiring) + npm-consumer entry — prefer `setup`, don't call directly for dev
294
294
  ./run.sh remove [project-dir] # remove entwurf entries from project .pi/settings.json (project scope only; global user-scope citizen left intact)
@@ -455,17 +455,12 @@ preflight_dep_integrity() {
455
455
  # still catching a pnpm dir-move that left the symlink store dangling
456
456
  # (accessSync follows the link).
457
457
  #
458
- # Probe set = the BUNDLED runtime `dependencies` only. The `@earendil-works/pi-*`
459
- # peer trio is intentionally EXCLUDED, and the reason depends on the lane — the old
460
- # blanket claim ("the pi loader provides that runtime itself") was true for only one
461
- # of them and is corrected here:
462
- # pi-managed install — pi omits peers (--legacy-peer-deps) and its own loader
463
- # supplies the runtime, so the trio is legitimately absent.
464
- # neutral npm/pnpm install — nothing supplies it. The optional peer is simply
465
- # unresolved (entwurf-preflight.ts:51), and the project-trust lane that needs it
466
- # is dead on that host. Excluding the trio from this probe is still right (a hard
467
- # require would reject every consumer install), but it is a KNOWN GAP, not proof
468
- # that the runtime is present by another route.
458
+ # Probe set = the non-Earendil bundled runtime `dependencies` below. The
459
+ # `@earendil-works/*` SDK set has been an exact production dependency since #130
460
+ # (before that it was an optional peer trio this probe could not require), and #130
461
+ # left it out of this probe: its installed integrity — every edge at the exact pin —
462
+ # is the pi-durable carrier verifier's subject (setup's pi-durable row and
463
+ # `entwurf pi-durable`), not a presence probe's.
469
464
  # pi runtime presence/version is covered by check-pi-runtime-version /
470
465
  # check-pi-import-surface, neither of which runs on a consumer host.
471
466
  local probe=(
@@ -725,7 +720,7 @@ install_user_scope() {
725
720
  # scripts/herdr-plugin-activate.mjs → `run.sh install-user-scope --plugin-runtime …`) and had no
726
721
  # version check at all, so a host pi setup would name as FAIL got its citizen written here in
727
722
  # silence. Both doors now tell the same truth, off the SAME derived range — `pi_supported_range`
728
- # reads the package.json devDep pin, so there is one range in the repo and no second parser.
723
+ # reads the pinned SDK generation, so there is one range in the repo and no second parser.
729
724
  #
730
725
  # ABSENT pi is deliberately NOT changed here. This verb is called by an activation that has
731
726
  # already decided pi is one of its backends; inventing a presence verdict at the writer would put
@@ -983,7 +978,7 @@ smoke_pi_durable_fresh_live() {
983
978
  # offering and model are read from its native store via an online node:sqlite backup. Private
984
979
  # tmux server; REAL meta roots (one Pi + one pd minted, asserted); records/transcripts/DB kept.
985
980
  # pi-durable absent from FRESH_CALL_BACKENDS or without a mailbox rail, or LIVE!=1, is a
986
- # protocol SKIP; with LIVE=1 every missing prerequisite (operator runtime, pi, tmux, bridge) FAILs.
981
+ # protocol SKIP; with LIVE=1 every missing prerequisite (a verified carrier, pi, tmux, bridge) FAILs.
987
982
  run_ts scripts/smoke-pi-durable-fresh-live.ts
988
983
  }
989
984
 
@@ -1302,8 +1297,9 @@ check_entwurf_bridge_boot() {
1302
1297
 
1303
1298
  check_entwurf_bridge_pi_free() {
1304
1299
  # 0.12.1 A-gate (static half): the entwurf-bridge MCP server must boot WITHOUT any
1305
- # pi package. entwurf is a harness-neutral npm package; pi is one optional adapter
1306
- # lane, not a boot dependency. Walks the EAGER static value-import closure of
1300
+ # pi package. entwurf is a harness-neutral npm package; pi is one adapter lane, not a
1301
+ # boot dependency — since #130 the pi SDK is installed (the pi-durable carrier's), but
1302
+ # the bridge must still not import it. Walks the EAGER static value-import closure of
1307
1303
  # mcp/entwurf-bridge/src/index.ts and fails if any reachable module statically
1308
1304
  # value-imports @earendil-works/pi-*. Type-only imports and dynamic `await import()`
1309
1305
  # (the intended lazy preflight boundary) are excluded — the runtime boot smoke is the
@@ -1521,10 +1517,12 @@ check_pi_durable_beside() {
1521
1517
  # #129: the pi-durable qualification lane's execution coordinate (VERIFY 「Four rules」 rule 3). It is
1522
1518
  # not a discovery path — check-tests-beside-behavior already finds these files. It exists because the
1523
1519
  # qualification runner re-invokes a gate argv once per mutant, and the narrow filter keeps one mutant
1524
- # from re-running every beside test. The four files are one contact: the adapter and its packaged
1525
- # bootstrap, the runtime locator/verifier (which also reads the three checkout gates as SOURCE), the
1526
- # fresh preflight, and the owner join that admits the durable host.
1527
- run_vitest pi-extensions/meta-bridge-pi-durable.test.ts pi-extensions/lib/pi-durable-runtime.test.ts pi-extensions/lib/pi-durable-fresh-preflight.test.ts pi-extensions/lib/entwurf-deliverability.owner-join.test.ts
1520
+ # from re-running every beside test. The six files are one contact: the adapter and its packaged
1521
+ # bootstrap, the installed carrier/SDK-set verifier (which also reads the three checkout gates as
1522
+ # SOURCE), the fresh preflight, the owner join that admits the durable host, the carrier's
1523
+ # relocation grammar, resolver and maintainer emitter (#130), and the bootstrap's explicit
1524
+ # --native-module ingress (#130 P2).
1525
+ run_vitest pi-extensions/meta-bridge-pi-durable.test.ts pi-extensions/lib/pi-durable-runtime.test.ts pi-extensions/lib/pi-durable-fresh-preflight.test.ts pi-extensions/lib/entwurf-deliverability.owner-join.test.ts pi-extensions/lib/pi-durable-carrier.test.ts pi-extensions/lib/pi-durable-native-module.test.ts
1528
1526
  }
1529
1527
 
1530
1528
  smoke_mux_fresh_call_live() {
@@ -2200,67 +2198,57 @@ assert.equal(geminiBundled, undefined, 'package.json must not bundle @google/gem
2200
2198
  // heredoc (which is indented, so won't match `^...`).
2201
2199
  const runSh = readFileSync('run.sh', 'utf8');
2202
2200
 
2203
- // pi peer/dev alignment (#26 / 0.8.0 dep-alignment gate). The three
2204
- // @earendil-works/pi-* devDeps must pin one identical version, and that
2205
- // version must match the check-pack-install peer-install pins below
2206
- // (`pnpm add @earendil-works/pi-ai@X ...`). Without this, a pi bump could
2207
- // drift package.json devDeps away from the fresh-temp install smoke and
2208
- // the "dependency alignment gate" would not actually verify pi.
2209
- const piAi = pkg.devDependencies?.['@earendil-works/pi-ai'];
2210
- const piCoding = pkg.devDependencies?.['@earendil-works/pi-coding-agent'];
2211
- const piTui = pkg.devDependencies?.['@earendil-works/pi-tui'];
2212
- // #120 P2: pi-agent-core is now DIRECTLY imported by test/pi-queue.oracle.test.ts, which proves
2213
- // what the control-socket receipt says about a receiver's queues. An oracle pinned to a DIFFERENT
2214
- // pi than the one this repo targets would answer honestly about a pi nobody runs, so its exact
2215
- // dev pin moves with the floor or the floor is not a floor.
2216
- const piCore = pkg.devDependencies?.['@earendil-works/pi-agent-core'];
2217
- assert.ok(piAi, 'package.json devDependencies must pin @earendil-works/pi-ai');
2201
+ // pi SDK alignment (#26 / 0.8.0 dep-alignment gate; #130 production set). Since 0.32 the pi SDK is
2202
+ // a PRODUCTION dependency set — the pi-durable carrier runs against it — declared once, exactly, in
2203
+ // pi/pi-durable/overlay/upstream-pin.json (`sdk.members` + `sdk.direct`). package.json must carry
2204
+ // exactly that set in `dependencies`, and no @earendil-works package as a dev, peer or optional
2205
+ // dependency beside it: one name in two dependency classes is install behaviour nothing here has
2206
+ // measured. The members are one SDK generation, and that version is the FLOOR every other surface
2207
+ // below names (the check-pack-install constellation, the workspace closure, the docs) — the host
2208
+ // range `>=<floor> <<major>.<minor+1>` is derived from it, never retyped.
2209
+ const durablePin = JSON.parse(readFileSync('pi/pi-durable/overlay/upstream-pin.json', 'utf8'));
2210
+ const sdkMembers = durablePin.sdk?.members ?? {};
2211
+ const sdkDirect = durablePin.sdk?.direct ?? {};
2212
+ const piAi = sdkMembers['@earendil-works/pi-ai'];
2213
+ assert.ok(/^\d+\.\d+\.\d+$/.test(piAi ?? ''), 'pi/pi-durable/overlay/upstream-pin.json sdk.members must pin @earendil-works/pi-ai exactly');
2214
+ // #120 P2: pi-agent-core is DIRECTLY imported by test/pi-queue.oracle.test.ts, which proves what the
2215
+ // control-socket receipt says about a receiver's queues. An oracle pinned to a DIFFERENT pi than the
2216
+ // one this repo targets would answer honestly about a pi nobody runs, so its exact pin moves with
2217
+ // the floor or the floor is not a floor.
2218
+ const piCore = pkg.dependencies?.['@earendil-works/pi-agent-core'];
2218
2219
  assert.equal(piCore, piAi,
2219
2220
  `[QK:PI-CORE-PIN-TRACKS-FLOOR] @earendil-works/pi-agent-core (${piCore}) must match @earendil-works/pi-ai (${piAi}) — the queue oracle imports it directly to prove what the control-socket receipt claims about a receiver's queues, so a pin that drifts off the floor would answer honestly about a pi nobody here runs`);
2220
- assert.equal(piCoding, piAi,
2221
- `@earendil-works/pi-coding-agent (${piCoding}) must match @earendil-works/pi-ai (${piAi})`);
2222
- assert.equal(piTui, piAi,
2223
- `@earendil-works/pi-tui (${piTui}) must match @earendil-works/pi-ai (${piAi})`);
2221
+ for (const [name, ver] of Object.entries(sdkMembers)) {
2222
+ assert.equal(ver, piAi, `pi/pi-durable/overlay/upstream-pin.json: sdk member ${name}@${ver} is not the one SDK generation ${piAi}`);
2223
+ }
2224
+ for (const [name, ver] of Object.entries({ ...sdkMembers, ...sdkDirect })) {
2225
+ assert.equal(pkg.dependencies?.[name], ver,
2226
+ `[QK:PI-SDK-PRODUCTION-SET] package.json dependencies ${name} (${pkg.dependencies?.[name]}) must be exactly the pinned ${ver} (pi/pi-durable/overlay/upstream-pin.json sdk) — the carrier runs against the package's own production set, not whatever a host provides`);
2227
+ }
2228
+ for (const name of Object.keys(pkg.dependencies ?? {}).filter((n) => n.startsWith('@earendil-works/'))) {
2229
+ assert.ok(name in sdkMembers, `package.json dependencies ${name} is not a declared sdk member — declare it in the pin or remove it`);
2230
+ }
2231
+ for (const field of ['devDependencies', 'peerDependencies', 'optionalDependencies', 'peerDependenciesMeta']) {
2232
+ const dual = Object.keys(pkg[field] ?? {}).filter((n) => n.startsWith('@earendil-works/'));
2233
+ assert.deepEqual(dual, [], `[QK:PI-SDK-NO-DUAL-DECLARATION] package.json ${field} must carry no @earendil-works package beside the production set (found ${dual.join(', ')}) — one name in two dependency classes is install behaviour nothing here has measured`);
2234
+ }
2224
2235
 
2225
- // check-pack-install peer-install pins (quoted `@earendil-works/pi-*@<ver>`
2236
+ // check-pack-install install pins (quoted `@earendil-works/pi-*@<ver>`
2226
2237
  // args; the `\d`-anchored version avoids matching this regex literal itself).
2227
2238
  const peerAi = runSh.match(/"@earendil-works\/pi-ai@(\d[\d.]*)"/)?.[1];
2228
2239
  const peerCoding = runSh.match(/"@earendil-works\/pi-coding-agent@(\d[\d.]*)"/)?.[1];
2229
2240
  const peerTui = runSh.match(/"@earendil-works\/pi-tui@(\d[\d.]*)"/)?.[1];
2230
2241
  assert.equal(peerAi, piAi,
2231
- `run.sh check-pack-install pi-ai peer pin (${peerAi}) must match package.json devDep (${piAi})`);
2242
+ `run.sh check-pack-install pi-ai install pin (${peerAi}) must match the pinned SDK (${piAi})`);
2232
2243
  assert.equal(peerCoding, piAi,
2233
- `run.sh check-pack-install pi-coding-agent peer pin (${peerCoding}) must match (${piAi})`);
2244
+ `run.sh check-pack-install pi-coding-agent install pin (${peerCoding}) must match (${piAi})`);
2234
2245
  assert.equal(peerTui, piAi,
2235
- `run.sh check-pack-install pi-tui peer pin (${peerTui}) must match (${piAi})`);
2236
-
2237
- // peerDependencies must be a CLOSED range (0.11 Stage 0, drift-proofing): the
2238
- // floor tracks the devDep pin so a consumer can't install against a pi lacking
2239
- // the public trust exports the bridge imports at the pinned minor, AND an upper
2240
- // bound at the next minor stops a fresh install from silently pulling a future
2241
- // pi (past the declared ceiling — 0.87+ at the current 0.86.0 pin) whose
2242
- // internal export surface has drifted from the one we typecheck against.
2243
- // pi moves its public surface every minor (the 0.79→0.80 getModels→provider-
2244
- // factory churn is exactly this, and 0.86 is the same shape again: a custom
2245
- // provider's streamSimple now receives a branded TranscriptContext instead of a
2246
- // raw Context, with systemPrompt/tools folded into a leading system message), so
2247
- // an open `>=` floor is exactly how the next installer re-acquires the drift.
2248
- // The floor is also the HARD MINIMUM a consumer install resolves: at `>=0.86.0`
2249
- // an existing 0.85.1 host is upgraded, not kept.
2250
- // Expected shape: `>=<devDep> <<major>.<minor+1>` (e.g. `>=0.86.0 <0.87`, `>=1.0.0 <1.1`).
2251
- // Pi 1.0 did not change the rule: an unverified minor is still unverified, so the ceiling
2252
- // stays the next minor of the pin's own major.
2246
+ `run.sh check-pack-install pi-tui install pin (${peerTui}) must match (${piAi})`);
2247
+
2248
+ // The supported HOST range a doc may declare is derived, closed: `>=<floor> <<major>.<minor+1>`.
2249
+ // pi moves its public surface every minor (the 0.79→0.80 getModels churn, the 0.86 TranscriptContext
2250
+ // change), so an unverified minor is still unverified; the ceiling stays the next minor of the floor.
2253
2251
  const [piMaj, piMin] = piAi.split('.').map(Number);
2254
- const expectedPeer = `>=${piAi} <${piMaj}.${piMin + 1}`;
2255
- const peerDepAi = pkg.peerDependencies?.['@earendil-works/pi-ai'];
2256
- const peerDepCoding = pkg.peerDependencies?.['@earendil-works/pi-coding-agent'];
2257
- const peerDepTui = pkg.peerDependencies?.['@earendil-works/pi-tui'];
2258
- assert.equal(peerDepAi, expectedPeer,
2259
- `package.json peerDependencies @earendil-works/pi-ai (${peerDepAi}) must be "${expectedPeer}" (devDep floor + next-minor ceiling)`);
2260
- assert.equal(peerDepCoding, expectedPeer,
2261
- `package.json peerDependencies @earendil-works/pi-coding-agent (${peerDepCoding}) must be "${expectedPeer}"`);
2262
- assert.equal(peerDepTui, expectedPeer,
2263
- `package.json peerDependencies @earendil-works/pi-tui (${peerDepTui}) must be "${expectedPeer}"`);
2264
2252
 
2265
2253
  // BASELINE DOCS (0.12.8). This gate was BORN reading a doc: 362becd added it
2266
2254
  // after the 21de0f9 drift and asserted README.md's codex-acp install pin against
@@ -2324,14 +2312,14 @@ for (const file of BASELINE_DOCS) {
2324
2312
  for (const [decl, floor, ceilMajor, ceilMinor] of text.matchAll(/>=\s?(\d+\.\d+\.\d+)\s?<\s?(\d+)\.(\d+)/g)) {
2325
2313
  rangeDecls++;
2326
2314
  assert.equal(floor, piAi,
2327
- `${file}: declared pi floor in "${decl}" is ${floor}, but the devDep pin is ${piAi} — a baseline doc may not advertise a version no gate drives`);
2315
+ `${file}: declared pi floor in "${decl}" is ${floor}, but the pinned SDK is ${piAi} — a baseline doc may not advertise a version no gate drives`);
2328
2316
  assert.equal(`${ceilMajor}.${ceilMinor}`, `${piMaj}.${piMin + 1}`,
2329
2317
  `${file}: declared pi ceiling in "${decl}" must be the next minor (${piMaj}.${piMin + 1})`);
2330
2318
  }
2331
2319
  // Exact install pins: `@earendil-works/pi-<pkg>@<version>`.
2332
2320
  for (const [decl, ver] of text.matchAll(/@earendil-works\/pi-(?:ai|coding-agent|tui)@(\d+\.\d+\.\d+)/g)) {
2333
2321
  exactDecls++;
2334
- assert.equal(ver, piAi, `${file}: install example "${decl}" pins ${ver}, but the devDep pin is ${piAi}`);
2322
+ assert.equal(ver, piAi, `${file}: install example "${decl}" pins ${ver}, but the pinned SDK is ${piAi}`);
2335
2323
  }
2336
2324
  }
2337
2325
  // Prose declarations carry the pin in sentences the two patterns above cannot
@@ -2345,7 +2333,7 @@ const PROSE_DECLS = [
2345
2333
  for (const [file, re, shape] of PROSE_DECLS) {
2346
2334
  const m = readFileSync(file, 'utf8').match(re);
2347
2335
  assert.ok(m, `${file}: the baseline sentence "${shape}" is gone — restore it or update check-dep-versions; a doc reword must not silently drop the pin from the gate`);
2348
- assert.equal(m[1], piAi, `${file}: "${shape}" declares ${m[1]}, but the devDep pin is ${piAi}`);
2336
+ assert.equal(m[1], piAi, `${file}: "${shape}" declares ${m[1]}, but the pinned SDK is ${piAi}`);
2349
2337
  }
2350
2338
  // ── #120 P4: ONE FLOOR, FOUR MECHANICAL SURFACES ──────────────────────────
2351
2339
  // The bump is mostly a number substitution, and that is exactly how a bump goes
@@ -2365,6 +2353,8 @@ const PI_CONSTELLATION = [
2365
2353
  '@earendil-works/pi-telemetry', '@earendil-works/chord',
2366
2354
  // `[측정 2026-09-30]` 0.99.1: pi-coding-agent's runtime deps gained the built-in extensions' packages.
2367
2355
  '@earendil-works/pi-codemode', '@earendil-works/pi-mcp',
2356
+ // #130: the durable library the pi-durable carrier imports — a production dependency since 0.32.
2357
+ '@earendil-works/pi-durable',
2368
2358
  ];
2369
2359
  const sameSet = (got, want, where) => {
2370
2360
  const missing = want.filter((n) => !got.includes(n));
@@ -2409,7 +2399,7 @@ if (!matcherPin) {
2409
2399
  const CURRENT_CONTRACT_DECLS = [
2410
2400
  ['plugins/herdr/README.md', /npm install -g "@earendil-works\/pi-coding-agent@(>=[\d.]+ <\d+\.\d+)"/, 'the herdr install line'],
2411
2401
  ['docs/mux-launch-rail.md', /현 supported range 는 `(>=[\d.]+ <\d+\.\d+)`/, "mux-launch-rail's current supported range"],
2412
- ['docs/acp-backend-rail.md', /devDep exact `(\d+\.\d+\.\d+)`, peer `(>=[\d.]+ <\d+\.\d+)`/, "the ACP support row's exact+range pair"],
2402
+ ['docs/acp-backend-rail.md', /SDK exact `(\d+\.\d+\.\d+)`, host `(>=[\d.]+ <\d+\.\d+)`/, "the ACP support row's exact+range pair"],
2413
2403
  ];
2414
2404
  for (const [file, re, shape] of CURRENT_CONTRACT_DECLS) {
2415
2405
  const m = readFileSync(file, 'utf8').match(re);
@@ -2420,14 +2410,14 @@ for (const [file, re, shape] of CURRENT_CONTRACT_DECLS) {
2420
2410
  }
2421
2411
  }
2422
2412
  assert.deepEqual(floorGaps, [],
2423
- `[QK:PI-FLOOR-SINGLE-SOURCE] the pi floor is declared on four mechanical surfaces — the package's exact dev pins and peer ceiling, run.sh's install constellation, the pnpm workspace closure, and the current-contract sentences in the docs — and every one of them must name the SAME floor. A bump that moves three of the four is the ordinary way this breaks, and the surface left behind is the one nothing else reads`);
2413
+ `[QK:PI-FLOOR-SINGLE-SOURCE] the pi floor is declared on four mechanical surfaces — the durable pin's SDK set with package.json's exact production dependencies, run.sh's install constellation, the pnpm workspace closure, and the current-contract sentences in the docs — and every one of them must name the SAME floor. A bump that moves three of the four is the ordinary way this breaks, and the surface left behind is the one nothing else reads`);
2424
2414
 
2425
2415
  // Guard the guard: if the patterns ever stop matching, the loops above pass
2426
2416
  // vacuously and the docs fall back OUT of the gate without a word.
2427
2417
  assert.ok(rangeDecls >= 5, `expected at least 5 pi range declarations across the baseline docs, found ${rangeDecls} — the doc scan matched (almost) nothing and would pass vacuously`);
2428
2418
  assert.ok(exactDecls >= 1, `expected at least 1 exact pi install pin in the baseline docs, found ${exactDecls}`);
2429
2419
 
2430
- console.log(`[check-dep-versions] ok — pi ${piAi} is coherent across package.json (devDeps + peer range), run.sh (peer-install pins), and ${BASELINE_DOCS.length} baseline docs (${rangeDecls} range + ${exactDecls} exact + ${PROSE_DECLS.length} prose declarations)`);
2420
+ console.log(`[check-dep-versions] ok — pi ${piAi} is coherent across the durable pin's SDK set, package.json (exact production dependencies, no dev/peer duplicate), run.sh (install pins), and ${BASELINE_DOCS.length} baseline docs (${rangeDecls} range + ${exactDecls} exact + ${PROSE_DECLS.length} prose declarations)`);
2431
2421
  EOF
2432
2422
  )
2433
2423
  }
@@ -2839,17 +2829,17 @@ check_pi_import_surface() {
2839
2829
  # Do NOT widen this to a `providers/*` subpath — it typechecks but CANNOT
2840
2830
  # resolve under the extension loader.
2841
2831
  #
2842
- # #129 EXCEPTION — exactly TWO specifiers, in exactly ONE file:
2843
- # @earendil-works/pi-coding-agent/experimental/durable/runtime.ts and …/tui.ts
2844
- # in pi/pi-durable/bootstrap.mjs
2845
- # The durable app is source-only upstream (the published pi-coding-agent excludes
2846
- # dist/experimental and ships no src/), so these resolve ONLY against the operator's
2847
- # pinned runtime checkout, through the source resolver `entwurf pi-durable` loads with
2848
- # --import — never against this package's pi dependency. They are the one way to reach
2849
- # the app at all; building the string to dodge this scan would be the evasion this gate
2850
- # exists to stop. Only those quoted specifiers on that file's lines are neutralised
2851
- # before the forbidden pattern is applied again, so any other pi subpath in that file,
2852
- # and the same specifier in any other file, stay FORBIDDEN (proved on the fixture below).
2832
+ # #130 CARRIER FENCE (replaces the #129 bootstrap exception, retired with the source runtime):
2833
+ # the pi-durable carrier (pi/pi-durable/carrier/*.js, upstream app files emitted by
2834
+ # scripts/emit-pi-durable-carrier.ts) is the ONE place pi-coding-agent internals are reached,
2835
+ # and only through the reserved `entwurf-pi-dist:` scheme its resolver answers. The fence is
2836
+ # declared and asserted here, not inferred from the root-only scan staying quiet:
2837
+ # - the scheme is quoted ONLY in carrier files and at its one definition
2838
+ # (pi/pi-durable/carrier-relocation.mjs);
2839
+ # - a carrier file names no pi-coding-agent specifier at all, and every bare specifier it does
2840
+ # name is `node:*`, a declared sdk member (root or subpath) or a declared direct dependency
2841
+ # (pi/pi-durable/overlay/upstream-pin.json `sdk`).
2842
+ # Proved on an external fixture repo below, like the work-surface denominator.
2853
2843
  # ONE corpus, TWO callers. The real scan and the denominator fixture must run the
2854
2844
  # SAME two lines, or the fixture would prove a command the gate does not use.
2855
2845
  pi_import_work_surface() {
@@ -2858,12 +2848,35 @@ check_pi_import_surface() {
2858
2848
  pi_import_scan() {
2859
2849
  pi_import_work_surface \
2860
2850
  | xargs -0r grep -HnE "[\"'\`]@earendil-works/pi-(ai|coding-agent|tui)/" 2>/dev/null \
2861
- | grep -vE "[\"'\`]@earendil-works/pi-ai/compat[\"'\`]" 2>/dev/null \
2862
- | sed -E "/^pi\/pi-durable\/bootstrap\.mjs:[0-9]+:/ s#[\"'\`]@earendil-works/pi-coding-agent/experimental/durable/(runtime|tui)\.ts[\"'\`]#(durable-runtime-specifier)#g" \
2863
- | grep -E "[\"'\`]@earendil-works/pi-(ai|coding-agent|tui)/" 2>/dev/null || true
2851
+ | grep -vE "[\"'\`]@earendil-works/pi-ai/compat[\"'\`]" 2>/dev/null || true
2852
+ }
2853
+ # The carrier fence over the same work surface: prints one line per violation. $1 = the pin.
2854
+ pi_carrier_fence_scan() {
2855
+ pi_import_work_surface | node -e '
2856
+ const fs = require("node:fs");
2857
+ const pin = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
2858
+ const declared = new Set([...Object.keys(pin.sdk?.members ?? {}), ...Object.keys(pin.sdk?.direct ?? {})]);
2859
+ const files = fs.readFileSync(0, "utf8").split("\0").filter(Boolean);
2860
+ const carrier = (f) => /^pi\/pi-durable\/carrier\/[^/]+\.js$/.test(f);
2861
+ const scheme = /["\x27`]entwurf-pi-dist:/g;
2862
+ for (const f of files) {
2863
+ const text = fs.readFileSync(f, "utf8");
2864
+ const quoted = (text.match(scheme) ?? []).length;
2865
+ if (!carrier(f) && quoted > (f === "pi/pi-durable/carrier-relocation.mjs" ? 1 : 0)) {
2866
+ console.log(`${f}: quotes the reserved entwurf-pi-dist: scheme outside the carrier`);
2867
+ }
2868
+ if (!carrier(f)) continue;
2869
+ for (const m of text.matchAll(/^\s*(?:import|export|\})[^;]*?\bfrom\s*"([^"]+)";|^\s*import\s*"([^"]+)";/gm)) {
2870
+ const spec = m[1] ?? m[2];
2871
+ if (spec.startsWith("./") || spec.startsWith("entwurf-pi-dist:") || spec.startsWith("node:")) continue;
2872
+ const name = spec.startsWith("@") ? spec.split("/").slice(0, 2).join("/") : spec.split("/")[0];
2873
+ if (name === "@earendil-works/pi-coding-agent" || !declared.has(name)) console.log(`${f}: imports ${spec}, outside the declared carrier set`);
2874
+ }
2875
+ }
2876
+ ' "$1"
2864
2877
  }
2865
2878
 
2866
- local probe_dir probe_hits hits
2879
+ local probe_dir probe_hits probe_fence hits fence
2867
2880
  probe_dir=$(mktemp -d "${TMPDIR:-/tmp}/entwurf-pi-import-denominator.XXXXXX")
2868
2881
  (
2869
2882
  cd "$probe_dir" || exit 1
@@ -2871,15 +2884,19 @@ check_pi_import_surface() {
2871
2884
  printf '%s\n' 'import { getModels } from "@earendil-works/pi-ai/compat";' > tracked-allowed.ts
2872
2885
  git add tracked-allowed.ts
2873
2886
  printf '%s\n' 'import "@earendil-works/pi-ai/private-probe";' > untracked-forbidden.ts
2874
- mkdir -p pi/pi-durable
2875
- printf '%s\n' 'const RUNTIME = "@earendil-works/pi-coding-agent/experimental/durable/runtime.ts";' \
2876
- 'import "@earendil-works/pi-coding-agent/experimental/other.ts";' \
2877
- 'const TUI = "@earendil-works/pi-coding-agent/experimental/durable/tui.ts"; import "@earendil-works/pi-tui/private";' \
2878
- > pi/pi-durable/bootstrap.mjs
2879
- printf '%s\n' 'const RUNTIME = "@earendil-works/pi-coding-agent/experimental/durable/runtime.ts";' > elsewhere.mjs
2880
- git add pi/pi-durable/bootstrap.mjs elsewhere.mjs
2887
+ mkdir -p pi/pi-durable/carrier pi/pi-durable/overlay
2888
+ printf '%s\n' '{"sdk":{"members":{"@earendil-works/pi-ai":"1.0.4","@earendil-works/pi-durable":"1.0.4"},"direct":{"proper-lockfile":"4.1.2"}}}' \
2889
+ > pi/pi-durable/overlay/upstream-pin.json
2890
+ printf '%s\n' 'import { a } from "@earendil-works/pi-ai";' 'import { b } from "@earendil-works/pi-durable/tools";' \
2891
+ 'import lock from "proper-lockfile";' 'import { c } from "entwurf-pi-dist:core/x.js";' 'import { d } from "./sibling.js";' \
2892
+ > pi/pi-durable/carrier/allowed.js
2893
+ printf '%s\n' 'import { e } from "@earendil-works/pi-coding-agent";' > pi/pi-durable/carrier/coding-agent.js
2894
+ printf '%s\n' 'import { f } from "left-pad";' > pi/pi-durable/carrier/undeclared.js
2895
+ printf '%s\n' 'import { g } from "entwurf-pi-dist:core/x.js";' > elsewhere.mjs
2896
+ git add pi/pi-durable elsewhere.mjs
2881
2897
  ) || { fail "[check-pi-import-surface] could not build the denominator fixture in $probe_dir"; rm -rf "$probe_dir"; return 1; }
2882
2898
  probe_hits=$(cd "$probe_dir" && pi_import_scan)
2899
+ probe_fence=$(cd "$probe_dir" && pi_carrier_fence_scan pi/pi-durable/overlay/upstream-pin.json)
2883
2900
  rm -rf "$probe_dir"
2884
2901
  # ONE assertion, ONE claim token: the manifest contract requires the signature to
2885
2902
  # occur exactly once in this file, so both fixture conditions are folded into a
@@ -2891,13 +2908,13 @@ check_pi_import_surface() {
2891
2908
  fail "[QK:PIIMPORT-WORK-SURFACE] the denominator fixture disagrees with the corpus — untracked-forbidden reached=$saw_untracked_forbidden (want yes: a brand-new forbidden import must not escape until it is staged), tracked-allowed flagged=$saw_tracked_allowed (want no: the /compat exception must survive)"
2892
2909
  return 1
2893
2910
  fi
2894
- local durable_allowed_flagged="no" durable_other_reached="no" durable_sameline_reached="no" durable_elsewhere_reached="no"
2895
- grep -qE '^pi/pi-durable/bootstrap\.mjs:1:' <<<"$probe_hits" && durable_allowed_flagged="yes"
2896
- grep -qE '^pi/pi-durable/bootstrap\.mjs:2:' <<<"$probe_hits" && durable_other_reached="yes"
2897
- grep -qE '^pi/pi-durable/bootstrap\.mjs:3:' <<<"$probe_hits" && durable_sameline_reached="yes"
2898
- grep -qE '^elsewhere\.mjs:1:' <<<"$probe_hits" && durable_elsewhere_reached="yes"
2899
- if [ "$durable_allowed_flagged" != "no" ] || [ "$durable_other_reached" != "yes" ] || [ "$durable_sameline_reached" != "yes" ] || [ "$durable_elsewhere_reached" != "yes" ]; then
2900
- fail "[QK:PIIMPORT-DURABLE-BOOTSTRAP-EXACT] the #129 durable exception is not exact — its runtime specifier in pi/pi-durable/bootstrap.mjs flagged=$durable_allowed_flagged (want no), another experimental subpath in that file reached=$durable_other_reached (want yes), a forbidden specifier sharing a line with an allowed one reached=$durable_sameline_reached (want yes), the same specifier in another file reached=$durable_elsewhere_reached (want yes)"
2911
+ local fence_allowed="no" fence_coding_agent="no" fence_undeclared="no" fence_elsewhere="no"
2912
+ grep -qF 'carrier/allowed.js' <<<"$probe_fence" && fence_allowed="yes"
2913
+ grep -qF 'carrier/coding-agent.js' <<<"$probe_fence" && fence_coding_agent="yes"
2914
+ grep -qF 'carrier/undeclared.js' <<<"$probe_fence" && fence_undeclared="yes"
2915
+ grep -qF 'elsewhere.mjs' <<<"$probe_fence" && fence_elsewhere="yes"
2916
+ if [ "$fence_allowed" != "no" ] || [ "$fence_coding_agent" != "yes" ] || [ "$fence_undeclared" != "yes" ] || [ "$fence_elsewhere" != "yes" ]; then
2917
+ fail "[QK:PIIMPORT-CARRIER-FENCE] the #130 carrier fence is not exact — declared imports in a carrier file flagged=$fence_allowed (want no), a pi-coding-agent specifier in a carrier file reached=$fence_coding_agent (want yes), an undeclared package in a carrier file reached=$fence_undeclared (want yes), the reserved scheme outside the carrier reached=$fence_elsewhere (want yes)"
2901
2918
  return 1
2902
2919
  fi
2903
2920
 
@@ -2907,7 +2924,13 @@ check_pi_import_surface() {
2907
2924
  echo "$hits"
2908
2925
  exit 1
2909
2926
  fi
2910
- ok "[check-pi-import-surface] pi references are root/compat-only (plus the exact #129 durable bootstrap pair) across tracked + untracked-non-ignored ts/js; the untracked denominator and the durable exception's exactness are proved on an external fixture repo"
2927
+ fence=$(cd "$REPO_DIR" && pi_carrier_fence_scan pi/pi-durable/overlay/upstream-pin.json)
2928
+ if [ -n "$fence" ]; then
2929
+ echo "[check-pi-import-surface] FAIL: the #130 pi-durable carrier fence is broken:"
2930
+ echo "$fence"
2931
+ exit 1
2932
+ fi
2933
+ ok "[check-pi-import-surface] pi references are root/compat-only across tracked + untracked-non-ignored ts/js, and the pi-durable carrier reaches pi-coding-agent only through its reserved scheme with declared bare imports; the untracked denominator and the carrier fence are proved on an external fixture repo"
2911
2934
  }
2912
2935
 
2913
2936
  check_env_namespace() {
@@ -2934,65 +2957,26 @@ check_env_namespace() {
2934
2957
  }
2935
2958
 
2936
2959
  check_pi_runtime_version() {
2937
- # 0.11 Stage 0 (동결결정 9, runtime half): tsc catches a missing 0.80 export
2938
- # at dev time, but an installed environment can still resolve a pi OUTSIDE the
2939
- # supported range at runtime — older, where the named trust exports / 0.80
2940
- # provider-factory surface do not exist; or newer, where they have moved again.
2941
- # Verify VERSION against the DECLARED CLOSED RANGE (both ends, see below) via a
2942
- # DYNAMIC import of the package root only — never statically import a
2943
- # range-only symbol here, or this guard would crash before it can fail loud.
2960
+ # 0.11 Stage 0 (동결결정 9, runtime half), re-scoped by #130. tsc catches a missing export at
2961
+ # dev time, but an environment can still resolve a pi other than the one this repo pins at
2962
+ # runtime. Since 0.32 the pi SDK is a production dependency set (the pi-durable carrier runs
2963
+ # against it), so the runtime this checkout's tests, bridge and carrier import IS that set, and
2964
+ # the question is no longer "inside a range" but "exactly the pinned generation, edge by edge".
2965
+ # It is answered by the ONE native-set verifier the launcher, setup and the fresh preflight use
2966
+ # (pi-extensions/lib/pi-durable-runtime.ts): every declared member and direct dependency resolves
2967
+ # from the carrier, and every member's own member edge, at exactly the pinned version. A stale
2968
+ # development node_modules (an older pi left behind a bump) is a named sdk-absent/sdk-mismatch.
2944
2969
  #
2945
- # The floor is DERIVED from the package.json devDep pin, never a second literal.
2946
- # A hand-kept `const FLOOR = '<version>'` is a declaration no gate enforces:
2947
- # check-dep-versions binds the devDeps, the peer range, and the check-pack-install
2948
- # peer pins to one another, but it never saw this constant — so a pi bump that
2949
- # forgot it would leave the runtime gate still blessing the OLD floor, silently.
2950
- # That is the same "declared runtime ≠ verified runtime" split the 0.12.8
2951
- # check-pack-install fix closed; there must be exactly ONE pin to move.
2952
- (cd "$REPO_DIR" && node --input-type=module <<'EOF'
2953
- import { readFileSync } from 'node:fs';
2954
-
2955
- const pkg = JSON.parse(readFileSync('package.json', 'utf8'));
2956
- const FLOOR = pkg.devDependencies?.['@earendil-works/pi-coding-agent'];
2957
- if (typeof FLOOR !== 'string' || !/^\d+\.\d+\.\d+$/.test(FLOOR)) {
2958
- console.error(`[check-pi-runtime-version] FAIL: package.json devDependencies['@earendil-works/pi-coding-agent'] must be an EXACT x.y.z pin to serve as the runtime floor (got ${FLOOR ?? 'nothing'})`);
2959
- process.exit(1);
2960
- }
2961
- // The declared contract is a CLOSED range (`>=<devDep> <<major>.<minor+1>`, enforced on
2962
- // package.json by check-dep-versions), so the runtime check must be closed too.
2963
- // A floor-only comparison would bless a resolved pi ABOVE the ceiling — and an
2964
- // out-of-range pi is exactly the drift this cut exists to stop: 0.80.6 landed on
2965
- // the dev box while the repo still declared 0.80.3, and every gate stayed green.
2966
- // Verifying only half of a declared range is the same lie in the other direction.
2967
- const [FLOOR_MAJOR, FLOOR_MINOR] = FLOOR.split('.').map(Number);
2968
- const CEILING = `${FLOOR_MAJOR}.${FLOOR_MINOR + 1}.0`;
2969
- const cmp = (a, b) => {
2970
- const pa = a.split('.').map(Number), pb = b.split('.').map(Number);
2971
- for (let i = 0; i < 3; i++) { if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0); }
2972
- return 0;
2973
- };
2974
- let VERSION;
2975
- try {
2976
- ({ VERSION } = await import('@earendil-works/pi-coding-agent'));
2977
- } catch (e) {
2978
- console.error(`[check-pi-runtime-version] FAIL: cannot import @earendil-works/pi-coding-agent root — ${e?.message ?? e}`);
2979
- process.exit(1);
2980
- }
2981
- if (typeof VERSION !== 'string') {
2982
- console.error('[check-pi-runtime-version] FAIL: pi root export VERSION is not a string');
2983
- process.exit(1);
2984
- }
2985
- if (cmp(VERSION, FLOOR) < 0) {
2986
- console.error(`[check-pi-runtime-version] FAIL: pi VERSION ${VERSION} < ${FLOOR} — the bridge is built and tested against the ${FLOOR} public/runtime surface (trust exports hasTrustRequiringProjectResources + ProjectTrustStore nearest-ancestor get, the 0.80 model-catalog API getModels reached via the deprecated /compat entrypoint — 0.80 moved the standalone root getModels there, and the extension loader resolves only /compat, NOT the providers/* factory subpath — provider registration surface, compaction semantics) that older pi lacks or behaves differently on. Bump @earendil-works/pi-*.`);
2987
- process.exit(1);
2988
- }
2989
- if (cmp(VERSION, CEILING) >= 0) {
2990
- console.error(`[check-pi-runtime-version] FAIL: pi VERSION ${VERSION} >= ${CEILING} — OUTSIDE the declared range (>=${FLOOR} <${CEILING.slice(0, -2)}). pi moves its public surface every minor (the 0.79→0.80 getModels→/compat churn), so a next-minor runtime is unverified by definition: no gate here has driven it. Either pin the repo to that pi (devDeps + peer range + baseline docs move together) or install the declared one.`);
2991
- process.exit(1);
2992
- }
2993
- console.log(`[check-pi-runtime-version] ok — pi VERSION ${VERSION} within the declared range (>=${FLOOR} <${CEILING.slice(0, -2)})`);
2994
- EOF
2995
- )
2970
+ # What this deliberately does NOT answer: the ordinary Pi HOST on PATH. That is a separate
2971
+ # subject with its own range (`pi_supported_range`, enforced by setup and install-user-scope on a
2972
+ # real `pi --version`), and a green here says nothing about it.
2973
+ local out rc=0
2974
+ out=$(cd "$REPO_DIR" && run_ts pi-extensions/lib/pi-durable-runtime.ts resolve 2>&1) || rc=$?
2975
+ if [ "$rc" -ne 0 ]; then
2976
+ fail "[check-pi-runtime-version] the pinned pi SDK set is not what this checkout resolves: ${out##*$'\n'}"
2977
+ return 1
2978
+ fi
2979
+ echo "[check-pi-runtime-version] ok — this checkout resolves exactly the pinned pi SDK set (native set; the PATH host is setup's subject)"
2996
2980
  }
2997
2981
 
2998
2982
  check_install_preflight() {
@@ -3038,8 +3022,8 @@ check_install_preflight() {
3038
3022
  # (a bare `test -d` would pass) with the other runtime deps symlinked live, but a
3039
3023
  # representative dep (@anthropic-ai/sdk) dangles. Asserts the dir-move blind spot
3040
3024
  # is closed AND that the failure names the broken dep. Uses a BUNDLED runtime dep
3041
- # because the @earendil-works/pi-* peer trio is loader-provided and no longer part
3042
- # of the install preflight probe set.
3025
+ # because the @earendil-works SDK set is not part of the install preflight probe
3026
+ # set (the carrier verifier owns its integrity).
3043
3027
  fake=$(mktemp -d); proj=$(mktemp -d)
3044
3028
  cp "$REPO_DIR/run.sh" "$fake/run.sh"
3045
3029
  mkdir -p "$fake/node_modules/@modelcontextprotocol" "$fake/node_modules/@agentclientprotocol" "$fake/node_modules/@anthropic-ai"
@@ -3689,6 +3673,15 @@ check_pack() {
3689
3673
  "pi/pi-durable/bootstrap.mjs"
3690
3674
  "pi/pi-durable/overlay/upstream-pin.json"
3691
3675
  "pi/pi-durable/overlay/runtime-contacts.patch"
3676
+ "pi/pi-durable/carrier-resolver.mjs"
3677
+ "pi/pi-durable/carrier-relocation.mjs"
3678
+ "pi/pi-durable/carrier/runtime.js"
3679
+ "pi/pi-durable/carrier/tui.js"
3680
+ "pi/pi-durable/carrier/harness-setup.js"
3681
+ "pi/pi-durable/carrier/prompt.js"
3682
+ "pi/pi-durable/carrier/sessions.js"
3683
+ "pi/pi-durable/carrier/subagent.js"
3684
+ "pi/pi-durable/carrier/LICENSE"
3692
3685
  "pi/meta-bridge-omp/entwurf-meta-omp/package.json"
3693
3686
  "mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
3694
3687
  "scripts/postinstall-chmod.cjs"
@@ -3817,7 +3810,7 @@ check_pack() {
3817
3810
  # which is exactly what property (1)'s `(_|$)` absorbs; all three shapes are fixtures
3818
3811
  # below so a future suffix change cannot pass vacuously.)
3819
3812
  pack_install_leaked_pi() {
3820
- grep '^@earendil-works+' | grep -Ev '@1\.0\.2(_|$)' || true
3813
+ grep '^@earendil-works+' | grep -Ev '@1\.0\.4(_|$)' || true
3821
3814
  }
3822
3815
 
3823
3816
  # Matcher self-test on SYNTHETIC lookalikes: a healthy install tree cannot exercise either
@@ -3837,15 +3830,15 @@ check_pack_pin_matcher() {
3837
3830
  # None may leak; the two lookalikes must — a PREFIX-EXTENDED version (`0.86.0-beta.1`,
3838
3831
  # the prerelease shape that an unanchored match would bless) and an off-pin version.
3839
3832
  matcher_probe=$(printf '%s\n' \
3840
- '@earendil-works+pi-ai@1.0.2' \
3841
- '@earendil-works+pi-ai@1.0.2_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6' \
3842
- '@earendil-works+pi-ai@1.0.2_ws@8.21.3' \
3843
- '@earendil-works+pi-ai@1.0.2_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__ws@8.21.3_zod@4.3.6' \
3844
- '@earendil-works+pi-ai@1.0.2-beta.1' \
3833
+ '@earendil-works+pi-ai@1.0.4' \
3834
+ '@earendil-works+pi-ai@1.0.4_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6' \
3835
+ '@earendil-works+pi-ai@1.0.4_ws@8.21.3' \
3836
+ '@earendil-works+pi-ai@1.0.4_@modelcontextprotocol+sdk@1.29.0_zod@4.3.6__ws@8.21.3_zod@4.3.6' \
3837
+ '@earendil-works+pi-ai@1.0.4-beta.1' \
3845
3838
  '@earendil-works+pi-agent-core@0.87.1' | pack_install_leaked_pi)
3846
- if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.2-beta.1
3839
+ if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.4-beta.1
3847
3840
  @earendil-works+pi-agent-core@0.87.1' ]; then
3848
- fail "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED] the pin-leak matcher must flag the prefix-extended 1.0.2-beta.1 and the off-pin 0.87.1 lookalikes, and pass 1.0.2 bare or with any measured peer-hash — got: ${matcher_probe:-<nothing leaked>}"
3841
+ fail "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED] the pin-leak matcher must flag the prefix-extended 1.0.4-beta.1 and the off-pin 0.87.1 lookalikes, and pass 1.0.4 bare or with any measured peer-hash — got: ${matcher_probe:-<nothing leaked>}"
3849
3842
  return 1
3850
3843
  fi
3851
3844
 
@@ -3853,9 +3846,9 @@ check_pack_pin_matcher() {
3853
3846
  # (0.85.0 onward, still true at 0.99.1). An off-pin chord MUST leak; the pinned one must not. A matcher narrowed
3854
3847
  # back to `^@earendil-works+pi-` sees nothing here and dies at this signature.
3855
3848
  matcher_probe=$(printf '%s\n' \
3856
- '@earendil-works+chord@1.0.2' \
3849
+ '@earendil-works+chord@1.0.4' \
3857
3850
  '@earendil-works+chord@0.87.1' \
3858
- '@earendil-works+pi-ai@1.0.2' | pack_install_leaked_pi)
3851
+ '@earendil-works+pi-ai@1.0.4' | pack_install_leaked_pi)
3859
3852
  if [ "$matcher_probe" != '@earendil-works+chord@0.87.1' ]; then
3860
3853
  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 is 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) — got: ${matcher_probe:-<nothing leaked>}"
3861
3854
  return 1
@@ -3864,6 +3857,233 @@ check_pack_pin_matcher() {
3864
3857
  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)"
3865
3858
  }
3866
3859
 
3860
+ # #130 — the pi-durable carrier proved on ACTUAL npm consumers of the candidate tarball.
3861
+ # $1 tarball $2 the gate's npm sandbox $3 an existing Entwurf-only npm consumer root inside it.
3862
+ # Cells: L1s (Entwurf alone, $3), L1 (project-local beside an aligned host pi-coding-agent at the
3863
+ # pinned SDK version), L2 (an isolated `npm -g --prefix`), each through (a) the INSTALLED verifier
3864
+ # (exit 0, prints its own carrier-resolver) and (b) an independent consumer oracle; then the L3
3865
+ # NEGATIVE (an override binds pi-durable's pi-ai edge one patch behind: the installed verifier must
3866
+ # refuse it by name, while a bare import still succeeds); then (c) the public launch on L1s.
3867
+ # The oracle observes RESOLUTIONS (a resolve hook), not every filesystem read; it asserts each
3868
+ # resolved product file lies inside THIS consumer's node_modules — a sandbox ancestor is not the
3869
+ # boundary (#130 P1a review, Defect B) — and proves that predicate on a control: the installed
3870
+ # package of a NEIGHBOUR consumer in the same sandbox, which must be judged outside.
3871
+ # Same-version sharing within the consumer is an ordinary layout; copies are recorded, not refused.
3872
+ pack_install_durable_cells() {
3873
+ local tgz="$1" box="$2" l1s="$3" pin_ver oracle_dir cell root control pkg out rc
3874
+ local host_specs=() host_old_specs=() spec
3875
+ pin_ver=$(cd "$REPO_DIR" && node -p "require('./pi/pi-durable/overlay/upstream-pin.json').sdk.members['@earendil-works/pi-coding-agent']")
3876
+ # The HOST fixture needs a coherent generation too: coding-agent@1.0.4 alone
3877
+ # has ^1.0.4 SDK edges, which can resolve 1.1.0 (CI37694671506: pi-ai tar 404).
3878
+ # These are fixture roots from the owning pin, not product overrides or fallback.
3879
+ out=$(cd "$REPO_DIR" && node -e 'const p = require("./pi/pi-durable/overlay/upstream-pin.json"); console.log(Object.entries(p.sdk.members).map(([n,v]) => `${n}@${v}`).join("\n"));') || return 1
3880
+ mapfile -t host_specs <<<"$out"
3881
+ oracle_dir="$box/pd-oracle"; mkdir -p "$oracle_dir"
3882
+ cat > "$oracle_dir/oracle.mjs" <<'ORACLE'
3883
+ // node --import <pkg>/pi/pi-durable/carrier-resolver.mjs oracle.mjs <pkg> <consumer node_modules> <control file> <receipt>
3884
+ import fs from "node:fs";
3885
+ import { registerHooks } from "node:module";
3886
+ import path from "node:path";
3887
+ import { fileURLToPath, pathToFileURL } from "node:url";
3888
+ const [pkg, consumerRoot, control, receiptPath] = process.argv.slice(2);
3889
+ const seen = [];
3890
+ registerHooks({ resolve(specifier, context, next) { const r = next(specifier, context); seen.push({ specifier, parent: context.parentURL ?? null, url: r.url }); return r; } });
3891
+ const root = fs.realpathSync(consumerRoot);
3892
+ const inside = (file) => fs.realpathSync(file).startsWith(root + path.sep);
3893
+ const pin = JSON.parse(fs.readFileSync(path.join(pkg, "pi/pi-durable/overlay/upstream-pin.json"), "utf8"));
3894
+ const members = pin.sdk.members, direct = pin.sdk.direct;
3895
+ const carrier = path.join(pkg, "pi/pi-durable/carrier");
3896
+ const exportsOk = (await import(pathToFileURL(path.join(carrier, "runtime.js")).href)).openDurable instanceof Function
3897
+ && (await import(pathToFileURL(path.join(carrier, "tui.js")).href)).runDurableTui instanceof Function;
3898
+ const files = [...new Set(seen.filter((s) => s.url.startsWith("file:")).map((s) => fileURLToPath(s.url)))];
3899
+ const outside = files.filter((f) => !inside(f));
3900
+ const owner = (file) => { for (let d = path.dirname(fs.realpathSync(file)); d !== path.dirname(d); d = path.dirname(d)) { const m = path.join(d, "package.json"); if (fs.existsSync(m)) { const j = JSON.parse(fs.readFileSync(m, "utf8")); if (typeof j.name === "string") return { name: j.name, version: j.version, root: d }; } } return null; };
3901
+ const copies = {};
3902
+ for (const f of files) { const o = owner(f); if (o?.name.startsWith("@earendil-works/")) (copies[o.name] ??= new Set()).add(`${o.version}@${path.relative(root, o.root)}`); }
3903
+ const relocated = seen.filter((s) => s.specifier.startsWith("entwurf-pi-dist:"));
3904
+ const codingAgentRoots = new Set(relocated.map((s) => owner(fileURLToPath(s.url))?.root));
3905
+ // Independent of the product's resolver: the package directory a bare import from `fromFile` binds is the
3906
+ // nearest ancestor `node_modules/<name>` of the file's REAL directory, walked here by hand.
3907
+ const lookup = (name, fromFile) => { for (let d = fs.realpathSync(path.dirname(fromFile)); ; d = path.dirname(d)) { const m = path.join(d, "node_modules", name, "package.json"); if (fs.existsSync(m)) return m; if (d === path.dirname(d)) return null; } };
3908
+ const edge = (from, to, want, fromFile) => { const m = lookup(to, fromFile); if (!m) return { from, to, want, got: null, name: null }; const j = JSON.parse(fs.readFileSync(m, "utf8")); return { from, to, want, got: j.version, name: j.name, at: path.relative(root, fs.realpathSync(path.dirname(m))) }; };
3909
+ const base = path.join(carrier, "runtime.js");
3910
+ const edges = Object.entries({ ...members, ...direct }).map(([n, v]) => edge("carrier", n, v, base));
3911
+ // Every reachable member copy, at any depth, once per real directory.
3912
+ const queue = edges.filter((e) => e.to in members && e.at).map((e) => e.at), seenCopies = new Set();
3913
+ while (queue.length > 0) { const at = queue.shift(); if (seenCopies.has(at)) continue; seenCopies.add(at); const m = path.join(root, at, "package.json"); const j = JSON.parse(fs.readFileSync(m, "utf8")); for (const dep of Object.keys(j.dependencies ?? {}).filter((x) => x in members)) { const e = edge(j.name, dep, members[dep], m); edges.push(e); if (e.at) queue.push(e.at); } }
3914
+ const verdict = {
3915
+ exportsOk,
3916
+ resolvedFiles: files.length,
3917
+ outsideConsumer: outside,
3918
+ controlRejected: fs.existsSync(control) && !inside(control),
3919
+ loadedVersionsOk: Object.entries(copies).every(([n, set]) => [...set].every((c) => c.startsWith(`${members[n]}@`))),
3920
+ relocations: relocated.length,
3921
+ relocationOneDistInside: codingAgentRoots.size === 1 && relocated.every((s) => inside(fileURLToPath(s.url))),
3922
+ memberEdges: edges.filter((e) => e.from !== "carrier").length,
3923
+ memberCopiesWalked: seenCopies.size,
3924
+ edgeMismatches: edges.filter((e) => e.got !== e.want || e.name !== e.to),
3925
+ };
3926
+ fs.writeFileSync(receiptPath, JSON.stringify({ consumerRoot: root, verdict, copies: Object.fromEntries(Object.entries(copies).map(([n, s]) => [n, [...s]])), edges, resolutions: seen }, null, 1));
3927
+ const ok = verdict.exportsOk && verdict.outsideConsumer.length === 0 && verdict.controlRejected && verdict.loadedVersionsOk
3928
+ && verdict.relocations > 0 && verdict.relocationOneDistInside && verdict.memberEdges > 0 && verdict.edgeMismatches.length === 0;
3929
+ console.log(JSON.stringify({ ok, ...verdict, outsideConsumer: verdict.outsideConsumer.length, edgeMismatches: verdict.edgeMismatches.length }));
3930
+ process.exit(ok ? 0 : 1);
3931
+ ORACLE
3932
+
3933
+ mkdir -p "$box/pd-aligned" "$box/pd-global" "$box/pd-mismatch"
3934
+ out=$(cd "$box/pd-aligned" && npm install "$tgz" "${host_specs[@]}" --no-audit --no-fund 2>&1) || {
3935
+ fail "[check-pack-install] pi-durable L1 (aligned host) install failed:"; echo "$out" | tail -10 | sed 's/^/ /' >&2; return 1; }
3936
+ out=$(cd "$box" && npm install -g --prefix "$box/pd-global" "$tgz" --no-audit --no-fund 2>&1) || {
3937
+ fail "[check-pack-install] pi-durable L2 (isolated global) install failed:"; echo "$out" | tail -10 | sed 's/^/ /' >&2; return 1; }
3938
+
3939
+ for cell in L1s L1 L2; do
3940
+ case "$cell" in
3941
+ L1s) root="$l1s/node_modules" control="$box/pd-aligned/node_modules/@junghanacs/entwurf/package.json" ;;
3942
+ L1) root="$box/pd-aligned/node_modules" control="$box/pd-global/lib/node_modules/@junghanacs/entwurf/package.json" ;;
3943
+ L2) root="$box/pd-global/lib/node_modules" control="$l1s/node_modules/@junghanacs/entwurf/package.json" ;;
3944
+ esac
3945
+ pkg="$root/@junghanacs/entwurf"
3946
+ rc=0; out=$(cd "$box" && node "$pkg/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js" resolve 2>&1) || rc=$?
3947
+ if [ "$rc" -ne 0 ] || [ "$(realpath "$out" 2>/dev/null)" != "$(realpath "$pkg/pi/pi-durable/carrier-resolver.mjs")" ]; then
3948
+ fail "[check-pack-install] pi-durable $cell: the INSTALLED verifier did not verify its own carrier (rc=$rc): $out"
3949
+ return 1
3950
+ fi
3951
+ rc=0; out=$(cd "$box" && node --import "$out" "$oracle_dir/oracle.mjs" "$pkg" "$root" "$control" "$box/pd-oracle/$cell.json" 2>&1) || rc=$?
3952
+ if [ "$rc" -ne 0 ]; then
3953
+ fail "[QK:PACK-INSTALL-DURABLE-CONSUMER] [check-pack-install] pi-durable $cell: the carrier is not a coherent, consumer-contained load (receipt $box/pd-oracle/$cell.json): $out"
3954
+ return 1
3955
+ fi
3956
+ echo "[check-pack-install] pi-durable $cell: installed verifier PASS; consumer oracle $out"
3957
+ done
3958
+
3959
+ printf '%s\n' "{\"name\":\"pd-mismatch\",\"version\":\"1.0.0\",\"private\":true,\"overrides\":{\"@earendil-works/pi-durable\":{\"@earendil-works/pi-ai\":\"1.0.3\"}}}" > "$box/pd-mismatch/package.json"
3960
+ out=$(cd "$box/pd-mismatch" && npm install "$tgz" --no-audit --no-fund 2>&1) || {
3961
+ fail "[check-pack-install] pi-durable L3 (mismatch control) install failed:"; echo "$out" | tail -10 | sed 's/^/ /' >&2; return 1; }
3962
+ pkg="$box/pd-mismatch/node_modules/@junghanacs/entwurf"
3963
+ rc=0; out=$(cd "$box" && node "$pkg/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js" resolve 2>&1) || rc=$?
3964
+ if [ "$rc" -ne 3 ] || ! grep -q "pi-durable-sdk-mismatch: @earendil-works/pi-durable → @earendil-works/pi-ai wants $pin_ver, binds 1.0.3" <<<"$out"; then
3965
+ fail "[QK:PACK-INSTALL-DURABLE-MISMATCH-REFUSED] [check-pack-install] pi-durable L3: an installed tree whose pi-durable binds pi-ai 1.0.3 must be refused by name as pi-durable-sdk-mismatch (rc=$rc): $out"
3966
+ return 1
3967
+ fi
3968
+ 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=$?
3969
+ if [ "$rc" -ne 0 ] || [ "$out" != "function" ]; then
3970
+ fail "[check-pack-install] pi-durable L3: the control premise failed — the mixed tree was expected to still IMPORT (rc=$rc): $out"
3971
+ return 1
3972
+ fi
3973
+ echo "[check-pack-install] pi-durable L3: the mixed tree still imports, and the installed verifier refuses it as pi-durable-sdk-mismatch"
3974
+
3975
+ # L4 — a THIRD-depth mismatch control on the same coherence axis. `[측정 2026-10-07]` npm 11 does not
3976
+ # produce this layout from an override (nested strategy included, it dedupes pi-durable's pi-ai to the
3977
+ # shared copy and overrides that), so it is CONSTRUCTED from real package bytes inside the already
3978
+ # proved L2 consumer: pi-durable gets its own same-version copy of the installed pi-ai, whose
3979
+ # pi-telemetry is the real published 1.0.3. Both the installed verifier and the independent oracle
3980
+ # must name the depth-3 edge; a walk that stopped at the carrier's own members would pass it.
3981
+ local l4_root="$box/pd-global/lib/node_modules" l4_tel="$box/pd-tel-103" l4_tel_ver="1.0.3"
3982
+ pkg="$l4_root/@junghanacs/entwurf"
3983
+ mkdir -p "$l4_tel" "$pkg/node_modules/@earendil-works/pi-durable/node_modules/@earendil-works"
3984
+ out=$(cd "$l4_tel" && npm pack "@earendil-works/pi-telemetry@$l4_tel_ver" --silent 2>&1 && tar -xzf ./*.tgz 2>&1) || {
3985
+ fail "[check-pack-install] could not fetch the real pi-telemetry 1.0.3 for the L4 control:"; echo "$out" | tail -5 | sed 's/^/ /' >&2; return 1; }
3986
+ local l4_ai="$pkg/node_modules/@earendil-works/pi-durable/node_modules/@earendil-works/pi-ai"
3987
+ cp -a "$(realpath "$pkg/node_modules/@earendil-works/pi-ai")" "$l4_ai"
3988
+ mkdir -p "$l4_ai/node_modules/@earendil-works"
3989
+ cp -a "$l4_tel/package" "$l4_ai/node_modules/@earendil-works/pi-telemetry"
3990
+ rc=0; out=$(cd "$box" && node "$pkg/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js" resolve 2>&1) || rc=$?
3991
+ if [ "$rc" -ne 3 ] || ! grep -q "pi-durable-sdk-mismatch: @earendil-works/pi-ai → @earendil-works/pi-telemetry wants $pin_ver, binds 1.0.3 at $(realpath "$l4_ai")/node_modules/@earendil-works/pi-telemetry" <<<"$out"; then
3992
+ fail "[QK:PACK-INSTALL-DURABLE-DEPTH3-REFUSED] [check-pack-install] pi-durable L4: a depth-3 pi-telemetry 1.0.3 under pi-durable's own pi-ai copy must be refused by name (rc=$rc): $out"
3993
+ return 1
3994
+ fi
3995
+ rc=0; out=$(cd "$box" && node --import "$pkg/pi/pi-durable/carrier-resolver.mjs" "$oracle_dir/oracle.mjs" "$pkg" "$l4_root" "$l1s/node_modules/@junghanacs/entwurf/package.json" "$box/pd-oracle/L4.json" 2>&1) || rc=$?
3996
+ if [ "$rc" -eq 0 ] || ! grep -q '"edgeMismatches":1' <<<"$out"; then
3997
+ fail "[check-pack-install] pi-durable L4: the independent oracle did not see exactly the one depth-3 mismatch (rc=$rc): $out"
3998
+ return 1
3999
+ fi
4000
+ echo "[check-pack-install] pi-durable L4: a constructed depth-3 pi-telemetry 1.0.3 is refused by the installed verifier and seen by the independent oracle"
4001
+
4002
+ # (c) The public launch on L1s, through the installed bin: verifier → resolver → bootstrap → TUI
4003
+ # module → the carrier's real openDurable on the pinned SDK, whose own model resolution
4004
+ # (`findInitialAgentModel`) refuses a provider no catalog registers — `[측정 2026-10-07]` the
4005
+ # upstream message, before the overlay's exact-model check is reached. Offline (PI_OFFLINE),
4006
+ # sandbox HOME/agent dir, no credential; the contact's bridge
4007
+ # is spawned only at the birth, which this refusal precedes, so no citizen may exist after it.
4008
+ local launch_home="$box/pd-launch-home" launch_cwd="$box/pd-launch-cwd" launch_env=()
4009
+ mkdir -p "$launch_home/.pi/agent" "$launch_cwd"
4010
+ mapfile -t launch_env < <(pack_install_consumer_env "$launch_home")
4011
+ rc=0; out=$(cd "$launch_cwd" && env "${launch_env[@]}" PI_OFFLINE=1 "$l1s/node_modules/.bin/entwurf" pi-durable --provider entwurf-pack-probe --model no-such-model --width task-wide 2>&1 </dev/null) || rc=$?
4012
+ if [ "$rc" -eq 0 ] || ! grep -q 'Could not resolve model: Unknown provider "entwurf-pack-probe"' <<<"$out" || ! grep -q "at openDurable (file://.*/pi/pi-durable/carrier/runtime.js" <<<"$out" || grep -qE "pi-durable-(package-incomplete|carrier-drift|sdk-absent|sdk-mismatch)|ERR_MODULE_NOT_FOUND|ERR_UNSUPPORTED_ESM_URL_SCHEME" <<<"$out"; then
4013
+ fail "[QK:PACK-INSTALL-DURABLE-PUBLIC-LAUNCH] [check-pack-install] the installed 'entwurf pi-durable' did not reach the carrier openDurable's own model refusal on the pinned SDK (rc=$rc):"
4014
+ echo "$out" | tail -15 | sed 's/^/ /' >&2
4015
+ return 1
4016
+ fi
4017
+ if ls "$launch_home/.pi/agent/meta-sessions" 2>/dev/null | grep -q .; then
4018
+ fail "[check-pack-install] the refused durable launch minted a meta record — a refusal before birth must leave no citizen"
4019
+ return 1
4020
+ fi
4021
+ echo "[check-pack-install] pi-durable public launch: the installed verb ran the carrier's openDurable on the pinned SDK, whose own model resolution refused the unregistered provider, before any birth"
4022
+
4023
+ # (c2) #130 P2: ONE explicit operator module on the INSTALLED package. The synthetic fixture is
4024
+ # copied from this checkout into the sandbox — it never ships (test/ is outside the package files).
4025
+ # Its initialization appends `init` to the receipt this cell names; the same public launch must then
4026
+ # reach the same carrier model refusal, so the installed bootstrap loaded the module before the
4027
+ # runtime and the native registry installed its extension (carrier/runtime.js 146) before that
4028
+ # refusal (runtime.js 162). A module claiming an extension name the app installs itself is refused by
4029
+ # name before anything opens: no durable session directory, no citizen, in a fresh sandbox home.
4030
+ # Native SDK file opens here are ordinary (the module runs in the native process); none is judged.
4031
+ local mod_dir="$box/pd-module" mod_home="$box/pd-module-home" mod_env=()
4032
+ mkdir -p "$mod_dir" "$mod_home/.pi/agent"
4033
+ cp "$REPO_DIR/test/fixtures/pi-durable-native-module/mock.mjs" "$mod_dir/mock.mjs"
4034
+ printf 'export default { name: "subagent" };\n' > "$mod_dir/reserved.mjs"
4035
+ rc=0; out=$(cd "$launch_cwd" && env "${launch_env[@]}" PI_OFFLINE=1 MOCK_NATIVE_RECEIPT="$mod_dir/receipt.log" "$l1s/node_modules/.bin/entwurf" pi-durable --provider entwurf-pack-probe --model no-such-model --width task-wide --native-module "$mod_dir/mock.mjs" 2>&1 </dev/null) || rc=$?
4036
+ if [ "$rc" -eq 0 ] || [ "$(cat "$mod_dir/receipt.log" 2>/dev/null)" != "init" ] || ! grep -q 'Could not resolve model: Unknown provider "entwurf-pack-probe"' <<<"$out" || ! grep -q "at openDurable (file://.*/pi/pi-durable/carrier/runtime.js" <<<"$out" || grep -q "native-module-" <<<"$out"; then
4037
+ fail "[QK:PACK-INSTALL-DURABLE-NATIVE-MODULE] [check-pack-install] the installed 'entwurf pi-durable --native-module' did not initialize the module once and then reach the carrier openDurable's own model refusal (rc=$rc, receipt $(cat "$mod_dir/receipt.log" 2>/dev/null | tr '\n' ' ')):"
4038
+ echo "$out" | tail -15 | sed 's/^/ /' >&2
4039
+ return 1
4040
+ fi
4041
+ mapfile -t mod_env < <(pack_install_consumer_env "$mod_home")
4042
+ rc=0; out=$(cd "$launch_cwd" && env "${mod_env[@]}" PI_OFFLINE=1 "$l1s/node_modules/.bin/entwurf" pi-durable --provider entwurf-pack-probe --model no-such-model --width task-wide --native-module "$mod_dir/reserved.mjs" 2>&1 </dev/null) || rc=$?
4043
+ if [ "$rc" -eq 0 ] || ! grep -q "native-module-name-reserved: .*subagent" <<<"$out" || grep -q "Unknown provider" <<<"$out" || [ -e "$mod_home/.pi/agent/experimental" ] || [ -e "$mod_home/.pi/agent/meta-sessions" ]; then
4044
+ fail "[QK:PACK-INSTALL-DURABLE-NATIVE-MODULE] [check-pack-install] the installed launch did not refuse a reserved-name module by name before anything opened (rc=$rc):"
4045
+ echo "$out" | tail -15 | sed 's/^/ /' >&2
4046
+ return 1
4047
+ fi
4048
+ echo "[check-pack-install] pi-durable native module: the installed bootstrap initialized one explicit module before the carrier's runtime (then the same model refusal), and refused a reserved extension name before anything opened"
4049
+
4050
+ # (d) Host vs native are two subjects. The installed package's native SDK set is the pin (above);
4051
+ # the ordinary Pi HOST on PATH is judged by its OWN real `pi --version` against the derived range.
4052
+ # Real host binaries, no forged version: a sandbox install of the previous pi (1.0.2) must make the
4053
+ # installed setup's pi row a named FAIL with ZERO Pi wiring while pi-durable still PASSes, and the
4054
+ # aligned host binary (the pinned version, installed above for L1) must be inside the range.
4055
+ # The previous host version is a variable, not a quoted `@pkg@x.y.z` spec: check-dep-versions reads
4056
+ # those specs as this repo's install pins, and this one is deliberately off the floor.
4057
+ local host_home host_proj host_old="$box/pd-host-old" host_env=() host_old_ver="1.0.2"
4058
+ mkdir -p "$host_old"
4059
+ for spec in "${host_specs[@]}"; do host_old_specs+=("${spec%@*}@$host_old_ver"); done
4060
+ out=$(cd "$host_old" && npm install "${host_old_specs[@]}" --no-audit --no-fund 2>&1) || {
4061
+ fail "[check-pack-install] could not install the previous-host pi fixture (1.0.2):"; echo "$out" | tail -10 | sed 's/^/ /' >&2; return 1; }
4062
+ for cell in old aligned; do
4063
+ host_home="$box/pd-host-$cell-home"; host_proj="$box/pd-host-$cell-proj"
4064
+ mkdir -p "$host_home/.pi/agent" "$host_proj"
4065
+ mapfile -t host_env < <(pack_install_consumer_env "$host_home")
4066
+ local host_bin="$host_old/node_modules/.bin/pi"
4067
+ [ "$cell" = aligned ] && host_bin="$box/pd-aligned/node_modules/.bin/pi"
4068
+ rc=0; out=$(cd "$box" && env "${host_env[@]}" PI_BIN="$host_bin" CLAUDE_BIN="$box/definitely-absent" AGY_BIN="$box/definitely-absent" \
4069
+ COPILOT_BIN="$box/definitely-absent" OMP_BIN="$box/definitely-absent" CODEX_BIN="$box/definitely-absent" \
4070
+ "$l1s/node_modules/.bin/entwurf" setup "$host_proj" 2>&1) || rc=$?
4071
+ if ! grep -q "pi-durable: PASS" <<<"$out"; then
4072
+ fail "[check-pack-install] host $cell: the native pi-durable row must stay PASS whatever the PATH host is:"; echo "$out" | tail -20 | sed 's/^/ /' >&2; return 1
4073
+ fi
4074
+ if [ "$cell" = old ]; then
4075
+ if [ "$rc" -eq 0 ] || ! grep -q "pi: FAIL — detected pi 1.0.2 is outside the supported range >=$pin_ver <1.1" <<<"$out" || [ -e "$host_proj/.pi" ] || [ -e "$host_home/.pi/agent/settings.json" ]; then
4076
+ fail "[QK:PACK-INSTALL-HOST-RANGE-SEPARATE] [check-pack-install] a real pi 1.0.2 host beside the $pin_ver native set must be a named pi FAIL with zero Pi wiring and a non-green setup (rc=$rc):"
4077
+ echo "$out" | tail -20 | sed 's/^/ /' >&2
4078
+ return 1
4079
+ fi
4080
+ elif grep -q "outside the supported range" <<<"$out"; then
4081
+ fail "[check-pack-install] host aligned: the pinned-version host binary was judged outside the range:"; echo "$out" | tail -20 | sed 's/^/ /' >&2; return 1
4082
+ fi
4083
+ done
4084
+ echo "[check-pack-install] host vs native: a real pi 1.0.2 host is a named pi FAIL with no wiring while pi-durable PASSes; the $pin_ver host binary is inside the range"
4085
+ }
4086
+
3867
4087
  # The writable roots of ONE consumer sandbox, shared by every consumer subcall of
3868
4088
  # check-pack-install that drives an installed `run.sh` writer. The writers resolve their agent
3869
4089
  # dir as `${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}` (`resolve`/`install` below), so swapping HOME
@@ -4061,6 +4281,15 @@ _check_pack_install_impl() {
4061
4281
  "pi/pi-durable/bootstrap.mjs"
4062
4282
  "pi/pi-durable/overlay/upstream-pin.json"
4063
4283
  "pi/pi-durable/overlay/runtime-contacts.patch"
4284
+ "pi/pi-durable/carrier-resolver.mjs"
4285
+ "pi/pi-durable/carrier-relocation.mjs"
4286
+ "pi/pi-durable/carrier/runtime.js"
4287
+ "pi/pi-durable/carrier/tui.js"
4288
+ "pi/pi-durable/carrier/harness-setup.js"
4289
+ "pi/pi-durable/carrier/prompt.js"
4290
+ "pi/pi-durable/carrier/sessions.js"
4291
+ "pi/pi-durable/carrier/subagent.js"
4292
+ "pi/pi-durable/carrier/LICENSE"
4064
4293
  "pi/meta-bridge-omp/entwurf-meta-omp/package.json"
4065
4294
  "mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
4066
4295
  "scripts/postinstall-chmod.cjs"
@@ -4139,9 +4368,9 @@ _check_pack_install_impl() {
4139
4368
  # repo packages with; --ignore-workspace stops it from re-attaching
4140
4369
  # to our pnpm-workspace.yaml; --ignore-scripts blocks the husky
4141
4370
  # prepare hook (and any future install scripts) from running inside
4142
- # the consumer project. Peer deps are pinned to the CURRENT pi release
4143
- # baseline (the package.json devDep pin — the pins below are what
4144
- # check-dep-versions binds to that devDep) so the smoke matches the same
4371
+ # the consumer project. The pi SDK is pinned to the CURRENT pi release
4372
+ # baseline (the package.json exact production dependency — the pins below
4373
+ # are what check-dep-versions binds to it) so the smoke matches the same
4145
4374
  # shape an external pi user would have after `pi install`.
4146
4375
  local tmp npm_tmp
4147
4376
  tmp=$(mktemp -d -t entwurf-install-smoke.XXXXXX)
@@ -4205,20 +4434,25 @@ _check_pack_install_impl() {
4205
4434
  # `[측정 2026-10-05]` at 1.0.2 the constellation is unchanged: `npm view <pkg>@1.0.2 dependencies`
4206
4435
  # gives pi-coding-agent {chord, pi-agent-core, pi-ai, pi-codemode, pi-mcp, pi-tui}, pi-ai
4207
4436
  # {pi-telemetry}, pi-client {chord, pi-protocol}, pi-protocol {chord}, all ten published at 1.0.2.
4208
- echo "[check-pack-install] pnpm add into $tmp (with 1.0.x peers + chord + codemode + mcp + typebox)"
4437
+ # `[측정 2026-10-07]` at 1.0.4 the same edges hold, and #130 adds @earendil-works/pi-durable: the
4438
+ # library the pi-durable carrier imports, a production dependency of this package since 0.32 (its
4439
+ # own deps: chord, pi-ai). All eleven are published at 1.0.4. The tarball now DECLARES the nine-member
4440
+ # SDK set itself, so these pins are an aligned host install beside it, not peers it lacks.
4441
+ echo "[check-pack-install] pnpm add into $tmp (with the aligned 1.0.x SDK + chord + codemode + mcp + durable + typebox)"
4209
4442
  local install_log
4210
4443
  install_log=$(cd "$tmp" && pnpm add \
4211
4444
  "$tgz_path" \
4212
- "@earendil-works/pi-ai@1.0.2" \
4213
- "@earendil-works/pi-coding-agent@1.0.2" \
4214
- "@earendil-works/pi-tui@1.0.2" \
4215
- "@earendil-works/pi-agent-core@1.0.2" \
4216
- "@earendil-works/pi-client@1.0.2" \
4217
- "@earendil-works/pi-protocol@1.0.2" \
4218
- "@earendil-works/pi-telemetry@1.0.2" \
4219
- "@earendil-works/chord@1.0.2" \
4220
- "@earendil-works/pi-codemode@1.0.2" \
4221
- "@earendil-works/pi-mcp@1.0.2" \
4445
+ "@earendil-works/pi-ai@1.0.4" \
4446
+ "@earendil-works/pi-coding-agent@1.0.4" \
4447
+ "@earendil-works/pi-tui@1.0.4" \
4448
+ "@earendil-works/pi-agent-core@1.0.4" \
4449
+ "@earendil-works/pi-client@1.0.4" \
4450
+ "@earendil-works/pi-protocol@1.0.4" \
4451
+ "@earendil-works/pi-telemetry@1.0.4" \
4452
+ "@earendil-works/chord@1.0.4" \
4453
+ "@earendil-works/pi-codemode@1.0.4" \
4454
+ "@earendil-works/pi-mcp@1.0.4" \
4455
+ "@earendil-works/pi-durable@1.0.4" \
4222
4456
  "typebox@latest" \
4223
4457
  --ignore-workspace --ignore-scripts 2>&1) || {
4224
4458
  fail "[check-pack-install] pnpm add failed:"
@@ -4234,11 +4468,11 @@ _check_pack_install_impl() {
4234
4468
  local leaked_pi
4235
4469
  leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | pack_install_leaked_pi)
4236
4470
  if [ -n "$leaked_pi" ]; then
4237
- fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.0.2):"
4471
+ fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.0.4):"
4238
4472
  printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
4239
4473
  return 1
4240
4474
  fi
4241
- echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.0.2 (chord included)"
4475
+ echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.0.4 (chord and pi-durable included)"
4242
4476
 
4243
4477
  # Resolve the installed package.json and confirm pi.extensions
4244
4478
  # arrived intact. If pi.extensions is empty or missing, the
@@ -4347,8 +4581,8 @@ _check_pack_install_impl() {
4347
4581
  # and safe to run in CI. Output goes to stderr; capture both
4348
4582
  # streams with 2>&1.
4349
4583
  #
4350
- # The pi that loads the tarball is the PINNED peer this smoke just installed next to
4351
- # it ($tmp/node_modules/.bin/pi = the floor of the supported peer range), NEVER
4584
+ # The pi that loads the tarball is the PINNED SDK pi this smoke just installed next to
4585
+ # it ($tmp/node_modules/.bin/pi = the floor of the supported host range), NEVER
4352
4586
  # whatever `pi` the host happens to have on PATH. A gate may not READ the operator's
4353
4587
  # global install any more than it may WRITE it: PATH resolution made this gate green
4354
4588
  # on a dev box carrying a newer global pi and RED in CI, which carries no global pi
@@ -4371,14 +4605,14 @@ _check_pack_install_impl() {
4371
4605
  )
4372
4606
 
4373
4607
  # Assert the version: a gate that cannot name which pi it proved has proved nothing.
4374
- # package.json devDeps is the pin SSOT (check-dep-versions keeps the peer-install
4375
- # literals above in step with it).
4608
+ # The pinned SDK generation is the pin SSOT (package.json's exact production dependency, which
4609
+ # check-dep-versions binds to the durable pin and to the install literals above).
4376
4610
  local pi_bin="$tmp/node_modules/.bin/pi" pi_pin pi_ver
4377
4611
  if [ ! -x "$pi_bin" ]; then
4378
4612
  fail "[check-pack-install] pinned pi missing from the install-smoke tree ($pi_bin) — cannot run loader smoke"
4379
4613
  return 1
4380
4614
  fi
4381
- pi_pin=$(cd "$REPO_DIR" && node -p "require('./package.json').devDependencies['@earendil-works/pi-coding-agent']")
4615
+ pi_pin=$(cd "$REPO_DIR" && node -p "require('./package.json').dependencies['@earendil-works/pi-coding-agent']")
4382
4616
  pi_ver=$(cd "$tmp" && env "${pi_env[@]}" "$pi_bin" --version 2>&1 | head -1 | tr -d '[:space:]')
4383
4617
  if [ "$pi_ver" != "$pi_pin" ]; then
4384
4618
  fail "[check-pack-install] install-smoke pi is '$pi_ver', expected the pinned '$pi_pin' — the loader smoke would prove the wrong runtime"
@@ -4445,8 +4679,9 @@ _check_pack_install_impl() {
4445
4679
  # npm-managed neutral install regression — the README's PRIMARY install path is
4446
4680
  # now `npm install @junghanacs/entwurf` (NOT `pi install npm:...`). This layout
4447
4681
  # lands the package under node_modules, hoists runtime deps to the sibling
4448
- # node_modules, has no package-local node_modules, and the pi peer trio must be
4449
- # absent because pi is an optional adapter lane. The old cwd-relative
4682
+ # node_modules, has no package-local node_modules, and (since #130) carries the
4683
+ # pi SDK as a production dependency the bridge must still not import — the
4684
+ # pi-free boot below proves that under a deny hook. The old cwd-relative
4450
4685
  # preflight_dep_integrity rejected every hoisted-dep npm install; 0.12.0 then
4451
4686
  # additionally died because start.sh tried strip-types under node_modules.
4452
4687
  # Prove `entwurf`/`entwurf-bridge` bins exist, `run.sh install` writes settings
@@ -4536,6 +4771,10 @@ sys.exit(0 if any(isinstance(s,str) and s.endswith('/node_modules/@junghanacs/en
4536
4771
  fi
4537
4772
  echo "[check-pack-install] user-scope citizen regression pass (npm consumer: --entwurf-control loads from a foreign cwd)"
4538
4773
 
4774
+ # #130: the pi-durable carrier on actual npm consumers (L1s = this Entwurf-only root, L1 aligned
4775
+ # host, L2 isolated global, L3 mismatch control) and the public launch.
4776
+ pack_install_durable_cells "$tgz_path" "$npm_tmp" "$npmroot" || return 1
4777
+
4539
4778
  # Two-root ownership row (#86 C2, L1b extension): a SECOND npm root under the
4540
4779
  # SAME consumer HOME must not silently steal the user-scope registration the
4541
4780
  # first root owns — normal install refuses (naming takeover-user-scope) and the
@@ -4670,13 +4909,20 @@ sys.exit(0 if any(isinstance(s,str) and s.rstrip('/')== '$npm2_pkg' for s in src
4670
4909
  return 1
4671
4910
  fi
4672
4911
  local skip_probe
4673
- for skip_probe in "pi: SKIP" "claude: SKIP" "agy: SKIP" "copilot: SKIP" "omp: SKIP" "codex: SKIP" "pi-durable: SKIP"; do
4912
+ for skip_probe in "pi: SKIP" "claude: SKIP" "agy: SKIP" "copilot: SKIP" "omp: SKIP" "codex: SKIP"; do
4674
4913
  if ! grep -q "$skip_probe" <<<"$setup_out"; then
4675
4914
  fail "[QK:CODEX-PACK-SETUP-ZERO-STATE] [check-pack-install] installed all-absent setup missing explicit zero-state '$skip_probe':"
4676
4915
  echo "$setup_out" | tail -25 | sed 's/^/ /' >&2
4677
4916
  return 1
4678
4917
  fi
4679
4918
  done
4919
+ # #130: pi-durable is not a detected harness — its carrier and pi SDK set ship IN this package, so
4920
+ # the installed row must verify them from node_modules (PASS), never fall back to a zero-state SKIP.
4921
+ if ! grep -q "pi-durable: PASS" <<<"$setup_out"; then
4922
+ fail "[check-pack-install] installed all-absent setup did not verify the packaged pi-durable carrier and its SDK set (want 'pi-durable: PASS'):"
4923
+ echo "$setup_out" | tail -25 | sed 's/^/ /' >&2
4924
+ return 1
4925
+ fi
4680
4926
  if ! grep -q "bins: PASS — provided by npm bin linking" <<<"$setup_out"; then
4681
4927
  fail "[check-pack-install] installed setup must report stable bins PASS as npm-provided (capability present, not absent):"
4682
4928
  echo "$setup_out" | tail -25 | sed 's/^/ /' >&2
@@ -5031,29 +5277,55 @@ PY
5031
5277
  # surface. Two proofs in one: (1) the prepack dist JS boots under node_modules
5032
5278
  # with plain node — a strip-types fallback would crash with the exact error
5033
5279
  # above, so a parseable tools/list IS proof the dist path was taken; (2) the
5034
- # boot is pi-free — the @earendil-works peer trio is optional and must NOT be
5035
- # installed by the neutral npm path, so the eager closure stands up with pi absent.
5280
+ # boot is pi-free. Until #130 that was proved by ABSENCE (the pi peers were optional and the
5281
+ # neutral npm path did not install them). Since 0.32 the pi SDK is a production dependency, so
5282
+ # it is always installed and absence can no longer be the premise; the proof is now adversarial
5283
+ # in the other direction: the bridge boots under a preloaded resolve hook that REFUSES every
5284
+ # `@earendil-works/*` specifier, so an eager graph that imported pi would die at boot.
5036
5285
  local installed_start="$npmroot/node_modules/.bin/entwurf-bridge"
5037
5286
  local installed_dist="$npm_pkg/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js"
5038
5287
  if [ ! -f "$installed_dist" ]; then
5039
5288
  fail "[check-pack-install] installed bridge missing prebuilt dist (prepack did not emit into the tarball?): $installed_dist"
5040
5289
  return 1
5041
5290
  fi
5042
- if [ -d "$npmroot/node_modules/@earendil-works" ]; then
5043
- fail "[check-pack-install] @earendil-works present in npm-managed node_modules — pi-free boot proof is void (neutral npm install should not install optional pi peers)"
5291
+ if [ ! -d "$npmroot/node_modules/@earendil-works/pi-coding-agent" ]; then
5292
+ fail "[check-pack-install] the npm-managed install lacks @earendil-works/pi-coding-agent — the pi-free boot proof below needs pi PRESENT to deny it (#130 production SDK)"
5044
5293
  return 1
5045
5294
  fi
5295
+ local deny_pi="$npm_tmp/deny-pi/deny-pi.mjs"
5296
+ mkdir -p "$(dirname "$deny_pi")"
5297
+ cat > "$deny_pi" <<'DENY'
5298
+ import { registerHooks } from "node:module";
5299
+ registerHooks({
5300
+ resolve(specifier, context, next) {
5301
+ if (specifier.startsWith("@earendil-works/")) throw new Error(`pi-free boot violated: the bridge imported ${specifier}`);
5302
+ return next(specifier, context);
5303
+ },
5304
+ });
5305
+ DENY
5306
+ # Control: the hook really refuses an @earendil-works import from this tree (else the proof is vacuous).
5307
+ local deny_ctl
5308
+ deny_ctl=$(cd "$npmroot" && node --import "$deny_pi" --input-type=module -e "await import('@earendil-works/pi-ai')" 2>&1) && {
5309
+ fail "[check-pack-install] the pi-deny hook let @earendil-works/pi-ai load — the pi-free boot proof would be vacuous"
5310
+ return 1
5311
+ }
5312
+ if ! grep -q "pi-free boot violated: the bridge imported @earendil-works/pi-ai" <<<"$deny_ctl"; then
5313
+ fail "[check-pack-install] the pi-deny control failed for another reason:"; echo "$deny_ctl" | tail -5 | sed 's/^/ /' >&2; return 1
5314
+ fi
5046
5315
  local boot_out
5047
- if ! boot_out=$(START_SH="$installed_start" node --input-type=module <<'JS'
5316
+ if ! boot_out=$(START_SH="$installed_start" DENY_PI="$deny_pi" node --input-type=module <<'JS'
5048
5317
  import { spawn } from 'node:child_process';
5049
5318
  const start = process.env.START_SH;
5050
5319
  // Sanitize the child env so the pi-free proof cannot be masked by a leaked
5051
5320
  // module-resolution path: if NODE_PATH (or a stray pi env) pointed at a tree
5052
5321
  // holding @earendil-works, a statically pi-importing eager graph could resolve
5053
5322
  // and boot anyway, turning this gate falsely green. Strip it so "boots with
5054
- // @earendil absent" stays an honest adversarial proof.
5323
+ // every @earendil-works resolution refused" stays an honest adversarial proof.
5055
5324
  const env = { ...process.env };
5056
5325
  delete env.NODE_PATH;
5326
+ // #130: pi is installed beside the bridge now; every @earendil-works resolution is refused instead.
5327
+ env.NODE_OPTIONS = `${env.NODE_OPTIONS ?? ''} --import ${process.env.DENY_PI}`.trim();
5328
+ delete env.DENY_PI;
5057
5329
  const child = spawn(start, { stdio: ['pipe', 'pipe', 'pipe'], env });
5058
5330
  let stdout = '', stderr = '', done = false;
5059
5331
  const timer = setTimeout(() => {
@@ -5777,13 +6049,15 @@ setup_mode() {
5777
6049
  esac
5778
6050
  }
5779
6051
 
5780
- # Supported pi range, derived at runtime from the package.json devDependencies
5781
- # pin (the SSOT check-dep-versions binds: peer range == `>=<pin> <<major>.<minor+1>`).
5782
- # Never retyped here as a second literal.
6052
+ # Supported HOST pi range, derived at runtime from the pinned SDK generation — package.json's exact
6053
+ # production dependency on pi-coding-agent, which check-dep-versions binds to the durable pin's SDK
6054
+ # set: `>=<pin> <<major>.<minor+1>`. Never retyped here as a second literal. This is the ordinary Pi
6055
+ # on PATH that loads Entwurf's extensions; the carrier's own SDK set is a different subject
6056
+ # (pi-durable-runtime.ts), and a host inside this range is not required to be the same copy.
5783
6057
  pi_supported_range() {
5784
6058
  node -e '
5785
6059
  const pkg = require(process.argv[1]);
5786
- const pin = pkg.devDependencies?.["@earendil-works/pi-coding-agent"];
6060
+ const pin = pkg.dependencies?.["@earendil-works/pi-coding-agent"];
5787
6061
  if (!/^\d+\.\d+\.\d+$/.test(pin ?? "")) { console.error(`unparseable pi pin: ${pin}`); process.exit(1); }
5788
6062
  const [maj, min] = pin.split(".").map(Number);
5789
6063
  console.log(`>=${pin} <${maj}.${min + 1}`);
@@ -6135,19 +6409,18 @@ setup_all() {
6135
6409
  setup_result codex-terminal-title FAIL "detected codex, but the terminal-title setting did not complete (see above)"
6136
6410
  fi
6137
6411
  fi
6138
- # ── pi-durable ── #129: presence-driven like every harness, but the "harness" is the
6139
- # operator-provided durable runtime at its ONE fixed place, and setup writes NOTHING for it.
6140
- # Absent is a zero-state SKIP; present and the pin is PASS; present but not the pin is a
6141
- # named FAIL the operator repairs. The verdict is the same leaf the managed launch and the
6142
- # fresh preflight ask — 0 verified, 4 absent, anything else refused. Entwurf never installs
6143
- # the runtime (docs/setup-clean-host.md §2b).
6412
+ # ── pi-durable ── #129, #130: the durable app is this package's own carrier and its pi SDK set
6413
+ # is a production dependency, so there is nothing to detect and setup writes NOTHING for it —
6414
+ # the row reports whether the installed carrier can run. There is no SKIP: a missing piece is an
6415
+ # incomplete installation, a named FAIL repaired by reinstalling Entwurf. The verdict is the
6416
+ # same leaf the managed launch and the fresh preflight ask — 0 verified, anything else refused.
6144
6417
  local pd_rc pd_out
6145
6418
  pd_rc=0; pd_out=$(run_ts pi-extensions/lib/pi-durable-runtime.ts resolve 2>&1) || pd_rc=$?
6146
- case "$pd_rc" in
6147
- 0) setup_result pi-durable PASS "operator runtime is the pin — launch with 'entwurf pi-durable'" ;;
6148
- 4) setup_result pi-durable SKIP "no operator-provided durable runtime at the fixed location — zero durable wiring written (Entwurf never installs it)" ;;
6149
- *) setup_result pi-durable FAIL "a durable runtime is present but refused — ${pd_out##*$'\n'}" ;;
6150
- esac
6419
+ if [ "$pd_rc" -eq 0 ]; then
6420
+ setup_result pi-durable PASS "carrier and its pi SDK set verify — launch with 'entwurf pi-durable --provider <p> --model <id> --width task-wide'"
6421
+ else
6422
+ setup_result pi-durable FAIL "the installed pi-durable carrier is refused — ${pd_out##*$'\n'}"
6423
+ fi
6151
6424
 
6152
6425
  # ── core bridge boundary ── deterministic preflight lives in `pnpm run
6153
6426
  # check:full`; live substrate acceptance lives in `LIVE=1 ./run.sh
@@ -7569,15 +7842,15 @@ case "$cmd" in
7569
7842
  exec bash "$REPO_DIR/scripts/copilot-launch.sh" "$@"
7570
7843
  ;;
7571
7844
  pi-durable)
7572
- # #129 W (L3): the MANAGED durable launch. Same shape and reasons as `copilot` above: `exec`,
7573
- # no subshell and no cd — the durable TUI must own this terminal, the caller's cwd, this pid
7574
- # and its exit status — and `shift`, because everything after the verb is the bootstrap's argv.
7845
+ # #129 W (L3), #130: the MANAGED durable launch. Same shape and reasons as `copilot` above:
7846
+ # `exec`, no subshell and no cd — the durable TUI must own this terminal, the caller's cwd, this
7847
+ # pid and its exit status — and `shift`, because everything after the verb is the bootstrap's argv.
7575
7848
  #
7576
- # The durable app is source-only upstream, so its runtime is the OPERATOR's, at ONE fixed
7577
- # place, and it is verified against the packaged pin BEFORE any of it runs: its source
7578
- # resolver is the first code this launch would load from it. Absent or drifted is a named
7579
- # refusal from the same leaf the fresh preflight and setup ask (exit 4 absent, 3 otherwise).
7580
- # Entwurf never installs, repairs or moves that runtime.
7849
+ # The durable app is this package's CARRIER (pi/pi-durable/carrier/), and it is verified with its
7850
+ # declared pi SDK set BEFORE any of it runs: the resolver it prints is the first code this launch
7851
+ # loads. An incomplete package, a drifted carrier or an absent/mismatched SDK edge is a named
7852
+ # refusal (exit 3) from the same leaf the fresh preflight and setup ask. Nothing outside the
7853
+ # package is located, installed or repaired.
7581
7854
  shift || true
7582
7855
  pd_resolver=$(run_ts pi-extensions/lib/pi-durable-runtime.ts resolve) || exit $?
7583
7856
  exec node --import "$pd_resolver" "$REPO_DIR/pi/pi-durable/bootstrap.mjs" "$@"