@junghanacs/entwurf 0.30.0 → 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 +229 -0
- package/DELIVERY.md +1 -0
- package/README.md +49 -4
- package/VERIFY.md +23 -4
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +111 -18
- 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/acp/backend-adapter.js +43 -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 +15 -12
- 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/acp/backend-adapter.ts +68 -0
- package/pi-extensions/lib/acp/backend.ts +41 -5
- 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 +214 -36
- package/scripts/check-fresh-call-dispatch.ts +18 -0
- package/scripts/check-gate-qualification.ts +4 -2
- package/scripts/check-herdr-plugin-build.ts +159 -57
- 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/fixtures/herdr-supply.json +8 -8
- 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/acp-prompt-lifecycle.json +2 -2
- package/scripts/mutants/acp-vendor-rejection.json +62 -0
- package/scripts/mutants/control-send-receipt.json +1 -1
- package/scripts/mutants/copilot-birth.json +2 -2
- package/scripts/mutants/herdr-plugin-build.json +11 -0
- package/scripts/mutants/herdr-supply.json +3 -3
- 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-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-herdr-fresh-call-live.ts +21 -7
- 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
|
|
@@ -1348,6 +1367,14 @@ check_acp_foreground_only() {
|
|
|
1348
1367
|
run_vitest pi-extensions/lib/acp/backend-adapter.test.ts
|
|
1349
1368
|
}
|
|
1350
1369
|
|
|
1370
|
+
check_acp_vendor_rejection() {
|
|
1371
|
+
# Behaviour-adjacent tests are discovered by the glob lane. This narrow case is the
|
|
1372
|
+
# mutant execution coordinate: include the adapter admission and real turn pipeline,
|
|
1373
|
+
# and keep run_vitest's failed-title attribution for qualification.
|
|
1374
|
+
section "ACP vendor rejection admission (mutant execution coordinate)"
|
|
1375
|
+
run_vitest pi-extensions/lib/acp/backend-adapter.test.ts pi-extensions/lib/acp/backend.vendor-rejection.test.ts
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1351
1378
|
check_pi_mcp_register() {
|
|
1352
1379
|
# NOT a discovery path — check-tests-beside-behavior finds the test by glob. This case is the
|
|
1353
1380
|
# MUTANT EXECUTION COORDINATE for scripts/mutants/pi-mcp-register.json (same reasoning as
|
|
@@ -1484,7 +1511,20 @@ check_mux_fresh_call() {
|
|
|
1484
1511
|
# codex-caller-seat rides here for the same reason as the two preflights: the leaf exists
|
|
1485
1512
|
# only as freshCall's Codex placement input (#95 lane B), so certifying it apart from the
|
|
1486
1513
|
# composition it feeds would let the two halves of one seat decision drift.
|
|
1487
|
-
|
|
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
|
|
1488
1528
|
}
|
|
1489
1529
|
|
|
1490
1530
|
smoke_mux_fresh_call_live() {
|
|
@@ -1622,9 +1662,9 @@ smoke_acp_session_reuse_live() {
|
|
|
1622
1662
|
# needs LIVE=1. Forces process-scoped (pushes --entwurf-control into argv) and
|
|
1623
1663
|
# drives TWO real ACP turns over ONE reused claude-agent-acp child via the real
|
|
1624
1664
|
# streamShellAcp: turn 1 introduces a codeword (full transcript), turn 2 sends
|
|
1625
|
-
# ONLY the latest user delta
|
|
1626
|
-
#
|
|
1627
|
-
#
|
|
1665
|
+
# ONLY the latest user delta. The REUSE lifecycle notice, with no new bootstrap,
|
|
1666
|
+
# is the verdict; codeword recall is supporting only (a rebuilt full transcript
|
|
1667
|
+
# could recall it too). The one-shot exit0 half is owned by
|
|
1628
1668
|
# smoke-acp-provider-live.
|
|
1629
1669
|
# Model override: ENTWURF_ACP_PROVIDER_MODEL (default claude-sonnet-5).
|
|
1630
1670
|
# LIVE=1 ./run.sh smoke-acp-session-reuse-live
|
|
@@ -2798,6 +2838,18 @@ check_pi_import_surface() {
|
|
|
2798
2838
|
# `/providers/*`, and any deeper path stay FORBIDDEN (we use only `/compat`).
|
|
2799
2839
|
# Do NOT widen this to a `providers/*` subpath — it typechecks but CANNOT
|
|
2800
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).
|
|
2801
2853
|
# ONE corpus, TWO callers. The real scan and the denominator fixture must run the
|
|
2802
2854
|
# SAME two lines, or the fixture would prove a command the gate does not use.
|
|
2803
2855
|
pi_import_work_surface() {
|
|
@@ -2806,7 +2858,9 @@ check_pi_import_surface() {
|
|
|
2806
2858
|
pi_import_scan() {
|
|
2807
2859
|
pi_import_work_surface \
|
|
2808
2860
|
| xargs -0r grep -HnE "[\"'\`]@earendil-works/pi-(ai|coding-agent|tui)/" 2>/dev/null \
|
|
2809
|
-
| 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
|
|
2810
2864
|
}
|
|
2811
2865
|
|
|
2812
2866
|
local probe_dir probe_hits hits
|
|
@@ -2817,6 +2871,13 @@ check_pi_import_surface() {
|
|
|
2817
2871
|
printf '%s\n' 'import { getModels } from "@earendil-works/pi-ai/compat";' > tracked-allowed.ts
|
|
2818
2872
|
git add tracked-allowed.ts
|
|
2819
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
|
|
2820
2881
|
) || { fail "[check-pi-import-surface] could not build the denominator fixture in $probe_dir"; rm -rf "$probe_dir"; return 1; }
|
|
2821
2882
|
probe_hits=$(cd "$probe_dir" && pi_import_scan)
|
|
2822
2883
|
rm -rf "$probe_dir"
|
|
@@ -2830,6 +2891,15 @@ check_pi_import_surface() {
|
|
|
2830
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)"
|
|
2831
2892
|
return 1
|
|
2832
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
|
|
2833
2903
|
|
|
2834
2904
|
hits=$(cd "$REPO_DIR" && pi_import_scan)
|
|
2835
2905
|
if [ -n "$hits" ]; then
|
|
@@ -2837,7 +2907,7 @@ check_pi_import_surface() {
|
|
|
2837
2907
|
echo "$hits"
|
|
2838
2908
|
exit 1
|
|
2839
2909
|
fi
|
|
2840
|
-
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"
|
|
2841
2911
|
}
|
|
2842
2912
|
|
|
2843
2913
|
check_env_namespace() {
|
|
@@ -3500,19 +3570,25 @@ check_pack() {
|
|
|
3500
3570
|
# Intent + policy live in NEXT.md Phase 2.3.
|
|
3501
3571
|
section "pack invariants (dry-run)"
|
|
3502
3572
|
|
|
3503
|
-
local json
|
|
3504
|
-
# --silent
|
|
3505
|
-
#
|
|
3506
|
-
# payload this parses.
|
|
3507
|
-
#
|
|
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.
|
|
3508
3580
|
# with-dist-lock wraps the WHOLE pack (prepack build-bridge emit + npm's
|
|
3509
3581
|
# post-build dist read) so a concurrent pack/build can't `rm -rf dist` mid-read
|
|
3510
3582
|
# (the 2026-07-03 phantom "dist missing" race). The nested prepack build-bridge
|
|
3511
3583
|
# is reentrant via ENTWURF_BUILD_LOCK_HELD.
|
|
3512
|
-
|
|
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") || {
|
|
3513
3586
|
fail "[check-pack] npm pack --dry-run failed"
|
|
3587
|
+
sed 's/^/ /' "$pack_err" >&2
|
|
3588
|
+
rm -f "$pack_err"
|
|
3514
3589
|
return 1
|
|
3515
3590
|
}
|
|
3591
|
+
rm -f "$pack_err"
|
|
3516
3592
|
|
|
3517
3593
|
local file_list
|
|
3518
3594
|
file_list=$(node -e '
|
|
@@ -3607,6 +3683,12 @@ check_pack() {
|
|
|
3607
3683
|
# check before assembling anything. The unit skeleton's package.json below is the other
|
|
3608
3684
|
# half — the installer copies it, and `pi/` ships per-FILE.
|
|
3609
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"
|
|
3610
3692
|
"pi/meta-bridge-omp/entwurf-meta-omp/package.json"
|
|
3611
3693
|
"mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
|
|
3612
3694
|
"scripts/postinstall-chmod.cjs"
|
|
@@ -3735,7 +3817,7 @@ check_pack() {
|
|
|
3735
3817
|
# which is exactly what property (1)'s `(_|$)` absorbs; all three shapes are fixtures
|
|
3736
3818
|
# below so a future suffix change cannot pass vacuously.)
|
|
3737
3819
|
pack_install_leaked_pi() {
|
|
3738
|
-
grep '^@earendil-works+' | grep -Ev '@1\.0\.
|
|
3820
|
+
grep '^@earendil-works+' | grep -Ev '@1\.0\.2(_|$)' || true
|
|
3739
3821
|
}
|
|
3740
3822
|
|
|
3741
3823
|
# Matcher self-test on SYNTHETIC lookalikes: a healthy install tree cannot exercise either
|
|
@@ -3755,15 +3837,15 @@ check_pack_pin_matcher() {
|
|
|
3755
3837
|
# None may leak; the two lookalikes must — a PREFIX-EXTENDED version (`0.86.0-beta.1`,
|
|
3756
3838
|
# the prerelease shape that an unanchored match would bless) and an off-pin version.
|
|
3757
3839
|
matcher_probe=$(printf '%s\n' \
|
|
3758
|
-
'@earendil-works+pi-ai@1.0.
|
|
3759
|
-
'@earendil-works+pi-ai@1.0.
|
|
3760
|
-
'@earendil-works+pi-ai@1.0.
|
|
3761
|
-
'@earendil-works+pi-ai@1.0.
|
|
3762
|
-
'@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' \
|
|
3763
3845
|
'@earendil-works+pi-agent-core@0.87.1' | pack_install_leaked_pi)
|
|
3764
|
-
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.
|
|
3846
|
+
if [ "$matcher_probe" != '@earendil-works+pi-ai@1.0.2-beta.1
|
|
3765
3847
|
@earendil-works+pi-agent-core@0.87.1' ]; then
|
|
3766
|
-
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>}"
|
|
3767
3849
|
return 1
|
|
3768
3850
|
fi
|
|
3769
3851
|
|
|
@@ -3771,9 +3853,9 @@ check_pack_pin_matcher() {
|
|
|
3771
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
|
|
3772
3854
|
# back to `^@earendil-works+pi-` sees nothing here and dies at this signature.
|
|
3773
3855
|
matcher_probe=$(printf '%s\n' \
|
|
3774
|
-
'@earendil-works+chord@1.0.
|
|
3856
|
+
'@earendil-works+chord@1.0.2' \
|
|
3775
3857
|
'@earendil-works+chord@0.87.1' \
|
|
3776
|
-
'@earendil-works+pi-ai@1.0.
|
|
3858
|
+
'@earendil-works+pi-ai@1.0.2' | pack_install_leaked_pi)
|
|
3777
3859
|
if [ "$matcher_probe" != '@earendil-works+chord@0.87.1' ]; then
|
|
3778
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>}"
|
|
3779
3861
|
return 1
|
|
@@ -3973,6 +4055,12 @@ _check_pack_install_impl() {
|
|
|
3973
4055
|
# check before assembling anything. The unit skeleton's package.json below is the other
|
|
3974
4056
|
# half — the installer copies it, and `pi/` ships per-FILE.
|
|
3975
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"
|
|
3976
4064
|
"pi/meta-bridge-omp/entwurf-meta-omp/package.json"
|
|
3977
4065
|
"mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js"
|
|
3978
4066
|
"scripts/postinstall-chmod.cjs"
|
|
@@ -4114,20 +4202,23 @@ _check_pack_install_impl() {
|
|
|
4114
4202
|
# @earendil-works/pi-codemode and @earendil-works/pi-mcp as runtime dependencies (the built-in
|
|
4115
4203
|
# codemode and MCP extensions), so both are pinned beside the eight. pi-client and pi-protocol are
|
|
4116
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.
|
|
4117
4208
|
echo "[check-pack-install] pnpm add into $tmp (with 1.0.x peers + chord + codemode + mcp + typebox)"
|
|
4118
4209
|
local install_log
|
|
4119
4210
|
install_log=$(cd "$tmp" && pnpm add \
|
|
4120
4211
|
"$tgz_path" \
|
|
4121
|
-
"@earendil-works/pi-ai@1.0.
|
|
4122
|
-
"@earendil-works/pi-coding-agent@1.0.
|
|
4123
|
-
"@earendil-works/pi-tui@1.0.
|
|
4124
|
-
"@earendil-works/pi-agent-core@1.0.
|
|
4125
|
-
"@earendil-works/pi-client@1.0.
|
|
4126
|
-
"@earendil-works/pi-protocol@1.0.
|
|
4127
|
-
"@earendil-works/pi-telemetry@1.0.
|
|
4128
|
-
"@earendil-works/chord@1.0.
|
|
4129
|
-
"@earendil-works/pi-codemode@1.0.
|
|
4130
|
-
"@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" \
|
|
4131
4222
|
"typebox@latest" \
|
|
4132
4223
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
4133
4224
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -4143,11 +4234,11 @@ _check_pack_install_impl() {
|
|
|
4143
4234
|
local leaked_pi
|
|
4144
4235
|
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | pack_install_leaked_pi)
|
|
4145
4236
|
if [ -n "$leaked_pi" ]; then
|
|
4146
|
-
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):"
|
|
4147
4238
|
printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
|
|
4148
4239
|
return 1
|
|
4149
4240
|
fi
|
|
4150
|
-
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)"
|
|
4151
4242
|
|
|
4152
4243
|
# Resolve the installed package.json and confirm pi.extensions
|
|
4153
4244
|
# arrived intact. If pi.extensions is empty or missing, the
|
|
@@ -4166,6 +4257,34 @@ _check_pack_install_impl() {
|
|
|
4166
4257
|
}
|
|
4167
4258
|
echo "[check-pack-install] installed: $probe"
|
|
4168
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
|
+
|
|
4169
4288
|
# #116 M3-b1/b2 — THE ACTUAL-PACKAGE RUNTIME PROOF, THROUGH THE SHIPPED OWNER.
|
|
4170
4289
|
# The Herdr plugin's runtime verifier decides whether a tree npm placed is a runtime the scoped
|
|
4171
4290
|
# wiring may name: exact name@version, the compiled entry, all three required bins present AND
|
|
@@ -4551,7 +4670,7 @@ sys.exit(0 if any(isinstance(s,str) and s.rstrip('/')== '$npm2_pkg' for s in src
|
|
|
4551
4670
|
return 1
|
|
4552
4671
|
fi
|
|
4553
4672
|
local skip_probe
|
|
4554
|
-
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
|
|
4555
4674
|
if ! grep -q "$skip_probe" <<<"$setup_out"; then
|
|
4556
4675
|
fail "[QK:CODEX-PACK-SETUP-ZERO-STATE] [check-pack-install] installed all-absent setup missing explicit zero-state '$skip_probe':"
|
|
4557
4676
|
echo "$setup_out" | tail -25 | sed 's/^/ /' >&2
|
|
@@ -6016,6 +6135,20 @@ setup_all() {
|
|
|
6016
6135
|
setup_result codex-terminal-title FAIL "detected codex, but the terminal-title setting did not complete (see above)"
|
|
6017
6136
|
fi
|
|
6018
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
|
+
|
|
6019
6152
|
# ── core bridge boundary ── deterministic preflight lives in `pnpm run
|
|
6020
6153
|
# check:full`; live substrate acceptance lives in `LIVE=1 ./run.sh
|
|
6021
6154
|
# release-gate <scratch> --cut`. Setup is the install path, so it verifies the
|
|
@@ -6528,6 +6661,8 @@ release_gate() {
|
|
|
6528
6661
|
# Codex then opens the outbound Pi and correlates that callback. Actor coordinates travel,
|
|
6529
6662
|
# and fresh Codex == app-server/MCP inherited session == outbound Pi is a hard check.
|
|
6530
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
|
|
6531
6666
|
|
|
6532
6667
|
# 4. BEHAVIOR lane (advisory, non-blocking). Model-in-loop gates that probe
|
|
6533
6668
|
# whether the model AUTONOMOUSLY drives the MCP entwurf surface. These never
|
|
@@ -6652,6 +6787,9 @@ case "$cmd" in
|
|
|
6652
6787
|
smoke-omp-fresh-live)
|
|
6653
6788
|
smoke_omp_fresh_live
|
|
6654
6789
|
;;
|
|
6790
|
+
smoke-pi-durable-fresh-live)
|
|
6791
|
+
smoke_pi_durable_fresh_live
|
|
6792
|
+
;;
|
|
6655
6793
|
check-capability-bundle-reach)
|
|
6656
6794
|
check_capability_bundle_reach
|
|
6657
6795
|
;;
|
|
@@ -6691,6 +6829,26 @@ case "$cmd" in
|
|
|
6691
6829
|
# on the status line; and still zero mailbox/receiver marker. Hermetic; no omp, no model turn
|
|
6692
6830
|
run_ts scripts/check-omp-birth-hook.ts
|
|
6693
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
|
+
;;
|
|
6694
6852
|
check-copilot-statusline)
|
|
6695
6853
|
check_copilot_statusline
|
|
6696
6854
|
;;
|
|
@@ -6769,6 +6927,9 @@ case "$cmd" in
|
|
|
6769
6927
|
check-mux-fresh-call)
|
|
6770
6928
|
check_mux_fresh_call
|
|
6771
6929
|
;;
|
|
6930
|
+
check-pi-durable-beside)
|
|
6931
|
+
check_pi_durable_beside
|
|
6932
|
+
;;
|
|
6772
6933
|
check-mux-resume-call)
|
|
6773
6934
|
check_mux_resume_call
|
|
6774
6935
|
;;
|
|
@@ -7407,6 +7568,20 @@ case "$cmd" in
|
|
|
7407
7568
|
shift || true
|
|
7408
7569
|
exec bash "$REPO_DIR/scripts/copilot-launch.sh" "$@"
|
|
7409
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
|
+
;;
|
|
7410
7585
|
pi)
|
|
7411
7586
|
# #118 홉 2: the managed pi launch. Same shape and same reasons as `copilot` above —
|
|
7412
7587
|
# `exec`, no subshell and no cd, because this operates on the operator's session; and
|
|
@@ -7716,6 +7891,9 @@ case "$cmd" in
|
|
|
7716
7891
|
check-acp-prompt-lifecycle)
|
|
7717
7892
|
check_acp_prompt_lifecycle
|
|
7718
7893
|
;;
|
|
7894
|
+
check-acp-vendor-rejection)
|
|
7895
|
+
check_acp_vendor_rejection
|
|
7896
|
+
;;
|
|
7719
7897
|
check-acp-launch-namespace)
|
|
7720
7898
|
check_acp_launch_namespace
|
|
7721
7899
|
;;
|
|
@@ -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".
|
|
@@ -3328,6 +3328,7 @@ let manifestCount: number;
|
|
|
3328
3328
|
"acp-stop-reason": 6,
|
|
3329
3329
|
"acp-stream-hooks": 10,
|
|
3330
3330
|
"acp-usage-accounting": 12,
|
|
3331
|
+
"acp-vendor-rejection": 4,
|
|
3331
3332
|
"agy-permission": 6,
|
|
3332
3333
|
"bridge-boot-resume": 5,
|
|
3333
3334
|
"bridge-command-boot": 12,
|
|
@@ -3345,6 +3346,7 @@ let manifestCount: number;
|
|
|
3345
3346
|
"pi-bridge-sender": 4,
|
|
3346
3347
|
"pi-mcp-bridge": 2,
|
|
3347
3348
|
"pi-mcp-register": 3,
|
|
3349
|
+
"pi-durable": 24,
|
|
3348
3350
|
"copilot-receive": 20,
|
|
3349
3351
|
"entwurf-peers": 1,
|
|
3350
3352
|
"fresh-call-dispatch": 11,
|
|
@@ -3354,7 +3356,7 @@ let manifestCount: number;
|
|
|
3354
3356
|
"herdr-plugin": 25,
|
|
3355
3357
|
"herdr-plugin-profile": 14,
|
|
3356
3358
|
"herdr-activation": 25,
|
|
3357
|
-
"herdr-plugin-build":
|
|
3359
|
+
"herdr-plugin-build": 14,
|
|
3358
3360
|
"herdr-runtime-bootstrap": 31,
|
|
3359
3361
|
"herdr-fresh-call": 38,
|
|
3360
3362
|
"herdr-supply": 11,
|
|
@@ -3364,7 +3366,7 @@ let manifestCount: number;
|
|
|
3364
3366
|
"meta-identity": 4,
|
|
3365
3367
|
"meta-retire": 4,
|
|
3366
3368
|
"mux-boundary": 16,
|
|
3367
|
-
"mux-fresh-call":
|
|
3369
|
+
"mux-fresh-call": 65,
|
|
3368
3370
|
"mux-launcher-fence": 8,
|
|
3369
3371
|
"mux-parent-artifact": 3,
|
|
3370
3372
|
"pack-install": 3,
|