@junghanacs/entwurf 0.12.8 → 0.12.10
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 +134 -248
- package/BASELINE.md +1 -1
- package/CHANGELOG.md +39 -1
- package/DELIVERY.md +5 -4
- package/README.md +148 -23
- package/VERIFY.md +3 -2
- package/demo/README.md +2 -2
- package/demo/demo.sh +7 -1
- package/docs/setup-clean-host.md +24 -7
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +168 -81
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +12 -12
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +5 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +16 -18
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +14 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +11 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +15 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +500 -54
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +8 -3
- package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +14 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +155 -29
- package/mcp/entwurf-bridge/src/index.ts +200 -94
- package/package.json +11 -9
- package/pi-extensions/entwurf-control.ts +81 -39
- package/pi-extensions/lib/acp/models.ts +12 -12
- package/pi-extensions/lib/acp/overlay.ts +5 -3
- package/pi-extensions/lib/entwurf-core.ts +26 -9
- package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
- package/pi-extensions/lib/entwurf-fact-provider.ts +24 -19
- package/pi-extensions/lib/entwurf-facts.ts +13 -13
- package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
- package/pi-extensions/lib/entwurf-self-address.ts +8 -9
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
- package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
- package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
- package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
- package/pi-extensions/lib/entwurf-v2-production.ts +22 -13
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +11 -3
- package/pi-extensions/lib/meta-sender-identity.ts +15 -5
- package/pi-extensions/lib/meta-session.ts +543 -58
- package/pi-extensions/meta-bridge-hook.ts +8 -2
- package/run.sh +78 -67
- package/scripts/agy-bridge-config.py +249 -49
- package/scripts/agy-bridge.sh +59 -14
- package/scripts/agy-imprint.ts +15 -1
- package/scripts/check-acp-carrier-augment.ts +34 -2
- package/scripts/check-acp-sdk-surface.ts +22 -11
- package/scripts/check-acp-session-reuse.ts +1 -1
- package/scripts/check-acp-session-store.ts +3 -3
- package/scripts/check-agy-permission-matrix.py +655 -0
- package/scripts/check-agy-sender-identity.ts +83 -0
- package/scripts/check-entwurf-control-rpc.ts +2 -2
- package/scripts/check-entwurf-deliverability.ts +9 -6
- package/scripts/check-entwurf-fact-provider.ts +16 -8
- package/scripts/check-entwurf-facts.ts +13 -13
- package/scripts/check-entwurf-resume-args.ts +25 -63
- package/scripts/check-entwurf-self-address.ts +187 -4
- package/scripts/check-entwurf-session-identity.ts +7 -6
- package/scripts/check-entwurf-v2-contract.ts +2 -2
- package/scripts/check-entwurf-v2-production.ts +9 -7
- package/scripts/check-entwurf-v2-spawn-production.ts +8 -4
- package/scripts/check-entwurf-v2-surface.ts +327 -14
- package/scripts/check-fresh-cut-gate.sh +305 -4
- package/scripts/check-gate-qualification.ts +785 -0
- package/scripts/check-meta-identity-consumers.ts +501 -1
- package/scripts/check-meta-listing.ts +91 -9
- package/scripts/check-meta-receiver-marker.ts +54 -0
- package/scripts/check-model-lock.ts +1 -1
- package/scripts/check-shell-quote.ts +2 -1
- package/scripts/lib/mutation-qualify.ts +794 -0
- package/scripts/meta-bridge-fresh-cut.ts +164 -28
- package/scripts/mutants/acp-augment.json +30 -0
- package/scripts/mutants/agy-permission.json +144 -0
- package/scripts/mutants/meta-identity.json +17 -0
- package/scripts/mutants/self-address.json +59 -0
- package/scripts/mutants/v2-surface.json +87 -0
- package/scripts/pi_settings_io.py +65 -0
- package/scripts/register-pi-package.py +183 -37
- package/scripts/register-pi-provider.py +68 -10
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
- package/scripts/smoke-acp-v2-send-live.ts +33 -18
- package/scripts/smoke-agy-install-state.sh +205 -20
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
- package/scripts/smoke-meta-install-state.sh +1 -1
- package/scripts/smoke-pi-attach.ts +7 -2
- package/scripts/smoke-user-scope-citizen.sh +177 -0
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
- package/scripts/check-entwurf-mailbox-guard.ts +0 -262
|
@@ -49,6 +49,7 @@ import * as path from "node:path";
|
|
|
49
49
|
import {
|
|
50
50
|
defaultMetaMailboxDir,
|
|
51
51
|
defaultMetaSessionsDir,
|
|
52
|
+
isPlausibleOwnerPid,
|
|
52
53
|
type MetaReceiverArmProvenance,
|
|
53
54
|
upsertMetaSession,
|
|
54
55
|
writeMetaReceiverMarker,
|
|
@@ -140,7 +141,12 @@ const META_HOOK_LAUNCH_TOKEN = "hook-launch/v1";
|
|
|
140
141
|
* no token means we do not know what our parent is, so we claim nothing.
|
|
141
142
|
* 2. A PLAUSIBLE LIVE PARENT. A reparented orphan (ppid 0/1) is not an owner, and
|
|
142
143
|
* minting a marker for init would be exactly the "blind ancestor" false-positive
|
|
143
|
-
* the old ancestry walk existed to prevent.
|
|
144
|
+
* the old ancestry walk existed to prevent. The rule is `isPlausibleOwnerPid`,
|
|
145
|
+
* shared with the other writer and with every reader: this side already refused
|
|
146
|
+
* what all three readers accepted, and one host's leftover `ownerPid: 1` marker
|
|
147
|
+
* then blocked its fresh-cut until the file was deleted by hand (#53 A). A
|
|
148
|
+
* predicate only one layer knows is how that drift happened, so it is no longer
|
|
149
|
+
* written out by hand here.
|
|
144
150
|
*
|
|
145
151
|
* Failing closed costs only reply-addressability, and the doctor sees the ERROR. The
|
|
146
152
|
* opposite — a marker keyed to a transient wrapper — is a lie a sender acts on.
|
|
@@ -148,7 +154,7 @@ const META_HOOK_LAUNCH_TOKEN = "hook-launch/v1";
|
|
|
148
154
|
function resolveMetaHookOwnerPid(): number | null {
|
|
149
155
|
if (process.env[META_HOOK_LAUNCH_ENV] !== META_HOOK_LAUNCH_TOKEN) return null;
|
|
150
156
|
const ownerPid = process.ppid;
|
|
151
|
-
if (!
|
|
157
|
+
if (!isPlausibleOwnerPid(ownerPid)) return null;
|
|
152
158
|
return ownerPid;
|
|
153
159
|
}
|
|
154
160
|
|
package/run.sh
CHANGED
|
@@ -90,11 +90,11 @@ Usage:
|
|
|
90
90
|
./run.sh check-meta-mailbox-state-write # deterministic gate (0.11 Stage 0 step 3D-4 commit2): post-cut receipt is state-only — meta-record file byte-identical across enqueue/read, state carries lastEnqueuedAt/lastReadAt (field isolation), empty inbox no-op on record+state, drift surfaces; no API
|
|
91
91
|
./run.sh check-meta-receiver-marker # deterministic gate (SE-2): receiver marker round-trip/start-key/provenance, UserPromptSubmit cannot mint presence, reader does not gate on record existence — marker SEMANTICS only; launch topology moved to check-hook-launch-topology
|
|
92
92
|
./run.sh check-hook-launch-topology # #51 gate 1: shipped hooks.json is exec form through hook-launch.sh, launcher is loud on an empty argv (older Claude's silent args drop), exec preserves the pid so the hook's parent is Claude, and a space/$/backtick plugin path survives as one argv element
|
|
93
|
-
./run.sh check-meta-identity-consumers # deterministic gate: V3-only consumer seam — read
|
|
93
|
+
./run.sh check-meta-identity-consumers # deterministic gate: V3-only consumer seam — per-entry targeted read + addressable read snapshot uniqueness, non-regular rivals never read, drift/unparseable rivals unreachable, unreadable regular rivals fail loud; strict upsert refuses an unreadable store before any write, no API
|
|
94
94
|
./run.sh check-meta-capability-source # deterministic gate (0.11 Stage 0 step 3D-3): capability-source cut-over — mint/parse read wakeMode/deliveryLevel from the registry (metaCapabilityFor, registry-driven via injection), not META_BACKEND_DESCRIPTORS; behaviour-preserving (registry ≡ const); the record.delivery slot 3D-3 preserved was deleted by 3D-4, no API
|
|
95
95
|
./run.sh check-socket-probe # deterministic gate (0.11 Stage 0, F3): three-valued control-socket liveness (alive|dead|indeterminate) — GC reclaims dead only, indeterminate survives; pure classify + 2-socket integration, no API
|
|
96
96
|
./run.sh check-project-trust-handler # deterministic gate (0.11 Stage 0, Trust 2층): project_trust handler — decideProjectTrust matrix (escape=inherited-false+interactive+trust-here→{yes,remember:true}; non-interactive→undecided; never undefined) + adapter single-writer, fake prompt, no UI
|
|
97
|
-
./run.sh check-entwurf-v2-contract # deterministic gate (0.11 Stage 0 step 4-pre, 동결결정 10 + Fable R1-R5): FROZEN entwurf_v2 contract — R1
|
|
97
|
+
./run.sh check-entwurf-v2-contract # deterministic gate (0.11 Stage 0 step 4-pre, 동결결정 10 + Fable R1-R5): FROZEN entwurf_v2 contract — R1 control-socket domain (currently pi; claude/codex/agy=unsupported, not folded), 6-cell intent×liveness table (single verdict, 2 allow/4 reject), N1 indeterminate-no-spawn, Q2 owned-live-no-autosend, R3 table↔receipt round-trip, R5 taxonomy, schema↔types drift; pure, no API
|
|
98
98
|
./run.sh check-entwurf-v2-lock # deterministic gate (0.11 Stage 0 step 5a, 버킷 B F2): per-gid dispatch LOCK primitive — openSync wx atomic acquire, second-acquire=target-locked conflict (holder JSON for human cleanup), nonce-owned release (successor survives late release), stale reclaim same-host+ESRCH-only (EPERM/remote/alive/unknown fail-closed), empty/corrupt=conflict not auto-deleted, F2-P1 malformed gid throws; real temp dir, deps injected
|
|
99
99
|
./run.sh check-entwurf-v2-decider # deterministic gate (0.11 Stage 0 step 5b): PURE dispatch decider decideDispatch — frozen 7-step order over injected fakes, lock acquire+release tracked so reject⇒no-plan-no-lock proven; pre-probe rejects observedLiveness=null, send/resume execute keep lock + mailbox no-lock (?7), resume plan no mode/provider/model, invalid gid throws (F2-P1); pure, no IO
|
|
100
100
|
./run.sh check-entwurf-v2-matrix # deterministic gate (0.11 Stage 0 step 5d-5 a): REACHABILITY + LOCK SSOT table — drives REAL decideDispatch over fakes, fixes every (target kind → transport → lock class) cell as one table (control-socket/meta-mailbox/spawn-bg + bad-target/conflict/locked/undeliverable/owned-live/dormant/indeterminate rejects), coverage pass fails on a dropped cell; thin coverage not a decider re-impl; pure, no IO
|
|
@@ -104,20 +104,19 @@ Usage:
|
|
|
104
104
|
./run.sh check-entwurf-v2-runner # deterministic gate (0.11 Stage 0 step 5d-1): execute-router (executeDispatch) routing an already-decided DispatchDecision to its 5c transport hand → one outcome-rich EntwurfV2RunResult. reject→rejected (no hand) / control/spawn/mailbox→matching hand with decision.lock verbatim / spawn lock-retained rides executed (fail-closed) / N3 rejectReason carried / N1 SendDeliveredReleaseFailedError→execution-failed{finalizedOutcome,releaseFailed,retrySafe:false}; fake hands, no IO
|
|
105
105
|
./run.sh check-entwurf-v2-mailbox # deterministic gate (0.11 Stage 0 step 5c-4, LAST 5c transport slice): ENQUEUE-ONLY meta-mailbox SEND body (executeMetaMailboxSend) + production sendViaMailbox adapter — sender→formatMetaMailboxBody with plan.wantsReply threaded (divergence from legacy hard false), sender absent→raw plan.message, enqueue opts EXACTLY {gardenId,body,sessionsDir,mailboxDir}, enqueue throw PROPAGATES (no success:false fold — mailbox has no in-band refuse); adapter NEVER touches lock (release is the hand's job); source guard: no release/routing seam
|
|
106
106
|
./run.sh check-entwurf-v2-spawn # deterministic gate (0.11 Stage 0 step 5c-3a): spawn-bg RESUME watcher hand (executeSpawnBgResume) wiring spawn + socket-observe IO onto the 5c-1 reducer — Fable-3: TIMEOUT IS NOT A RELEASE (bare observeTimeout→killChild, release 0; bounded killGrace then real socket-alive ∨ child-exited releases ×1); spawnChild throw→spawn-start-failed; no observation obtainable (grace elapses / post-spawn watch dep throws)→lock-retained fail-closed (released:false, evidence surfaced), NO direct-release hatch; IO-via-dep, controlled promises
|
|
107
|
-
./run.sh check-entwurf-resume-args # deterministic gate (0.11 Stage 0 step 5c-3b): resume-argv SSOT (buildResumePiArgs)
|
|
107
|
+
./run.sh check-entwurf-resume-args # deterministic gate (0.11 Stage 0 step 5c-3b): resume-argv SSOT (buildResumePiArgs) for the v2 spawn-bg RESIDENT citizen — the `legacy` one-shot variant and its async worker were removed 2026-07-27, so the shipped posture is the only one the gate drives: v2-control=--entwurf-control + no --no-extensions (keep-alive is the goal, resumed session stays addressable); keeps --mode json -p + prompt-as-turn (-p NOT dropped); explicitExtensionArgs preserved exactly once (#29); plan.launchArgs (--approve) ride before the prompt; null provider→no --provider
|
|
108
108
|
./run.sh check-entwurf-v2-spawn-production # deterministic gate (0.11 Stage 0 step 5c-3c): production SpawnBgResumeDeps factory (makeProductionSpawnBgResumeDeps) wiring the 5c-3a watcher's 6 IO seams — no real pi/socket/timer (that=opt-in smoke-entwurf-v2-spawn-live, OUT of pnpm check). socketWatchVerdict: address-conflict→forged (reject, never wait)/alive→alive/dead·indeterminate→wait; spawnChild builds v2-control argv (--entwurf-control, no --no-extensions, -p+prompt, --approve, cwd authority); awaitSocketAlive connectable→resolve / symlink→reject without connect / dead→wait→alive / abort-clears; awaitChildExit code + listener cleanup; awaitTimeout schedule + abort-clear; killChild=SIGTERM; proc-less child fails loud
|
|
109
109
|
./run.sh smoke-entwurf-v2-spawn-live # LIVE phase gate (0.11 Stage 0 step 5c-3c, D5) — OUT of pnpm check, needs LIVE=1. Exercises the production SpawnBgResumeDeps against REAL OS objects: S1 real unix socket → awaitSocketAlive resolves (real lstat+probe), symlink→forged, absent→abort settles; S2 real child → spawn-event resolve + SIGTERM kill + exit-code capture; S3 watcher integration → real timeout→kill→child-exited→release ×1. Does NOT spawn a real pi resume (that=5d matrix). Run before 5d: LIVE=1 ./run.sh smoke-entwurf-v2-spawn-live
|
|
110
110
|
./run.sh smoke-entwurf-v2-spawn-resume-live # 0.11.0 (A) ACCEPTANCE gate — OUT of pnpm check, needs LIVE=1. The FULL spawn-bg resident lifecycle: mint backend=pi identity → seed a REAL dormant pi session (one-shot into ~/.pi/agent/sessions) → runEntwurfV2(owned-outcome) routes dormant→spawn-bg resume → a REAL detached pi --entwurf-control child stands its socket up, resumes, DOES a model turn. Asserts executed/spawn-bg/socket-alive/released + lock released ×1 + no lock file + pid alive + socket connectable + resume USER & assistant OK nonces in the session JSONL. Model-in-loop IN. The gate v1 deprecation (0.12) is predicated on. Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4). LIVE=1 ./run.sh smoke-entwurf-v2-spawn-resume-live
|
|
111
111
|
./run.sh smoke-entwurf-v2-matrix-live # LIVE sentinel (0.11 Stage 0 step 5d-5, D4-b) — OUT of pnpm check, needs LIVE=1. Drives REAL production runEntwurfV2 deps over REAL OS objects, 4 cells: C1 control-socket (real pi --entwurf-control resident → RPC send → lock acquire→release ×1), C1b record-less socket (#50 C4: live record-less pi → EVERY intent rejected pre-probe record-less-socket, no lock, rendered hint names record authority + fresh-cut), C2 meta-mailbox deliverable (armed self-fetch citizen → real .msg enqueue, lock-free), C3 meta-mailbox guard (no armed receiver → reject, no garbage). Model-in-loop OUT (transport/lock/enqueue gate, GPT Q2); negative/timeout stay deterministic. Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4). LIVE=1 ./run.sh smoke-entwurf-v2-matrix-live
|
|
112
112
|
./run.sh smoke-agy-native-push-live # 봉인 8 LIVE acceptance for the native-push (agy) rail — OUT of pnpm check, needs LIVE=1 + AGY_CONVERSATION_ID (a live agy conversation). Drives the REAL antigravity adapter + register core + runEntwurfV2 (production deps): doctor-static preflight (dangling→FAIL, the ③ gate), probe route, register create/attach idempotency, fire→native-push delivered, post-send re-probe (D7 partial), owned-outcome→native-push-no-resume-authority, bogus-conv→native-push-probe-indeterminate. Meta-store isolated to a temp dir (only the agy round-trip is real; no real-store residue). LIVE=1 AGY_CONVERSATION_ID=<convId> ./run.sh smoke-agy-native-push-live
|
|
113
|
-
./run.sh check-entwurf-facts # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 1+2): PURE PeerFact core + resolveFactList union — R1 out-of-domain→unsupported, R3b
|
|
113
|
+
./run.sh check-entwurf-facts # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 1+2): PURE PeerFact core + resolveFactList union — R1 out-of-domain→unsupported, R3b socket-domain 4-value, facts-only keyset; union: PeerFact + RecordLessSocketFact by gardenId (#50 C4: record-less socket = diagnostic subject, gid+liveness only), dormant→dead, F3 indeterminate preserved, out-of-socket-domain+socket fail-loud; pure, no IO
|
|
114
114
|
./run.sh check-socket-discovery # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 3): SOCKET-axis scanSocketProbes — probes (dir sockets) ∪ (in-domain citizen canonical paths) 3-valued; dormant citizen no-file → dead (resumable, not unprobed), stall → indeterminate (F3), dir hygiene/dedup/missing-dir + e2e → resolveFactList; readdir/probe injected, no IO
|
|
115
|
-
./run.sh check-meta-listing # deterministic gate
|
|
116
|
-
./run.sh check-entwurf-fact-provider # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 4b): ASSEMBLY listEntwurfFacts — listAllMetaIdentities→scanSocketProbes→pre-quarantine
|
|
115
|
+
./run.sh check-meta-listing # deterministic gate: META-STORE facts axis — kind-carrying entries; non-regular records are never read, parse/drift become diagnostics, duplicate nativeSessionId quarantines every rival but not unrelated citizens; strict throws / collect partial; pure injected IO
|
|
116
|
+
./run.sh check-entwurf-fact-provider # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 4b): ASSEMBLY listEntwurfFacts — listAllMetaIdentities→scanSocketProbes→pre-quarantine out-of-socket-domain/socket conflicts→resolveFactList(clean)→{facts,diagnostics}; C-원칙: expected corruption (parse/collision)→diagnostics (listing survives), impossible invariant (dup/unprobed)→throw; collision quarantines BOTH PeerFact+socket; deps injected, no IO
|
|
117
117
|
./run.sh check-entwurf-peers-surface # deterministic gate (0.11 Stage 0 step 4, fact-provider slice 4c): MCP entwurf_peers RENDER renderEntwurfPeers (#50 C4) — payload keyset exactly {peers, diagnostics}; FORBIDDEN keys sessions/socketOnly/controlDir/socketPath/count + no .sock in text (socket is transport, never identity); record-less socket = aggregated record-less-socket diagnostic (F8, liveness-keyed message, alive names fresh-cut); NO verb-routing key (JSON deep scan) NOR word (text), diagnostics both surfaces, empty→(none), unsupported shown; WIRING guard: both surfaces call provider+render, getLiveSessions + /entwurf-sessions gone; facts fabricated, no IO
|
|
118
|
-
./run.sh check-entwurf-self-address # deterministic gate (SE-1/SE-2 slice 1): self-addressability honesty predicate computeSelfAddressability — pi replyable ⟺ live socket; meta ⟺ recordBacked ∧ ownerAlive ∧ watchArmed (regression-proof record-present rows); SOURCE GUARD buildStrictPiSenderEnvelope drops hardcoded replyable:true + existsSync-probes socket, entwurf_self renders alive vs expected
|
|
118
|
+
./run.sh check-entwurf-self-address # deterministic gate (SE-1/SE-2 slice 1): self-addressability honesty predicate computeSelfAddressability — pi replyable ⟺ live socket; meta splits by RAIL: self-fetch ⟺ recordBacked ∧ ownerAlive ∧ watchArmed (regression-proof record-present rows), native-push ⟺ recordBacked ∧ probeAlive (separate axis — no mailbox fact may rescue or sink it), unsupplied rail fail-closed; SOURCE GUARD buildStrictPiSenderEnvelope drops hardcoded replyable:true + existsSync-probes socket, entwurf_self renders alive vs expected AND renders the meta rail per-rail (mailbox only inside the self-fetch branch; native-push denies an inbox and gates injection on the probe)
|
|
119
119
|
./run.sh check-entwurf-deliverability # deterministic gate (SE-1/SE-2 slice 2c): conversational-mailbox deliverability predicate — computeMetaReceiverActive (recordBacked ∧ ownerAlive ∧ watchArmed) + mailboxConversationalDeliverable (self-fetch AND active); direct-inject pi refused (SE-1), self-fetch dead/unarmed refused (SE-2); self-address shares the same atom
|
|
120
|
-
./run.sh check-entwurf-mailbox-guard # deterministic gate (SE-1/SE-2 slice 2d): guarded mailbox enqueue — PURE 0-call (undeliverable target leaves injected enqueue uncalled) + TMPDIR snapshot (refused send leaves mailbox byte-identical, accepted writes one .msg) + fact gathering from record/capability/receiver-marker
|
|
121
120
|
./run.sh check-native-push-adapter # deterministic gate (봉인 3/8): native-push adapter leaf (antigravity) via a FAKE runner — FULL pid scan (not head -1), dead vs indeterminate, VOLATILE route re-discovery (no cache), send argv+ANTIGRAVITY_LS_ADDRESS env, non-zero exit throws, NO adapter-level retry (executor-owned), resolveNativePushAdapter fail-fast
|
|
122
121
|
./run.sh check-native-push-register # deterministic gate (봉인 5): registerNativeConversation (entwurf_register_native core) via fake adapter + isolated mkdtemp store — live probe→CREATE, re-register→ATTACH (same gid, cwd refreshed, no dup), not-live probe→REFUSE (throws, no record), receiver-marker abstinence (보정① source guard)
|
|
123
122
|
./run.sh check-agy-sender-identity # deterministic gate (#46 sender lane): WHO is calling the bridge — real agy hook as a child process writes an antigravity sender marker keyed by its PARENT pid (never on upsert failure), and resolveTrustedMetaSenderIdentity over isolated stores yields 0→null / 1→identity on EITHER backend / two distinct live identities on one owner pid→THROW (never guess, never downgrade to anonymous). This is what turns an agy send from external-mcp/unknown-host into a replyable garden citizen
|
|
@@ -128,9 +127,11 @@ Usage:
|
|
|
128
127
|
./run.sh smoke-meta-honesty # 1.0.0 meta-bridge: honesty regression gate (#30 blockers) — doorbell counts ALL msgs honestly + hook logs failures as ERROR (best-effort, no scream). Offline/deterministic (deps: bash+node+python3)
|
|
129
128
|
./run.sh smoke-meta-install-state # 1.0.0 meta-bridge Phase 2: stateful install/uninstall + store-doctor regression gate. Offline/deterministic (deps: bash+node+python3)
|
|
130
129
|
./run.sh check-meta-doctor-oracle # 0.12.8 (#51): detection power of the release ORACLE — healthy fixture must reach `doctor: PASS`, then 21 planted defects (retired shell form, partial hand-patch, launcher bypass/repoint/provenance loss, malformed exec args, owner type drift, extra leaf/group, doorbell asyncRewake/path/timeout, no live bridge, stale receiver, ambiguous/missing cache, missing hook log/writer, failing CLI probes) must each turn it FAIL naming their own cause, plus a positive case pinning that a long-writing CLI is NOT a false negative. Offline/deterministic (deps: bash+node+python3)
|
|
131
|
-
./run.sh smoke-agy-install-state # agy MCP + exact permission ownership regression
|
|
132
|
-
./run.sh
|
|
133
|
-
./run.sh
|
|
130
|
+
./run.sh smoke-agy-install-state # agy MCP + exact permission ownership regression: isolated HOME+XDG, adopt/state/inverse, symlink refuse, setup degrade. Offline/deterministic
|
|
131
|
+
./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)
|
|
132
|
+
./run.sh check-gate-qualification # kill-proof qualification (the gate-of-gates): runner self-test (classifier truth table + synthetic negatives incl. wrong-reason/hang/control-red/impurity) + committed mutant manifests (scripts/mutants/*.json) run in an isolated snapshot repo under control→mutant→restore→control; the real checkout is never written. Evidence = claim IDs + killed mutant IDs, never assertion counts
|
|
133
|
+
./run.sh smoke-agy-statusline-state # agy ambient garden-id statusLine install/doctor/inverse regression. Offline/deterministic
|
|
134
|
+
./run.sh smoke-agy-hooks-state # agy PreInvocation birth/sender hook install/doctor/inverse + direct stdin→meta-record regression. Offline/deterministic
|
|
134
135
|
./run.sh smoke-user-scope-citizen # 0.12.6 install-boundary: pi packages[] registration SSOT (register-pi-package.py) — idempotent + preserves unrelated + normalizes stale + remove symmetry + fails loud. Offline/hermetic (deps: bash+python3)
|
|
135
136
|
./run.sh smoke-meta-prune # 1.0.0 meta-bridge Phase 4: listing-only store janitor regression gate — classify keep/orphan/stale/ambiguous, delete nothing. Offline/deterministic (deps: bash+node)
|
|
136
137
|
./run.sh smoke-meta-keyset-guard # 0.10.0 meta-bridge: keyset-owner guard regression — check-keyset-overlap + managed-keys SSOT (disjoint passes, collisions fail). Offline/hermetic (deps: bash+python3)
|
|
@@ -150,13 +151,13 @@ Usage:
|
|
|
150
151
|
./run.sh uninstall-agy-hooks # honest inverse of install-agy-hooks from install-state
|
|
151
152
|
./run.sh doctor-agy-hooks # fail-loud doctor for agy hooks.json imprint wiring
|
|
152
153
|
./run.sh meta-bridge-prune # 1.0.0 meta-bridge Phase 4: LISTING-ONLY store hygiene — classify orphan/stale/ambiguous/keep, print manual rm commands, delete NOTHING ([dir] [--ttl-days N])
|
|
153
|
-
./run.sh meta-bridge-fresh-cut # the ONE generation verb (the verb every v3-only rejection names): quiesce-check live sockets/markers/native-push conversations (refusing any surface it cannot inspect), archive meta-sessions/ + meta-mailbox/ to `<dir>.archive-<ts>`, clear dead transport residue, open an empty v3 generation. No migration, no restore — the archive is forensic only
|
|
154
|
+
./run.sh meta-bridge-fresh-cut # the ONE generation verb (the verb every v3-only rejection names): quiesce-check live sockets/markers/native-push conversations (refusing any surface it cannot inspect), archive meta-sessions/ + meta-mailbox/ to `<dir>.archive-<ts>`, clear dead transport residue, open an empty v3 generation. No migration, no restore — the archive is forensic only. EXIT CONTRACT (#54, `--help` prints it): 0 complete / 1 NOTHING MOVED (re-run, do not setup) / 2 usage / 3 cut transition incomplete (inspect) / 4 cut complete but residue cleanup failed (`setup` may run; re-run only before new citizen birth, otherwise remove residue manually)
|
|
154
155
|
./run.sh meta-bridge-managed-keys # 0.10.0 meta-bridge: print the SSOT of settings keys entwurf OWNS (consumers read this to stay disjoint — keyset-owner invariant)
|
|
155
156
|
./run.sh check-keyset-overlap <fragment.json...> # 0.10.0 meta-bridge: PREVENTIVE keyset guard — fail if a consumer fragment collides with any pi-owned key (cross-repo; not in pnpm check)
|
|
156
157
|
./run.sh check-dep-versions # local deterministic check that the pi pin agrees across package.json (devDeps + peer range), run.sh (peer-install pins), and the baseline docs (AGENTS/README/ROADMAP/setup-clean-host/demo)
|
|
157
158
|
./run.sh check-node-floor-coherence # binds the Node floor (24+, single axis) across engines.node, run.sh setup preflight, meta-bridge install/doctor judgment logic, clean-host docs, the bridge launcher header, and the CI runner node-version — engines.node is the SSOT, everything else is derived; sweeps tracked contract text for an unregistered declaration
|
|
158
159
|
./run.sh check-pack # publish gate (dry-run): npm pack --dry-run + tarball invariants (runtime-critical present, dev residue absent)
|
|
159
|
-
./run.sh check-fresh-cut-gate # SOURCE cell of the generation-boundary proof (IN pnpm check):
|
|
160
|
+
./run.sh check-fresh-cut-gate # SOURCE cell of the generation-boundary proof (IN pnpm check): 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
|
|
160
161
|
./run.sh check-pack-install # heavy publish gate (prepublishOnly): actual npm pack + tar -tf + fresh-temp install smoke with the pinned pi peers (0.82.x) + the npm-installed bridge BOOTS (tools/list) and DELIVERS (tools/call entwurf_v2 → .msg lands) + 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)
|
|
161
162
|
./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)
|
|
162
163
|
./run.sh sync-auth # copy ~/.pi/agent/auth.json anthropic OAuth credentials to entwurf alias
|
|
@@ -501,7 +502,8 @@ register_user_scope_citizen() {
|
|
|
501
502
|
# exists to hold). Same explicit-global-lifecycle shape as install/uninstall-meta-bridge.
|
|
502
503
|
# Uses the same is_entwurf_source SSOT + --remove, so it never over-deletes a look-alike
|
|
503
504
|
# (entwurf-notes, openclaw-entwurf) and preserves every other package/key. Idempotent:
|
|
504
|
-
# no entwurf entry → no-op.
|
|
505
|
+
# no entwurf entry → no-op. A settings-relative entry naming this repo is preserved and
|
|
506
|
+
# reported rather than deleted — install never writes that form (#53 B).
|
|
505
507
|
remove_user_scope_citizen() {
|
|
506
508
|
local agent_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
|
|
507
509
|
python3 "$REPO_DIR/scripts/register-pi-package.py" "$agent_dir/settings.json" "$REPO_DIR" --remove
|
|
@@ -525,7 +527,10 @@ remove_local_package() {
|
|
|
525
527
|
preflight_pi_settings_shapes "$project_dir/.pi/settings.json" "$(mktemp -u)"
|
|
526
528
|
# packages[] cleanup via the shared SSOT — same is_entwurf_source predicate as
|
|
527
529
|
# install, so remove never over-deletes a look-alike repo (entwurf-notes, …)
|
|
528
|
-
# that install would never have registered.
|
|
530
|
+
# that install would never have registered. Same rule, one shape further (#53 B):
|
|
531
|
+
# register only ever WRITES the absolute path, so a settings-RELATIVE entry naming
|
|
532
|
+
# this repo (the committed `".."` in <repo>/.pi/settings.json) is source, not
|
|
533
|
+
# install state — remove leaves it and says so instead of editing tracked bytes.
|
|
529
534
|
python3 "$REPO_DIR/scripts/register-pi-package.py" "$project_dir/.pi/settings.json" "$REPO_DIR" --remove
|
|
530
535
|
# entwurfProvider.mcpServers.entwurf-bridge cleanup (project scope) via the shared SSOT: strip
|
|
531
536
|
# our-managed shapes (the bare stable bin AND the legacy repo start.sh path — a true user
|
|
@@ -741,7 +746,7 @@ check_entwurf_v2_contract() {
|
|
|
741
746
|
# contract (동결결정 10 + 버킷 B F1/F4/F6 + Fable R1-R5). The intent×liveness
|
|
742
747
|
# decision table is a constant; the "table cell ↔ dispatch receipt" round-trip
|
|
743
748
|
# is asserted exhaustively — THE executable proof F6 demands ("산문 금지").
|
|
744
|
-
# R1
|
|
749
|
+
# R1 control-socket capability domain (currently pi; claude-code/codex/antigravity =
|
|
745
750
|
# unsupported, never folded into dead/indeterminate). 6-cell table, single
|
|
746
751
|
# verdict per cell (Q2), 2 allow / 4 reject. N1 indeterminate never spawns;
|
|
747
752
|
# Q2 owned-outcome+live never auto-sends. R5 taxonomy covers table reasons +
|
|
@@ -944,14 +949,13 @@ check_entwurf_v2_spawn() {
|
|
|
944
949
|
|
|
945
950
|
check_entwurf_resume_args() {
|
|
946
951
|
# Deterministic gate for 0.11 Stage 0 step 5c-3b: the resume-argv SSOT
|
|
947
|
-
# (buildResumePiArgs)
|
|
948
|
-
#
|
|
949
|
-
# `--no-extensions`
|
|
950
|
-
#
|
|
951
|
-
#
|
|
952
|
-
#
|
|
953
|
-
#
|
|
954
|
-
# (--approve) before the prompt; null provider emits no --provider; no cross-contamination.
|
|
952
|
+
# (buildResumePiArgs). v2-control is the only shipped shape (the legacy one-shot variant and
|
|
953
|
+
# its launcher were removed 2026-07-27). Pins the resident posture: `--entwurf-control`
|
|
954
|
+
# present + `--no-extensions` never (the keep-alive is the goal — a resumed session stands
|
|
955
|
+
# its socket up and stays addressable), the headless `--mode json -p` prefix and the
|
|
956
|
+
# prompt-as-turn positional (`-p` NOT dropped), explicitExtensionArgs preserved exactly once
|
|
957
|
+
# (provider-resolution footgun #29), plan.launchArgs (--approve) before the prompt, and a
|
|
958
|
+
# null provider emitting no --provider.
|
|
955
959
|
run_ts scripts/check-entwurf-resume-args.ts
|
|
956
960
|
}
|
|
957
961
|
|
|
@@ -988,12 +992,12 @@ smoke_entwurf_v2_spawn_live() {
|
|
|
988
992
|
smoke_acp_socket_citizen_live() {
|
|
989
993
|
# S1 acceptance smoke (ACP plugin on v2) — OUT of pnpm check, needs LIVE=1.
|
|
990
994
|
# Spawns a REAL `pi --entwurf-control` resident on an ACP model
|
|
991
|
-
# (entwurf/claude-opus-
|
|
995
|
+
# (entwurf/claude-opus-5) and proves it is a first-class socket-citizen:
|
|
992
996
|
# the control socket stands up, get_info answers with the ACP model (model-lock
|
|
993
997
|
# did NOT revert — QM1), idle/cwd are reported, and the fail-loud streamSimple
|
|
994
998
|
# stub never fires (turn-free launch — QM2). No prompt is sent: S1 proves
|
|
995
999
|
# citizenship, never a backend turn (that is S2). Honest skip when LIVE!=1.
|
|
996
|
-
# Model override: ENTWURF_S1_MODEL (default claude-opus-
|
|
1000
|
+
# Model override: ENTWURF_S1_MODEL (default claude-opus-5).
|
|
997
1001
|
# LIVE=1 ./run.sh smoke-acp-socket-citizen-live
|
|
998
1002
|
run_ts scripts/smoke-acp-socket-citizen-live.ts
|
|
999
1003
|
}
|
|
@@ -1262,7 +1266,7 @@ check_meta_listing() {
|
|
|
1262
1266
|
check_entwurf_fact_provider() {
|
|
1263
1267
|
# Deterministic gate for 0.11 Stage 0 step 4 (fact-provider slice 4b): the
|
|
1264
1268
|
# ASSEMBLY layer listEntwurfFacts. listAllMetaIdentities → scanSocketProbes →
|
|
1265
|
-
# pre-quarantine
|
|
1269
|
+
# pre-quarantine out-of-socket-domain/socket conflicts → resolveFactList(clean) →
|
|
1266
1270
|
# {facts, diagnostics}. Throw-vs-diagnostics policy (GPT힣 C-원칙): expected
|
|
1267
1271
|
# corruption (parse failure / gardenId↔socket collision) → diagnostics, listing
|
|
1268
1272
|
# survives; impossible wiring invariant (resolveFactList duplicate/unprobed) →
|
|
@@ -1293,7 +1297,8 @@ check_entwurf_self_address() {
|
|
|
1293
1297
|
# from env presence alone: a socketless pi session, or a meta citizen whose owner
|
|
1294
1298
|
# exited / whose idle-watch was never armed, all advertised replyable while
|
|
1295
1299
|
# delivery silently failed (SE-1). Asserts: PURE truth table (pi replyable ⟺
|
|
1296
|
-
# socketAlive; meta ⟺ recordBacked ∧ ownerAlive ∧
|
|
1300
|
+
# socketAlive; external never; meta BY RAIL — self-fetch ⟺ recordBacked ∧ ownerAlive ∧
|
|
1301
|
+
# watchArmed, native-push ⟺ recordBacked ∧ probeAlive, unsupplied rail fail-closed),
|
|
1297
1302
|
# incl. the two regression-proof rows (record-present + owner-dead / watch-unarmed)
|
|
1298
1303
|
# that stay meaningful after slice 3 mints records; SOURCE GUARD that
|
|
1299
1304
|
# buildStrictPiSenderEnvelope drops the hardcoded `replyable: true` and existsSync-
|
|
@@ -1315,17 +1320,6 @@ check_entwurf_deliverability() {
|
|
|
1315
1320
|
run_ts scripts/check-entwurf-deliverability.ts
|
|
1316
1321
|
}
|
|
1317
1322
|
|
|
1318
|
-
check_entwurf_mailbox_guard() {
|
|
1319
|
-
# Deterministic gate for the guarded mailbox enqueue (SE-1/SE-2 slice 2d) — the IO
|
|
1320
|
-
# orchestration conversational-reply sites use instead of enqueueMetaMessage directly.
|
|
1321
|
-
# Asserts (GPT Q5, both axes): PURE 0-call — an undeliverable target (dead receiver /
|
|
1322
|
-
# direct-inject pi / absent record) leaves the injected enqueue UNCALLED, a deliverable
|
|
1323
|
-
# one calls it exactly once; TMPDIR SNAPSHOT with the real enqueueMetaMessage — a refused
|
|
1324
|
-
# send leaves the mailbox tree byte-identical (file list + content hash, not just mtime),
|
|
1325
|
-
# an accepted send writes exactly one .msg; plus fact gathering from record/capability/marker.
|
|
1326
|
-
run_ts scripts/check-entwurf-mailbox-guard.ts
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
1323
|
check_native_push_adapter() {
|
|
1330
1324
|
# Deterministic gate for the native-push adapter LEAF (봉인 3/8). Drives
|
|
1331
1325
|
# createAntigravityAdapter with a FAKE runner (no real agy/ss/pgrep). Asserts: FULL pid
|
|
@@ -1442,12 +1436,12 @@ assert.equal(peerTui, piAi,
|
|
|
1442
1436
|
// floor tracks the devDep pin so a consumer can't install against a pi lacking
|
|
1443
1437
|
// the public trust exports the bridge imports at the pinned minor, AND an upper
|
|
1444
1438
|
// bound at the next minor stops a fresh install from silently pulling a future
|
|
1445
|
-
// pi (past the declared ceiling — 0.83+ at the current 0.82.
|
|
1439
|
+
// pi (past the declared ceiling — 0.83+ at the current 0.82.1 pin) whose
|
|
1446
1440
|
// internal export surface has drifted from the one we typecheck against.
|
|
1447
1441
|
// pi moves its public surface every minor (the 0.79→0.80 getModels→provider-
|
|
1448
1442
|
// factory churn is exactly this), so an open `>=` floor is exactly how the next
|
|
1449
1443
|
// installer re-acquires the drift. Expected
|
|
1450
|
-
// shape: `>=<devDep> <0.<minor+1>` (e.g. `>=0.82.
|
|
1444
|
+
// shape: `>=<devDep> <0.<minor+1>` (e.g. `>=0.82.1 <0.83`).
|
|
1451
1445
|
const [piMaj, piMin] = piAi.split('.').map(Number);
|
|
1452
1446
|
assert.equal(piMaj, 0,
|
|
1453
1447
|
`pi pin major must stay 0 for the next-minor ceiling rule (got ${piAi}); revisit check-dep-versions when pi reaches 1.x`);
|
|
@@ -1691,7 +1685,7 @@ const SITES = [
|
|
|
1691
1685
|
['pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh', /Claude Code >= (\d+\.\d+\.\d+)/g, 1, 'launcher refusal message'],
|
|
1692
1686
|
['scripts/meta-bridge-claude-floor.sh', /THE FLOOR IS (\d+\.\d+\.\d+)/g, 1, 'floor helper rationale header'],
|
|
1693
1687
|
['docs/setup-clean-host.md', /`>=(\d+\.\d+\.\d+)`\*\* — the exec-form hook floor/g, 1, 'clean-host pin matrix'],
|
|
1694
|
-
['AGENTS.md', /Claude Code `>=(\d+\.\d+\.\d+)`/g, 1, 'AGENTS rule
|
|
1688
|
+
['AGENTS.md', /Claude Code `>=(\d+\.\d+\.\d+)`/g, 1, 'AGENTS rule 14'],
|
|
1695
1689
|
['README.md', /supported floor `>=(\d+\.\d+\.\d+)`/g, 1, 'README doctor description'],
|
|
1696
1690
|
['scripts/check-hook-launch-topology.ts', /\/(\d+)\\\.(\d+)\\\.(\d+)\//g, 1, 'topology gate floor assertion'],
|
|
1697
1691
|
];
|
|
@@ -1902,13 +1896,13 @@ check_pi_import_surface() {
|
|
|
1902
1896
|
# 0.80 moved the standalone root `getModels()` to the deprecated `/compat`
|
|
1903
1897
|
# entrypoint. This repo's pi-extensions/** are loaded by pi's EXTENSION loader
|
|
1904
1898
|
# (pi-coding-agent `core/extensions/loader.ts`), whose jiti alias map resolves
|
|
1905
|
-
#
|
|
1906
|
-
#
|
|
1899
|
+
# FOUR pi-ai specifiers for extensions — the bare root, `/compat`, `/oauth`, and
|
|
1900
|
+
# (since pi 0.81) `/providers/all`. Other `providers/*` subpaths are NOT in that
|
|
1907
1901
|
# map: jiti prefix-matches the bare `@earendil-works/pi-ai` alias and appends
|
|
1908
1902
|
# the remainder, producing the unresolvable `…/dist/compat.js/providers/
|
|
1909
1903
|
# anthropic` (verified live: extension load crash — invisible to static
|
|
1910
1904
|
# typecheck, which resolves against node_modules `exports`). So `/compat` is the
|
|
1911
|
-
# sanctioned extension entrypoint for the old global model-catalog API
|
|
1905
|
+
# sanctioned extension entrypoint this repo uses for the old global model-catalog API
|
|
1912
1906
|
# (lib/acp/models.ts: `getModels`), and the ONLY allowlisted exception. The
|
|
1913
1907
|
# allow-pattern is closing-quote-anchored (`@earendil-works/pi-ai/compat["'\`]`)
|
|
1914
1908
|
# so it permits ONLY that exact specifier: `/compat-foo`, `/oauth`, every
|
|
@@ -2229,7 +2223,7 @@ check_acp_provider_surface() {
|
|
|
2229
2223
|
check_acp_sdk_surface() {
|
|
2230
2224
|
# Deterministic gate for the S2a ACP SDK dependency surface. Pins the three
|
|
2231
2225
|
# ACP runtime deps to the current oracle versions (@agentclientprotocol/sdk
|
|
2232
|
-
# 1.3.0 + claude-agent-acp 0.
|
|
2226
|
+
# 1.3.0 + claude-agent-acp 0.62.0 + @anthropic-ai/sdk 0.100.1), locks the
|
|
2233
2227
|
# peer-resolution that keeps claude-agent-sdk satisfiable (0.100.1, not the
|
|
2234
2228
|
# stale 0.91.1), asserts the wire SDK still value-exports the symbols the raw
|
|
2235
2229
|
# turn needs (silent-rename gate), and forbids any source-level anthropic SDK
|
|
@@ -2715,7 +2709,7 @@ _check_pack_install_impl() {
|
|
|
2715
2709
|
printf '%s\n' '{ "name": "entwurf-install-smoke", "version": "0.0.0", "private": true }' > "$tmp/package.json"
|
|
2716
2710
|
|
|
2717
2711
|
# pi-agent-core is pinned even though we never import it: pi-coding-agent depends
|
|
2718
|
-
# on it by CARET (`^0.82.
|
|
2712
|
+
# on it by CARET (`^0.82.1`), so with no lockfile in this fresh temp project it
|
|
2719
2713
|
# floats to whatever pi published last — and that newer core then drags a NESTED
|
|
2720
2714
|
# pi-ai of its own. Measured 2026-07-21: pinning only the three we import left
|
|
2721
2715
|
# pi-agent-core@0.80.10 + pi-ai@0.80.10 in the tree while the gate still announced
|
|
@@ -2726,10 +2720,10 @@ _check_pack_install_impl() {
|
|
|
2726
2720
|
local install_log
|
|
2727
2721
|
install_log=$(cd "$tmp" && pnpm add \
|
|
2728
2722
|
"$tgz_path" \
|
|
2729
|
-
"@earendil-works/pi-ai@0.82.
|
|
2730
|
-
"@earendil-works/pi-coding-agent@0.82.
|
|
2731
|
-
"@earendil-works/pi-tui@0.82.
|
|
2732
|
-
"@earendil-works/pi-agent-core@0.82.
|
|
2723
|
+
"@earendil-works/pi-ai@0.82.1" \
|
|
2724
|
+
"@earendil-works/pi-coding-agent@0.82.1" \
|
|
2725
|
+
"@earendil-works/pi-tui@0.82.1" \
|
|
2726
|
+
"@earendil-works/pi-agent-core@0.82.1" \
|
|
2733
2727
|
"typebox@latest" \
|
|
2734
2728
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
2735
2729
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -2739,17 +2733,17 @@ _check_pack_install_impl() {
|
|
|
2739
2733
|
|
|
2740
2734
|
# A pin is a wish until the resolved tree is read back. Assert it: EVERY
|
|
2741
2735
|
# @earendil-works pi package present — direct or transitive, top level or nested —
|
|
2742
|
-
# must be the pinned 0.82.
|
|
2736
|
+
# must be the pinned 0.82.1. Anything else means an unpinned caret floated and the
|
|
2743
2737
|
# rest of this gate would be exercising a runtime nobody verified, while still
|
|
2744
|
-
# printing "pinned pi 0.82.
|
|
2738
|
+
# printing "pinned pi 0.82.1". Fail loud instead of proving the wrong floor.
|
|
2745
2739
|
local leaked_pi
|
|
2746
|
-
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | grep '^@earendil-works+pi-' | grep -v '@0\.82\.
|
|
2740
|
+
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | grep '^@earendil-works+pi-' | grep -v '@0\.82\.1' || true)
|
|
2747
2741
|
if [ -n "$leaked_pi" ]; then
|
|
2748
|
-
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 0.82.
|
|
2742
|
+
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 0.82.1):"
|
|
2749
2743
|
printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
|
|
2750
2744
|
return 1
|
|
2751
2745
|
fi
|
|
2752
|
-
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works pi package is 0.82.
|
|
2746
|
+
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works pi package is 0.82.1"
|
|
2753
2747
|
|
|
2754
2748
|
# Resolve the installed package.json and confirm pi.extensions
|
|
2755
2749
|
# arrived intact. If pi.extensions is empty or missing, the
|
|
@@ -2834,14 +2828,14 @@ _check_pack_install_impl() {
|
|
|
2834
2828
|
# opus anchor (CURATED_ANCHOR_MODEL_ID in lib/acp/models.ts — the model whose
|
|
2835
2829
|
# absence is a hard registry regression). Checking only one would let half the
|
|
2836
2830
|
# surface drop silently.
|
|
2837
|
-
for anchor in "claude-sonnet-5" "claude-opus-
|
|
2831
|
+
for anchor in "claude-sonnet-5" "claude-opus-5"; do
|
|
2838
2832
|
if ! grep -q "$anchor" <<<"$loader_out"; then
|
|
2839
2833
|
fail "[check-pack-install] pi loader output missing curated Claude model $anchor:"
|
|
2840
2834
|
echo "$loader_out" | tail -10 | sed 's/^/ /' >&2
|
|
2841
2835
|
return 1
|
|
2842
2836
|
fi
|
|
2843
2837
|
done
|
|
2844
|
-
echo "[check-pack-install] pi loader smoke pass (entwurf registered, claude-sonnet-5 + claude-opus-
|
|
2838
|
+
echo "[check-pack-install] pi loader smoke pass (entwurf registered, claude-sonnet-5 + claude-opus-5 anchor)"
|
|
2845
2839
|
|
|
2846
2840
|
# npm-managed neutral install regression — the README's PRIMARY install path is
|
|
2847
2841
|
# now `npm install @junghanacs/entwurf` (NOT `pi install npm:...`). This layout
|
|
@@ -2922,7 +2916,7 @@ sys.exit(0 if any(isinstance(s,str) and s.endswith('/node_modules/@junghanacs/en
|
|
|
2922
2916
|
echo "$foreign_out" | tail -10 | sed 's/^/ /' >&2
|
|
2923
2917
|
return 1
|
|
2924
2918
|
}
|
|
2925
|
-
if grep -qi "Unknown option" <<<"$foreign_out" || ! grep -q "claude-opus-
|
|
2919
|
+
if grep -qi "Unknown option" <<<"$foreign_out" || ! grep -q "claude-opus-5" <<<"$foreign_out"; then
|
|
2926
2920
|
fail "[check-pack-install] foreign-cwd --entwurf-control did not load the entwurf extension from user scope:"
|
|
2927
2921
|
echo "$foreign_out" | tail -10 | sed 's/^/ /' >&2
|
|
2928
2922
|
return 1
|
|
@@ -3753,12 +3747,13 @@ wire_agy_bridge() {
|
|
|
3753
3747
|
# reported as an mcp_config problem and sends the operator to repair the wrong file.
|
|
3754
3748
|
case "$out" in
|
|
3755
3749
|
*"permission refused (symlink)"*|*"permission invalid JSON"*|*"permission could not be granted"*)
|
|
3756
|
-
# The MCP server IS registered — only the allow
|
|
3757
|
-
# Ask, so the bridge works but stops for a y/n on EVERY
|
|
3750
|
+
# The MCP server IS registered — only the allow rules failed. agy defaults every mcp action to
|
|
3751
|
+
# Ask, so the bridge works but stops for a y/n on EVERY entwurf tool call. Half-wired, and said
|
|
3758
3752
|
# so: the explicit installer fails loud on this; setup only degrades it, never hides it.
|
|
3759
|
-
echo "[setup] WARN: agy settings.json could not take our permission
|
|
3760
|
-
echo "[setup] agy will prompt on every
|
|
3761
|
-
echo "[setup]
|
|
3753
|
+
echo "[setup] WARN: agy settings.json could not take our permission rules — bridge REGISTERED but NOT GRANTED." >&2
|
|
3754
|
+
echo "[setup] agy will prompt on every entwurf tool call until our narrow rules" >&2
|
|
3755
|
+
echo "[setup] ($(python3 "$REPO_DIR/scripts/agy-bridge-config.py" permission-rules 2>/dev/null || echo 'mcp(entwurf-bridge/<tool>)'))" >&2
|
|
3756
|
+
echo "[setup] are in its permissions.allow (see the line above for why). setup continues." >&2
|
|
3762
3757
|
;;
|
|
3763
3758
|
*"refused (symlink)"*)
|
|
3764
3759
|
echo "[setup] WARN: agy mcp_config is a symlink — someone else's SSOT (transitional)." >&2
|
|
@@ -4352,9 +4347,6 @@ case "$cmd" in
|
|
|
4352
4347
|
check-entwurf-deliverability)
|
|
4353
4348
|
check_entwurf_deliverability
|
|
4354
4349
|
;;
|
|
4355
|
-
check-entwurf-mailbox-guard)
|
|
4356
|
-
check_entwurf_mailbox_guard
|
|
4357
|
-
;;
|
|
4358
4350
|
check-native-push-adapter)
|
|
4359
4351
|
check_native_push_adapter
|
|
4360
4352
|
;;
|
|
@@ -4441,6 +4433,25 @@ case "$cmd" in
|
|
|
4441
4433
|
# Offline + deterministic (deps: bash+python3).
|
|
4442
4434
|
(cd "$REPO_DIR" && bash scripts/smoke-agy-install-state.sh)
|
|
4443
4435
|
;;
|
|
4436
|
+
check-agy-permission-matrix)
|
|
4437
|
+
# The agy permission engine's CONTRACT SPACE as a literal table (55 cells + stated
|
|
4438
|
+
# exclusions R2/R4-R7): parser-state × operation × settings × ownership × precedence.
|
|
4439
|
+
# Every recent permission defect was an unenumerated cell of this matrix; this gate
|
|
4440
|
+
# states the axes and exhausts the meaningful product, with hand-written literal
|
|
4441
|
+
# expectations (oracle independence — nothing is read back from the SUT). Sandbox
|
|
4442
|
+
# per cell; offline + deterministic (deps: python3).
|
|
4443
|
+
(cd "$REPO_DIR" && python3 scripts/check-agy-permission-matrix.py)
|
|
4444
|
+
;;
|
|
4445
|
+
check-gate-qualification)
|
|
4446
|
+
# Kill-proof qualification — the gate-of-gates. Proves the committed defect mutants
|
|
4447
|
+
# (scripts/mutants/*.json) make their gates fail BOUNDED and FOR THE CLAIMED REASON
|
|
4448
|
+
# ([QK:<claim>] token on a failure line), inside an isolated snapshot repo under the
|
|
4449
|
+
# control→mutant→restore→control state machine; the real checkout is never written
|
|
4450
|
+
# (HEAD + work-surface content hash asserted identical before/after). The runner is negative-controlled
|
|
4451
|
+
# first: zero-match/multi-match/survived/wrong-reason/hang(+pgroup grandchild kill)/
|
|
4452
|
+
# control-red/impurity all must classify red before any real manifest counts.
|
|
4453
|
+
run_ts scripts/check-gate-qualification.ts
|
|
4454
|
+
;;
|
|
4444
4455
|
smoke-agy-statusline-state)
|
|
4445
4456
|
# #46 Task 1 regression gate for the agy statusLine install adapter: install→doctor→uninstall
|
|
4446
4457
|
# in an ISOLATED HOME+XDG with a fake stable bin (entwurf-agy-statusline) + fake pgrep —
|