@junghanacs/entwurf 0.30.1 → 0.31.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.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +112 -0
- package/DELIVERY.md +1 -0
- package/README.md +47 -7
- package/VERIFY.md +17 -1
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/setup-clean-host.md +104 -4
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +7 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +28 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +30 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +92 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js +288 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +744 -0
- package/mcp/entwurf-bridge/src/index.ts +7 -7
- package/mcp/entwurf-bridge/tsconfig.build.json +8 -1
- package/package.json +13 -10
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/pi-durable/bootstrap.mjs +281 -0
- package/pi/pi-durable/overlay/runtime-contacts.patch +91 -0
- package/pi/pi-durable/overlay/upstream-pin.json +16 -0
- package/pi-extensions/lib/entwurf-deliverability.ts +7 -1
- package/pi-extensions/lib/fresh-call-composition.ts +42 -7
- package/pi-extensions/lib/meta-sender-identity.ts +7 -1
- package/pi-extensions/lib/meta-session.ts +28 -2
- package/pi-extensions/lib/mux-fresh-call.ts +34 -2
- package/pi-extensions/lib/pi-durable-fresh-preflight.ts +113 -0
- package/pi-extensions/lib/pi-durable-runtime.ts +384 -0
- package/pi-extensions/meta-bridge-pi-durable.ts +1020 -0
- package/run.sh +200 -33
- package/scripts/check-fresh-call-dispatch.ts +18 -0
- package/scripts/check-gate-qualification.ts +2 -1
- package/scripts/check-pi-durable-contact.ts +834 -0
- package/scripts/check-pi-durable-receive.ts +1116 -0
- package/scripts/check-pi-durable-send.ts +1661 -0
- package/scripts/lib/pi-durable-fresh-live-receipts.ts +139 -0
- package/scripts/lib/pi-durable-r1.ts +100 -0
- package/scripts/lib/pi-durable-reap.ts +27 -0
- package/scripts/lib/pi-durable-receive.ts +137 -0
- package/scripts/mutants/control-send-receipt.json +1 -1
- package/scripts/mutants/copilot-birth.json +2 -2
- package/scripts/mutants/meta-hook-session-switch.json +4 -2
- package/scripts/mutants/mux-fresh-call.json +69 -3
- package/scripts/mutants/omp-birth.json +2 -2
- package/scripts/mutants/omp-fresh.json +6 -4
- package/scripts/mutants/pack-install.json +3 -3
- package/scripts/mutants/pi-durable.json +390 -0
- package/scripts/mutants/pi-floor.json +2 -2
- package/scripts/pi-durable-contact-host.mjs +105 -0
- package/scripts/pi-durable-receive-host.mjs +127 -0
- package/scripts/pi-durable-send-host.mjs +213 -0
- package/scripts/smoke-pi-durable-fresh-live.ts +624 -0
- package/scripts/smoke-setup-verdict.sh +21 -2
- package/scripts/tsconfig.json +1 -0
package/run.sh
CHANGED
|
@@ -132,6 +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
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
|
|
136
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
|
|
137
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
|
|
@@ -199,6 +203,7 @@ Usage:
|
|
|
199
203
|
./run.sh smoke-setup-verdict # #86 C1+C3b aggregate setup verdict fixture: all-absent SKIP/green, pi presence+floor, detected-FAIL nonzero, copilot four-unit composition (present=independent PASS/FAIL rows, absent=zero-state SKIP), installed-mode named branch, credential store untouched. Offline/deterministic
|
|
200
204
|
./run.sh check-agy-permission-matrix # AGY permission CONTRACT SPACE as a literal table (55 cells): parser-state × operation × settings × ownership × precedence with stated exclusion rules; expectations are hand-written literals, never read from the SUT. Offline/deterministic (deps: python3)
|
|
201
205
|
./run.sh smoke-omp-fresh-live # #87 bundle C acceptance, RELEASE MUST: omp opened as ONE visible fresh sibling through the PUBLIC entwurf_fresh_call surface (never raw tmux), exact nonce callback -> garden id from the SENDER ENVELOPE -> record/backend identity -> addressed receive -> lastReadAt -> the drain visible in that same native session's own transcript. Needs LIVE=1 and spends real model turns. Self-deciding: omp outside FRESH_CALL_BACKENDS or without a mailbox rail is a protocol SKIP, which --cut reads as RED
|
|
206
|
+
./run.sh smoke-pi-durable-fresh-live # #129 first-admission acceptance, RELEASE MUST: real Pi opens pi-durable through entwurf_fresh_call (managed verb), exact-nonce callback into Pi, Pi→pd addressed receive drained by pd's live turn, pd→Pi dispatch relayed to the collector; pd's actual model + task-wide offering read from its native store (online sqlite backup). LIVE=1; models ENTWURF_PI_DURABLE_FRESH_MODEL / _PI_MODEL (default openai-codex/gpt-6.1-sol)
|
|
202
207
|
./run.sh smoke-omp-receive-live # #87 bundle B acceptance: another harness wakes an ALREADY-OPEN omp citizen, which reads its inbox and answers in the same session. Decides its own outcome from the capability registry — omp without a drainable mailbox is a protocol SKIP (no receiver unit exists to arm), which an unattended release-gate reports and `--cut` reads as RED; a registry that claims a receive rail with no acceptance body here is a FAIL
|
|
203
208
|
./run.sh smoke-entwurf-chain-live # LIVE cross-harness delivery chain: native Claude Code -> pi GPT -> pi ACP Sonnet -> mailbox terminus, proving sender identity/replyable at every hop and a real read receipt at the end. Prerequisites (claude on PATH, pi credentials per backend) report protocol SKIP, never a pass
|
|
204
209
|
./run.sh check-release-gate-outcomes # release-gate STEP OUTCOME protocol (P1): one skip exit code shared by the shell + TS halves, classifier never rounds a skip up to a pass, `--cut` refuses a MUST SKIP while a bare diagnostic stays exit 0, no LIVE smoke keeps the old exit-0 skip shape, and both real skip surfaces are INVOKED and observed to propagate the code
|
|
@@ -221,6 +226,7 @@ Usage:
|
|
|
221
226
|
./run.sh uninstall-meta-bridge # 1.0.0 meta-bridge Phase 2: stateful GLOBAL uninstall (restore only keys/items captured in install-state)
|
|
222
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
|
|
223
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
|
|
224
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)
|
|
225
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)
|
|
226
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,7 +288,7 @@ Usage:
|
|
|
282
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
|
|
283
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
|
|
284
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
|
|
285
|
-
./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)
|
|
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
|
|
286
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)
|
|
287
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
|
|
288
294
|
./run.sh remove [project-dir] # remove entwurf entries from project .pi/settings.json (project scope only; global user-scope citizen left intact)
|
|
@@ -968,6 +974,19 @@ smoke_omp_fresh_live() {
|
|
|
968
974
|
run_ts scripts/smoke-omp-fresh-live.ts
|
|
969
975
|
}
|
|
970
976
|
|
|
977
|
+
smoke_pi_durable_fresh_live() {
|
|
978
|
+
# #129 first-admission acceptance, RELEASE MUST: docs/adding-a-harness.md step 9 clause 7 and
|
|
979
|
+
# the two cross-harness dispatch receipts. A collector fixture opens a REAL visible Pi through
|
|
980
|
+
# the public entwurf_fresh_call; Pi's live turn opens pi-durable through the managed verb; pd's
|
|
981
|
+
# first action calls back into Pi by exact nonce; Pi's live turn → pd (mailbox, drained by pd's
|
|
982
|
+
# live turn) and pd's live turn → Pi (control socket), relayed to the fixture. pd's actual
|
|
983
|
+
# offering and model are read from its native store via an online node:sqlite backup. Private
|
|
984
|
+
# tmux server; REAL meta roots (one Pi + one pd minted, asserted); records/transcripts/DB kept.
|
|
985
|
+
# 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.
|
|
987
|
+
run_ts scripts/smoke-pi-durable-fresh-live.ts
|
|
988
|
+
}
|
|
989
|
+
|
|
971
990
|
smoke_codex_fresh_live() {
|
|
972
991
|
# #95 first-admission RELEASE MUST. The explicit operator-owned app-server PID is the
|
|
973
992
|
# seat authority: validate its Codex app-server argv and /proc TMUX/TMUX_PANE, then use
|
|
@@ -1492,7 +1511,20 @@ check_mux_fresh_call() {
|
|
|
1492
1511
|
# codex-caller-seat rides here for the same reason as the two preflights: the leaf exists
|
|
1493
1512
|
# only as freshCall's Codex placement input (#95 lane B), so certifying it apart from the
|
|
1494
1513
|
# composition it feeds would let the two halves of one seat decision drift.
|
|
1495
|
-
|
|
1514
|
+
# pi-durable-fresh-live-receipts rides here for tmux-coordinate-row's reason: it is the
|
|
1515
|
+
# deterministic half of a LIVE sibling (smoke-pi-durable-fresh-live, #129) — the oracles that judge
|
|
1516
|
+
# that gate's receipts, proven on inline rows, so no model turn and no durable host is needed.
|
|
1517
|
+
run_vitest test/mux-fresh-call.test.ts test/fresh-call-composition.contract.test.ts test/copilot-fresh-preflight.test.ts test/codex-fresh-preflight.test.ts test/fresh-call-surfaces.contract.test.ts test/fresh-call-provider.contract.test.ts test/omp-fresh-bootstrap.contract.test.ts test/tmux-coordinate-row.test.ts test/codex-fresh-live-protocol.test.ts test/codex-caller-seat.test.ts test/pi-durable-fresh-live-receipts.test.ts
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
check_pi_durable_beside() {
|
|
1521
|
+
# #129: the pi-durable qualification lane's execution coordinate (VERIFY 「Four rules」 rule 3). It is
|
|
1522
|
+
# not a discovery path — check-tests-beside-behavior already finds these files. It exists because the
|
|
1523
|
+
# 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
|
|
1496
1528
|
}
|
|
1497
1529
|
|
|
1498
1530
|
smoke_mux_fresh_call_live() {
|
|
@@ -2806,6 +2838,18 @@ check_pi_import_surface() {
|
|
|
2806
2838
|
# `/providers/*`, and any deeper path stay FORBIDDEN (we use only `/compat`).
|
|
2807
2839
|
# Do NOT widen this to a `providers/*` subpath — it typechecks but CANNOT
|
|
2808
2840
|
# resolve under the extension loader.
|
|
2841
|
+
#
|
|
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).
|
|
2809
2853
|
# ONE corpus, TWO callers. The real scan and the denominator fixture must run the
|
|
2810
2854
|
# SAME two lines, or the fixture would prove a command the gate does not use.
|
|
2811
2855
|
pi_import_work_surface() {
|
|
@@ -2814,7 +2858,9 @@ check_pi_import_surface() {
|
|
|
2814
2858
|
pi_import_scan() {
|
|
2815
2859
|
pi_import_work_surface \
|
|
2816
2860
|
| xargs -0r grep -HnE "[\"'\`]@earendil-works/pi-(ai|coding-agent|tui)/" 2>/dev/null \
|
|
2817
|
-
| grep -vE "[\"'\`]@earendil-works/pi-ai/compat[\"'\`]" 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
|
|
2818
2864
|
}
|
|
2819
2865
|
|
|
2820
2866
|
local probe_dir probe_hits hits
|
|
@@ -2825,6 +2871,13 @@ check_pi_import_surface() {
|
|
|
2825
2871
|
printf '%s\n' 'import { getModels } from "@earendil-works/pi-ai/compat";' > tracked-allowed.ts
|
|
2826
2872
|
git add tracked-allowed.ts
|
|
2827
2873
|
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
|
|
2828
2881
|
) || { fail "[check-pi-import-surface] could not build the denominator fixture in $probe_dir"; rm -rf "$probe_dir"; return 1; }
|
|
2829
2882
|
probe_hits=$(cd "$probe_dir" && pi_import_scan)
|
|
2830
2883
|
rm -rf "$probe_dir"
|
|
@@ -2838,6 +2891,15 @@ check_pi_import_surface() {
|
|
|
2838
2891
|
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)"
|
|
2839
2892
|
return 1
|
|
2840
2893
|
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)"
|
|
2901
|
+
return 1
|
|
2902
|
+
fi
|
|
2841
2903
|
|
|
2842
2904
|
hits=$(cd "$REPO_DIR" && pi_import_scan)
|
|
2843
2905
|
if [ -n "$hits" ]; then
|
|
@@ -2845,7 +2907,7 @@ check_pi_import_surface() {
|
|
|
2845
2907
|
echo "$hits"
|
|
2846
2908
|
exit 1
|
|
2847
2909
|
fi
|
|
2848
|
-
ok "[check-pi-import-surface] pi references are root/compat-only across tracked + untracked-non-ignored ts/js; the untracked denominator
|
|
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"
|
|
2849
2911
|
}
|
|
2850
2912
|
|
|
2851
2913
|
check_env_namespace() {
|
|
@@ -3508,19 +3570,25 @@ check_pack() {
|
|
|
3508
3570
|
# Intent + policy live in NEXT.md Phase 2.3.
|
|
3509
3571
|
section "pack invariants (dry-run)"
|
|
3510
3572
|
|
|
3511
|
-
local json
|
|
3512
|
-
# --silent
|
|
3513
|
-
#
|
|
3514
|
-
# payload this parses.
|
|
3515
|
-
#
|
|
3573
|
+
local json pack_err
|
|
3574
|
+
# --silent keeps npm's own lifecycle banner off stdout, and prepack sends its build
|
|
3575
|
+
# output to stderr (`pnpm run build-bridge 1>&2`); either on stdout would pollute the
|
|
3576
|
+
# --json payload this parses. --foreground-scripts streams that stderr instead of
|
|
3577
|
+
# npm's pipe buffer, and it is CAPTURED, not discarded: a pnpm verify-deps refusal
|
|
3578
|
+
# inside prepack used to fail this gate with no reason anywhere. prepack runs on
|
|
3579
|
+
# dry-run too, which is how dist lands in this gate's file list.
|
|
3516
3580
|
# with-dist-lock wraps the WHOLE pack (prepack build-bridge emit + npm's
|
|
3517
3581
|
# post-build dist read) so a concurrent pack/build can't `rm -rf dist` mid-read
|
|
3518
3582
|
# (the 2026-07-03 phantom "dist missing" race). The nested prepack build-bridge
|
|
3519
3583
|
# is reentrant via ENTWURF_BUILD_LOCK_HELD.
|
|
3520
|
-
|
|
3584
|
+
pack_err=$(mktemp)
|
|
3585
|
+
json=$(cd "$REPO_DIR" && bash scripts/with-dist-lock.sh npm pack --dry-run --json --silent --foreground-scripts 2>"$pack_err") || {
|
|
3521
3586
|
fail "[check-pack] npm pack --dry-run failed"
|
|
3587
|
+
sed 's/^/ /' "$pack_err" >&2
|
|
3588
|
+
rm -f "$pack_err"
|
|
3522
3589
|
return 1
|
|
3523
3590
|
}
|
|
3591
|
+
rm -f "$pack_err"
|
|
3524
3592
|
|
|
3525
3593
|
local file_list
|
|
3526
3594
|
file_list=$(node -e '
|
|
@@ -3615,6 +3683,12 @@ check_pack() {
|
|
|
3615
3683
|
# check before assembling anything. The unit skeleton's package.json below is the other
|
|
3616
3684
|
# half — the installer copies it, and `pi/` ships per-FILE.
|
|
3617
3685
|
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js"
|
|
3686
|
+
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js"
|
|
3687
|
+
"mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js"
|
|
3688
|
+
"mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js"
|
|
3689
|
+
"pi/pi-durable/bootstrap.mjs"
|
|
3690
|
+
"pi/pi-durable/overlay/upstream-pin.json"
|
|
3691
|
+
"pi/pi-durable/overlay/runtime-contacts.patch"
|
|
3618
3692
|
"pi/meta-bridge-omp/entwurf-meta-omp/package.json"
|
|
3619
3693
|
"mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
|
|
3620
3694
|
"scripts/postinstall-chmod.cjs"
|
|
@@ -3743,7 +3817,7 @@ check_pack() {
|
|
|
3743
3817
|
# which is exactly what property (1)'s `(_|$)` absorbs; all three shapes are fixtures
|
|
3744
3818
|
# below so a future suffix change cannot pass vacuously.)
|
|
3745
3819
|
pack_install_leaked_pi() {
|
|
3746
|
-
grep '^@earendil-works+' | grep -Ev '@1\.0\.
|
|
3820
|
+
grep '^@earendil-works+' | grep -Ev '@1\.0\.2(_|$)' || true
|
|
3747
3821
|
}
|
|
3748
3822
|
|
|
3749
3823
|
# Matcher self-test on SYNTHETIC lookalikes: a healthy install tree cannot exercise either
|
|
@@ -3763,15 +3837,15 @@ check_pack_pin_matcher() {
|
|
|
3763
3837
|
# None may leak; the two lookalikes must — a PREFIX-EXTENDED version (`0.86.0-beta.1`,
|
|
3764
3838
|
# the prerelease shape that an unanchored match would bless) and an off-pin version.
|
|
3765
3839
|
matcher_probe=$(printf '%s\n' \
|
|
3766
|
-
'@earendil-works+pi-ai@1.0.
|
|
3767
|
-
'@earendil-works+pi-ai@1.0.
|
|
3768
|
-
'@earendil-works+pi-ai@1.0.
|
|
3769
|
-
'@earendil-works+pi-ai@1.0.
|
|
3770
|
-
'@earendil-works+pi-ai@1.0.
|
|
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' \
|
|
3771
3845
|
'@earendil-works+pi-agent-core@0.87.1' | pack_install_leaked_pi)
|
|
3772
|
-
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.
|
|
3846
|
+
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.2-beta.1
|
|
3773
3847
|
@earendil-works+pi-agent-core@0.87.1' ]; then
|
|
3774
|
-
fail "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED] the pin-leak matcher must flag the prefix-extended 1.0.
|
|
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>}"
|
|
3775
3849
|
return 1
|
|
3776
3850
|
fi
|
|
3777
3851
|
|
|
@@ -3779,9 +3853,9 @@ check_pack_pin_matcher() {
|
|
|
3779
3853
|
# (0.85.0 onward, still true at 0.99.1). An off-pin chord MUST leak; the pinned one must not. A matcher narrowed
|
|
3780
3854
|
# back to `^@earendil-works+pi-` sees nothing here and dies at this signature.
|
|
3781
3855
|
matcher_probe=$(printf '%s\n' \
|
|
3782
|
-
'@earendil-works+chord@1.0.
|
|
3856
|
+
'@earendil-works+chord@1.0.2' \
|
|
3783
3857
|
'@earendil-works+chord@0.87.1' \
|
|
3784
|
-
'@earendil-works+pi-ai@1.0.
|
|
3858
|
+
'@earendil-works+pi-ai@1.0.2' | pack_install_leaked_pi)
|
|
3785
3859
|
if [ "$matcher_probe" != '@earendil-works+chord@0.87.1' ]; then
|
|
3786
3860
|
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>}"
|
|
3787
3861
|
return 1
|
|
@@ -3981,6 +4055,12 @@ _check_pack_install_impl() {
|
|
|
3981
4055
|
# check before assembling anything. The unit skeleton's package.json below is the other
|
|
3982
4056
|
# half — the installer copies it, and `pi/` ships per-FILE.
|
|
3983
4057
|
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js"
|
|
4058
|
+
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js"
|
|
4059
|
+
"mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js"
|
|
4060
|
+
"mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js"
|
|
4061
|
+
"pi/pi-durable/bootstrap.mjs"
|
|
4062
|
+
"pi/pi-durable/overlay/upstream-pin.json"
|
|
4063
|
+
"pi/pi-durable/overlay/runtime-contacts.patch"
|
|
3984
4064
|
"pi/meta-bridge-omp/entwurf-meta-omp/package.json"
|
|
3985
4065
|
"mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
|
|
3986
4066
|
"scripts/postinstall-chmod.cjs"
|
|
@@ -4122,20 +4202,23 @@ _check_pack_install_impl() {
|
|
|
4122
4202
|
# @earendil-works/pi-codemode and @earendil-works/pi-mcp as runtime dependencies (the built-in
|
|
4123
4203
|
# codemode and MCP extensions), so both are pinned beside the eight. pi-client and pi-protocol are
|
|
4124
4204
|
# still published at 0.99.1 and keep their pins under the rule above.
|
|
4205
|
+
# `[측정 2026-10-05]` at 1.0.2 the constellation is unchanged: `npm view <pkg>@1.0.2 dependencies`
|
|
4206
|
+
# gives pi-coding-agent {chord, pi-agent-core, pi-ai, pi-codemode, pi-mcp, pi-tui}, pi-ai
|
|
4207
|
+
# {pi-telemetry}, pi-client {chord, pi-protocol}, pi-protocol {chord}, all ten published at 1.0.2.
|
|
4125
4208
|
echo "[check-pack-install] pnpm add into $tmp (with 1.0.x peers + chord + codemode + mcp + typebox)"
|
|
4126
4209
|
local install_log
|
|
4127
4210
|
install_log=$(cd "$tmp" && pnpm add \
|
|
4128
4211
|
"$tgz_path" \
|
|
4129
|
-
"@earendil-works/pi-ai@1.0.
|
|
4130
|
-
"@earendil-works/pi-coding-agent@1.0.
|
|
4131
|
-
"@earendil-works/pi-tui@1.0.
|
|
4132
|
-
"@earendil-works/pi-agent-core@1.0.
|
|
4133
|
-
"@earendil-works/pi-client@1.0.
|
|
4134
|
-
"@earendil-works/pi-protocol@1.0.
|
|
4135
|
-
"@earendil-works/pi-telemetry@1.0.
|
|
4136
|
-
"@earendil-works/chord@1.0.
|
|
4137
|
-
"@earendil-works/pi-codemode@1.0.
|
|
4138
|
-
"@earendil-works/pi-mcp@1.0.
|
|
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" \
|
|
4139
4222
|
"typebox@latest" \
|
|
4140
4223
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
4141
4224
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -4151,11 +4234,11 @@ _check_pack_install_impl() {
|
|
|
4151
4234
|
local leaked_pi
|
|
4152
4235
|
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | pack_install_leaked_pi)
|
|
4153
4236
|
if [ -n "$leaked_pi" ]; then
|
|
4154
|
-
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.0.
|
|
4237
|
+
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 1.0.2):"
|
|
4155
4238
|
printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
|
|
4156
4239
|
return 1
|
|
4157
4240
|
fi
|
|
4158
|
-
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.0.
|
|
4241
|
+
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works package is 1.0.2 (chord included)"
|
|
4159
4242
|
|
|
4160
4243
|
# Resolve the installed package.json and confirm pi.extensions
|
|
4161
4244
|
# arrived intact. If pi.extensions is empty or missing, the
|
|
@@ -4174,6 +4257,34 @@ _check_pack_install_impl() {
|
|
|
4174
4257
|
}
|
|
4175
4258
|
echo "[check-pack-install] installed: $probe"
|
|
4176
4259
|
|
|
4260
|
+
# #129 — the packaged durable bootstrap, imported FROM the installed tree. The tarball listing
|
|
4261
|
+
# above proves the file ships, not that its static imports reach the shipped compiled closure
|
|
4262
|
+
# under node_modules (where a checkout .ts import would be refused by the strip-types fence), nor
|
|
4263
|
+
# that the bridge entry it hands the adapter is this package's own dist. Import only: main() runs
|
|
4264
|
+
# solely when the file is the process entry, and the runtime/TUI are dynamic imports inside it, so
|
|
4265
|
+
# no runtime, TUI, birth or bridge starts here.
|
|
4266
|
+
local durable_proof
|
|
4267
|
+
durable_proof=$(cd "$tmp" && node --input-type=module -e "
|
|
4268
|
+
const { realpathSync } = await import('node:fs');
|
|
4269
|
+
const pkg = realpathSync(process.cwd() + '/node_modules/@junghanacs/entwurf');
|
|
4270
|
+
const m = await import(pkg + '/pi/pi-durable/bootstrap.mjs');
|
|
4271
|
+
for (const name of ['main', 'openDurableCitizen']) {
|
|
4272
|
+
if (typeof m[name] !== 'function') { console.error(name + ' is not an exported function'); process.exit(1); }
|
|
4273
|
+
}
|
|
4274
|
+
const want = pkg + '/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js';
|
|
4275
|
+
const entry = m.PACKAGED_BRIDGE_ENTRY;
|
|
4276
|
+
if (typeof entry !== 'string' || realpathSync(entry) !== want) {
|
|
4277
|
+
console.error('PACKAGED_BRIDGE_ENTRY ' + entry + ' is not the dist entry of the installed package (' + want + ')');
|
|
4278
|
+
process.exit(1);
|
|
4279
|
+
}
|
|
4280
|
+
console.log('exports main/openDurableCitizen; PACKAGED_BRIDGE_ENTRY is the installed dist entry');
|
|
4281
|
+
" 2>&1) || {
|
|
4282
|
+
fail "[check-pack-install] installed durable bootstrap import failed:"
|
|
4283
|
+
echo "$durable_proof" | sed 's/^/ /' >&2
|
|
4284
|
+
return 1
|
|
4285
|
+
}
|
|
4286
|
+
echo "[check-pack-install] installed durable bootstrap: $durable_proof"
|
|
4287
|
+
|
|
4177
4288
|
# #116 M3-b1/b2 — THE ACTUAL-PACKAGE RUNTIME PROOF, THROUGH THE SHIPPED OWNER.
|
|
4178
4289
|
# The Herdr plugin's runtime verifier decides whether a tree npm placed is a runtime the scoped
|
|
4179
4290
|
# wiring may name: exact name@version, the compiled entry, all three required bins present AND
|
|
@@ -4559,7 +4670,7 @@ sys.exit(0 if any(isinstance(s,str) and s.rstrip('/')== '$npm2_pkg' for s in src
|
|
|
4559
4670
|
return 1
|
|
4560
4671
|
fi
|
|
4561
4672
|
local skip_probe
|
|
4562
|
-
for skip_probe in "pi: SKIP" "claude: SKIP" "agy: SKIP" "copilot: SKIP" "omp: SKIP" "codex: SKIP"; do
|
|
4673
|
+
for skip_probe in "pi: SKIP" "claude: SKIP" "agy: SKIP" "copilot: SKIP" "omp: SKIP" "codex: SKIP" "pi-durable: SKIP"; do
|
|
4563
4674
|
if ! grep -q "$skip_probe" <<<"$setup_out"; then
|
|
4564
4675
|
fail "[QK:CODEX-PACK-SETUP-ZERO-STATE] [check-pack-install] installed all-absent setup missing explicit zero-state '$skip_probe':"
|
|
4565
4676
|
echo "$setup_out" | tail -25 | sed 's/^/ /' >&2
|
|
@@ -6024,6 +6135,20 @@ setup_all() {
|
|
|
6024
6135
|
setup_result codex-terminal-title FAIL "detected codex, but the terminal-title setting did not complete (see above)"
|
|
6025
6136
|
fi
|
|
6026
6137
|
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).
|
|
6144
|
+
local pd_rc pd_out
|
|
6145
|
+
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
|
|
6151
|
+
|
|
6027
6152
|
# ── core bridge boundary ── deterministic preflight lives in `pnpm run
|
|
6028
6153
|
# check:full`; live substrate acceptance lives in `LIVE=1 ./run.sh
|
|
6029
6154
|
# release-gate <scratch> --cut`. Setup is the install path, so it verifies the
|
|
@@ -6536,6 +6661,8 @@ release_gate() {
|
|
|
6536
6661
|
# Codex then opens the outbound Pi and correlates that callback. Actor coordinates travel,
|
|
6537
6662
|
# and fresh Codex == app-server/MCP inherited session == outbound Pi is a hard check.
|
|
6538
6663
|
run_live_step "smoke-codex-fresh-live (#95: visible Pi -> visible Codex/callback/addressed v2 -> visible Pi/callback)" gate bash "$self" smoke-codex-fresh-live
|
|
6664
|
+
# #129 first-admission: step 9 clause 7 + the two cross-harness receipts for pi-durable.
|
|
6665
|
+
run_live_step "smoke-pi-durable-fresh-live (#129: visible Pi -> visible pi-durable/callback/addressed v2 -> Pi relay)" gate bash "$self" smoke-pi-durable-fresh-live
|
|
6539
6666
|
|
|
6540
6667
|
# 4. BEHAVIOR lane (advisory, non-blocking). Model-in-loop gates that probe
|
|
6541
6668
|
# whether the model AUTONOMOUSLY drives the MCP entwurf surface. These never
|
|
@@ -6660,6 +6787,9 @@ case "$cmd" in
|
|
|
6660
6787
|
smoke-omp-fresh-live)
|
|
6661
6788
|
smoke_omp_fresh_live
|
|
6662
6789
|
;;
|
|
6790
|
+
smoke-pi-durable-fresh-live)
|
|
6791
|
+
smoke_pi_durable_fresh_live
|
|
6792
|
+
;;
|
|
6663
6793
|
check-capability-bundle-reach)
|
|
6664
6794
|
check_capability_bundle_reach
|
|
6665
6795
|
;;
|
|
@@ -6699,6 +6829,26 @@ case "$cmd" in
|
|
|
6699
6829
|
# on the status line; and still zero mailbox/receiver marker. Hermetic; no omp, no model turn
|
|
6700
6830
|
run_ts scripts/check-omp-birth-hook.ts
|
|
6701
6831
|
;;
|
|
6832
|
+
check-pi-durable-contact)
|
|
6833
|
+
# #129 L-identity G-contact, checkout-only. Spawning gate (VERIFY: a vitest lane cannot hold
|
|
6834
|
+
# it): the real overlay durable app as a child host, the branch-emitted bridge as ITS child,
|
|
6835
|
+
# /proc as the PPID oracle. Both runtime inputs are operator-provisioned; absent → SKIP 97,
|
|
6836
|
+
# never pass. Installed: run_ts refuses it (no compiled twin) before any input is read.
|
|
6837
|
+
run_ts scripts/check-pi-durable-contact.ts
|
|
6838
|
+
;;
|
|
6839
|
+
check-pi-durable-send)
|
|
6840
|
+
# #129 L-send first cell, checkout-only spawning gate: one native durable turn against a
|
|
6841
|
+
# gate-owned scripted endpoint (S) through the native ToolTask (H) to a seeded target. No
|
|
6842
|
+
# vendor turn (V). Inputs as check-pi-durable-contact; absent → SKIP 97.
|
|
6843
|
+
run_ts scripts/check-pi-durable-send.ts
|
|
6844
|
+
;;
|
|
6845
|
+
check-pi-durable-receive)
|
|
6846
|
+
# #129 L-receive first cell, checkout-only spawning gate: no controller input; a gate-owned
|
|
6847
|
+
# sending bridge enqueues, the host's doorbell admits to the root, the scripted endpoint (S)
|
|
6848
|
+
# holds request #1 until the enqueue is captured, the native turn (H) drains it. No vendor (V).
|
|
6849
|
+
# Inputs as check-pi-durable-contact; absent → SKIP 97.
|
|
6850
|
+
run_ts scripts/check-pi-durable-receive.ts
|
|
6851
|
+
;;
|
|
6702
6852
|
check-copilot-statusline)
|
|
6703
6853
|
check_copilot_statusline
|
|
6704
6854
|
;;
|
|
@@ -6777,6 +6927,9 @@ case "$cmd" in
|
|
|
6777
6927
|
check-mux-fresh-call)
|
|
6778
6928
|
check_mux_fresh_call
|
|
6779
6929
|
;;
|
|
6930
|
+
check-pi-durable-beside)
|
|
6931
|
+
check_pi_durable_beside
|
|
6932
|
+
;;
|
|
6780
6933
|
check-mux-resume-call)
|
|
6781
6934
|
check_mux_resume_call
|
|
6782
6935
|
;;
|
|
@@ -7415,6 +7568,20 @@ case "$cmd" in
|
|
|
7415
7568
|
shift || true
|
|
7416
7569
|
exec bash "$REPO_DIR/scripts/copilot-launch.sh" "$@"
|
|
7417
7570
|
;;
|
|
7571
|
+
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.
|
|
7575
|
+
#
|
|
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.
|
|
7581
|
+
shift || true
|
|
7582
|
+
pd_resolver=$(run_ts pi-extensions/lib/pi-durable-runtime.ts resolve) || exit $?
|
|
7583
|
+
exec node --import "$pd_resolver" "$REPO_DIR/pi/pi-durable/bootstrap.mjs" "$@"
|
|
7584
|
+
;;
|
|
7418
7585
|
pi)
|
|
7419
7586
|
# #118 홉 2: the managed pi launch. Same shape and same reasons as `copilot` above —
|
|
7420
7587
|
# `exec`, no subshell and no cd, because this operates on the operator's session; and
|
|
@@ -138,6 +138,24 @@ async function main(): Promise<void> {
|
|
|
138
138
|
!herdrBranch.includes("codexCallerFreshPreflight"),
|
|
139
139
|
);
|
|
140
140
|
|
|
141
|
+
// #129: pi-durable joined the tmux fresh set, NOT the herdr pilot set (GLG, 2026-10-06: no herdr
|
|
142
|
+
// pi-durable support in 0.31). Same axis as the codex cell: refused by the herdr reason, nothing
|
|
143
|
+
// spawned, no tmux fallback, and its operator-runtime preflight is never asked on this branch.
|
|
144
|
+
const durable = recordingSpawn();
|
|
145
|
+
const durableRefused = await dispatchFreshCall(
|
|
146
|
+
{ ...REQUEST, backend: "pi-durable", model: "loopback/scripted" },
|
|
147
|
+
HERDR_ENV,
|
|
148
|
+
durable.spawn,
|
|
149
|
+
);
|
|
150
|
+
ok(
|
|
151
|
+
"[QK:FCD-HERDR-PI-DURABLE-UNSUPPORTED] inside herdr pi-durable is not a pilot backend: it refuses by the herdr reason with nothing spawned, never falls back to a tmux window, and its runtime preflight is never consulted there",
|
|
152
|
+
durableRefused.rail === "herdr" &&
|
|
153
|
+
!durableRefused.result.ok &&
|
|
154
|
+
durableRefused.result.reason === "herdr-backend-unsupported" &&
|
|
155
|
+
durable.calls.length === 0 &&
|
|
156
|
+
!herdrBranch.includes("piDurable"),
|
|
157
|
+
);
|
|
158
|
+
|
|
141
159
|
// ── the tmux rail keeps its pre-existing ordering ────────────────────────────────────
|
|
142
160
|
// The import line names the preflight too, so the body is what gets counted: the claim is
|
|
143
161
|
// "called once, on one path", not "the word appears once".
|
|
@@ -3346,6 +3346,7 @@ let manifestCount: number;
|
|
|
3346
3346
|
"pi-bridge-sender": 4,
|
|
3347
3347
|
"pi-mcp-bridge": 2,
|
|
3348
3348
|
"pi-mcp-register": 3,
|
|
3349
|
+
"pi-durable": 24,
|
|
3349
3350
|
"copilot-receive": 20,
|
|
3350
3351
|
"entwurf-peers": 1,
|
|
3351
3352
|
"fresh-call-dispatch": 11,
|
|
@@ -3365,7 +3366,7 @@ let manifestCount: number;
|
|
|
3365
3366
|
"meta-identity": 4,
|
|
3366
3367
|
"meta-retire": 4,
|
|
3367
3368
|
"mux-boundary": 16,
|
|
3368
|
-
"mux-fresh-call":
|
|
3369
|
+
"mux-fresh-call": 65,
|
|
3369
3370
|
"mux-launcher-fence": 8,
|
|
3370
3371
|
"mux-parent-artifact": 3,
|
|
3371
3372
|
"pack-install": 3,
|