@junghanacs/entwurf 0.13.0 → 0.14.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 +52 -17
- package/BASELINE.md +60 -206
- package/CHANGELOG.md +64 -0
- package/CONTRIBUTING.md +14 -10
- package/DELIVERY.md +118 -261
- package/README.md +91 -431
- package/VERIFY.md +74 -95
- package/demo/README.md +1 -1
- package/demo/demo-baseline.sh +1 -3
- package/demo/demo.sh +2 -5
- package/docs/acp-backend-rail.md +236 -0
- package/docs/external-mcp-host.md +131 -0
- package/docs/fresh-cut-policy.md +99 -0
- package/docs/setup-clean-host.md +124 -328
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +160 -67
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +12 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +11 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +42 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +11 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +7 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +13 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +45 -40
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +117 -95
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +23 -57
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +16 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +5 -53
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +21 -36
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -15
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +12 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +2 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +30 -67
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +256 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +91 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +258 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +202 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +289 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +170 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +136 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/session-id.js +8 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +3 -3
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +51 -0
- package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +9 -4
- package/mcp/entwurf-bridge/src/index.ts +176 -67
- package/mcp/entwurf-bridge/start.sh +2 -2
- package/mcp/entwurf-bridge/test.sh +23 -9
- package/mcp/entwurf-bridge/tsconfig.build.json +11 -2
- package/package.json +25 -11
- package/pi-extensions/entwurf-control.ts +220 -71
- package/pi-extensions/lib/acp/acp-client.ts +22 -0
- package/pi-extensions/lib/acp/augment.ts +42 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +12 -11
- package/pi-extensions/lib/acp/backend.ts +366 -38
- package/pi-extensions/lib/acp/config.ts +1 -1
- package/pi-extensions/lib/acp/engraving.ts +43 -1
- package/pi-extensions/lib/acp/event-mapper.ts +16 -13
- package/pi-extensions/lib/acp/models.ts +4 -4
- package/pi-extensions/lib/acp/overlay.ts +11 -9
- package/pi-extensions/lib/entwurf-control-rpc.ts +7 -5
- package/pi-extensions/lib/entwurf-core.ts +15 -15
- package/pi-extensions/lib/entwurf-resume-args.ts +41 -52
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-contract.ts +120 -99
- package/pi-extensions/lib/entwurf-v2-decider.ts +30 -91
- package/pi-extensions/lib/entwurf-v2-lock.ts +16 -7
- package/pi-extensions/lib/entwurf-v2-production.ts +4 -78
- package/pi-extensions/lib/entwurf-v2-release.ts +25 -49
- package/pi-extensions/lib/entwurf-v2-runner.ts +6 -21
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +12 -11
- package/pi-extensions/lib/entwurf-v2-send.ts +2 -7
- package/pi-extensions/lib/entwurf-v2-surface.ts +36 -76
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +370 -0
- package/pi-extensions/lib/meta-session.ts +93 -5
- package/pi-extensions/lib/mux-fresh-call.ts +328 -0
- package/pi-extensions/lib/mux-launch.ts +267 -0
- package/pi-extensions/lib/mux-placement.ts +387 -0
- package/pi-extensions/lib/mux-resume-call.ts +221 -0
- package/pi-extensions/lib/resume-launch-identity.ts +162 -0
- package/pi-extensions/lib/session-id.js +8 -5
- package/pi-extensions/lib/socket-discovery.ts +3 -3
- package/prompts/engraving.md +13 -5
- package/run.sh +688 -282
- package/scripts/agy-bridge-config.py +5 -1
- package/scripts/check-acp-backend-preflight.ts +1 -1
- package/scripts/check-acp-carrier-augment.ts +246 -10
- package/scripts/check-acp-cortex.ts +5 -5
- package/scripts/check-acp-overlay.ts +13 -3
- package/scripts/check-acp-prompt-lifecycle.ts +565 -0
- package/scripts/check-acp-stop-reason.ts +342 -0
- package/scripts/check-acp-stream-hooks.ts +504 -0
- package/scripts/check-elapsed.sh +25 -0
- package/scripts/check-entwurf-bridge-boot.ts +51 -4
- package/scripts/check-entwurf-bridge-pi-free.ts +6 -5
- package/scripts/check-entwurf-control-rpc.ts +4 -3
- package/scripts/check-entwurf-resume-args.ts +72 -70
- package/scripts/check-entwurf-session-identity.ts +14 -10
- package/scripts/check-entwurf-v2-contract.ts +34 -59
- package/scripts/check-entwurf-v2-decider.ts +17 -177
- package/scripts/check-entwurf-v2-lock.ts +5 -2
- package/scripts/check-entwurf-v2-matrix.ts +3 -53
- package/scripts/check-entwurf-v2-production.ts +2 -91
- package/scripts/check-entwurf-v2-release.ts +10 -105
- package/scripts/check-entwurf-v2-runner.ts +4 -85
- package/scripts/check-entwurf-v2-send-fallback.ts +5 -6
- package/scripts/check-entwurf-v2-send.ts +0 -28
- package/scripts/check-entwurf-v2-surface.ts +198 -128
- package/scripts/check-entwurf-v2-visible-resume.ts +445 -0
- package/scripts/check-fresh-cut-gate.sh +1 -1
- package/scripts/check-gate-qualification.ts +101 -7
- package/scripts/check-install-container.sh +10 -2
- package/scripts/check-install-surface.ts +1 -1
- package/scripts/check-keyset-overlap.py +1 -1
- package/scripts/check-meta-facts.ts +249 -0
- package/scripts/check-meta-identity-consumers.ts +1 -1
- package/scripts/check-meta-session.ts +169 -0
- package/scripts/check-mux-launch-tmux.ts +316 -0
- package/scripts/check-mux-launch.ts +288 -0
- package/scripts/check-mux-launcher-fence.ts +264 -0
- package/scripts/check-mux-parent-artifact.ts +195 -0
- package/scripts/check-mux-placement-tmux.ts +322 -0
- package/scripts/check-mux-placement.ts +323 -0
- package/scripts/check-mux-resume-call.ts +282 -0
- package/scripts/check-probe-cli-shim.ts +25 -22
- package/scripts/check-probe-ordering.ts +121 -81
- package/scripts/check-release-gate-outcomes.ts +452 -0
- package/scripts/check-resume-launch-identity.ts +244 -0
- package/scripts/check-socket-discovery.ts +1 -1
- package/scripts/fixtures/mux-parent-transcript.scrubbed.jsonl +3 -0
- package/scripts/inventory-verification-surface.ts +349 -0
- package/scripts/lib/claude-launcher-fence.ts +322 -0
- package/scripts/lib/live-skip.ts +33 -0
- package/scripts/lib/mutation-qualify.ts +109 -3
- package/scripts/lib/probe-acp-turn.ts +33 -12
- package/scripts/lib/step-outcome.sh +88 -0
- package/scripts/meta-bridge-doctor.sh +6 -8
- package/scripts/meta-facts.ts +60 -0
- package/scripts/mutants/acp-augment.json +106 -0
- package/scripts/mutants/acp-cortex.json +2 -2
- package/scripts/mutants/acp-overlay.json +17 -0
- package/scripts/mutants/acp-prompt-lifecycle.json +100 -0
- package/scripts/mutants/acp-stop-reason.json +80 -0
- package/scripts/mutants/acp-stream-hooks.json +158 -0
- package/scripts/mutants/bridge-boot-resume.json +45 -0
- package/scripts/mutants/meta-facts.json +50 -0
- package/scripts/mutants/meta-identity.json +36 -0
- package/scripts/mutants/mux-boundary.json +196 -0
- package/scripts/mutants/mux-fresh-call.json +185 -0
- package/scripts/mutants/mux-launcher-fence.json +123 -0
- package/scripts/mutants/mux-parent-artifact.json +39 -0
- package/scripts/mutants/mux-resume-call.json +148 -0
- package/scripts/mutants/probe-ordering.json +6 -1021
- package/scripts/mutants/release-gate.json +140 -0
- package/scripts/mutants/resume-args.json +76 -0
- package/scripts/mutants/resume-launch-identity.json +96 -0
- package/scripts/mutants/v2-surface.json +74 -23
- package/scripts/mutants/v2-visible-resume.json +215 -0
- package/scripts/new-session-id.ts +9 -4
- package/scripts/smoke-acp-bundled-mcp-live.ts +4 -3
- package/scripts/smoke-acp-carrier-augment-live.ts +2 -2
- package/scripts/smoke-acp-cortex-live.ts +8 -14
- package/scripts/smoke-acp-long-turn-live.ts +185 -0
- package/scripts/smoke-acp-mcp-live.ts +2 -2
- package/scripts/smoke-acp-memory-containment-live.ts +2 -2
- package/scripts/smoke-acp-ordering-probe-live.ts +2 -2
- package/scripts/smoke-acp-overlay-live.ts +2 -2
- package/scripts/smoke-acp-provider-live.ts +2 -2
- package/scripts/smoke-acp-raw-turn-live.ts +3 -3
- package/scripts/smoke-acp-session-reuse-live.ts +2 -2
- package/scripts/smoke-acp-skill-live.ts +2 -2
- package/scripts/smoke-acp-socket-citizen-live.ts +4 -3
- package/scripts/smoke-acp-v2-send-live.ts +4 -3
- package/scripts/smoke-agy-native-push-live.ts +10 -20
- package/scripts/smoke-claude-native-resume-live.sh +13 -3
- package/scripts/smoke-entwurf-chain-live.ts +352 -0
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -3
- package/scripts/smoke-meta-honesty.sh +1 -1
- package/scripts/smoke-meta-install-state.sh +4 -0
- package/scripts/smoke-mux-fresh-call-live.ts +365 -0
- package/scripts/smoke-mux-lifecycle-live.ts +1136 -0
- package/scripts/smoke-pi-attach.ts +1 -1
- package/scripts/smoke-user-scope-citizen.sh +1 -1
- package/scripts/tsconfig.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-preflight.js +0 -160
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +0 -273
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn.js +0 -216
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +0 -373
- package/pi-extensions/lib/entwurf-v2-spawn.ts +0 -323
- package/scripts/check-acp-sdk-surface.ts +0 -236
- package/scripts/check-entwurf-v2-spawn-production.ts +0 -551
- package/scripts/check-entwurf-v2-spawn.ts +0 -399
- package/scripts/smoke-entwurf-v2-spawn-live.ts +0 -188
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +0 -469
package/run.sh
CHANGED
|
@@ -51,6 +51,22 @@ PROVIDER_ID="entwurf"
|
|
|
51
51
|
# surfaces). Under an installed package it REFUSES rather than falling back to raw
|
|
52
52
|
# .ts — a fallback would just re-raise the fence error with a worse message.
|
|
53
53
|
# check-install-surface pins both halves statically.
|
|
54
|
+
# Release-gate STEP OUTCOME protocol (P1) — loaded LAZILY, never at top level.
|
|
55
|
+
#
|
|
56
|
+
# Only two surfaces need it: `release_gate`, which classifies each step's exit
|
|
57
|
+
# code, and the LIVE smoke wrappers, which return `$ENTWURF_STEP_SKIP_EXIT` when
|
|
58
|
+
# a prerequisite is missing. Both are dev-only. Sourcing it unconditionally at
|
|
59
|
+
# the top made EVERY subcommand depend on `scripts/lib/` being present, and
|
|
60
|
+
# check-fresh-cut-gate I9c caught the consequence immediately: on an installed
|
|
61
|
+
# tree assembled without that path, run.sh died with a bash "No such file"
|
|
62
|
+
# instead of printing the refusal it is supposed to print. An operator verb must
|
|
63
|
+
# never fail on a dev-only dependency, so the load happens where it is used.
|
|
64
|
+
entwurf_require_step_outcome() {
|
|
65
|
+
[ -n "${ENTWURF_STEP_SKIP_EXIT:-}" ] && return 0
|
|
66
|
+
# shellcheck source=scripts/lib/step-outcome.sh
|
|
67
|
+
. "$REPO_DIR/scripts/lib/step-outcome.sh"
|
|
68
|
+
}
|
|
69
|
+
|
|
54
70
|
run_ts() {
|
|
55
71
|
local rel="$1"; shift
|
|
56
72
|
case "$REPO_DIR" in
|
|
@@ -69,13 +85,44 @@ run_ts() {
|
|
|
69
85
|
esac
|
|
70
86
|
}
|
|
71
87
|
|
|
88
|
+
# Vitest-backed gate lanes (issue #62). Same authority boundary as run_ts's dev-clone
|
|
89
|
+
# refusal: vitest is a devDependency, so an installed package has no runner and the
|
|
90
|
+
# gate refuses legibly instead of silently passing or crashing on a missing binary.
|
|
91
|
+
run_vitest() {
|
|
92
|
+
case "$REPO_DIR" in
|
|
93
|
+
*/node_modules/*)
|
|
94
|
+
echo "entwurf: this gate is a dev-clone-only surface — vitest is a devDependency the installed package does not ship." >&2
|
|
95
|
+
echo " (Run it from a checkout after 'pnpm install'.)" >&2
|
|
96
|
+
return 1
|
|
97
|
+
;;
|
|
98
|
+
esac
|
|
99
|
+
local bin="$REPO_DIR/node_modules/.bin/vitest"
|
|
100
|
+
if [ ! -x "$bin" ]; then
|
|
101
|
+
echo "entwurf: vitest is not installed — run 'pnpm install' in the checkout first." >&2
|
|
102
|
+
return 1
|
|
103
|
+
fi
|
|
104
|
+
if [ -n "${ENTWURF_MUTATION_VITEST_REPORT:-}" ]; then
|
|
105
|
+
# Qualification asked for structured attribution: a kill is attributed from the
|
|
106
|
+
# failed TEST TITLES in this report, never from Vitest's code frame (which quotes
|
|
107
|
+
# the source lines around the assertion — including an adjacent PASSING test's
|
|
108
|
+
# [QK:…] title). The marker declares the lane structured; the report goes to a
|
|
109
|
+
# FILE because the runner merges stdout+stderr and one warning line ahead of the
|
|
110
|
+
# JSON would break the parse. Human output still rides stdout.
|
|
111
|
+
echo "__ENTWURF_VITEST_JSON__"
|
|
112
|
+
(cd "$REPO_DIR" && "$bin" run --reporter=default --reporter=json \
|
|
113
|
+
--outputFile.json="$ENTWURF_MUTATION_VITEST_REPORT" "$@")
|
|
114
|
+
return
|
|
115
|
+
fi
|
|
116
|
+
(cd "$REPO_DIR" && "$bin" run "$@")
|
|
117
|
+
}
|
|
118
|
+
|
|
72
119
|
usage() {
|
|
73
120
|
cat <<'EOF'
|
|
74
121
|
Usage:
|
|
75
122
|
./run.sh setup [project-dir] # ONE confident install: pnpm install + install + meta-bridge (if native harness) + v2 install smoke (LIVE substrate = release-gate)
|
|
76
|
-
./run.sh release-gate [project-dir] [--allow-skip-gemini] # SINGLE release gate: full static (pnpm check) + the v2-native live gates (v2 matrix
|
|
123
|
+
./run.sh release-gate [project-dir] [--cut] [--allow-skip-gemini] # SINGLE release gate: full static (pnpm run check:full) + the v2-native live gates (v2 matrix-live, check-bridge, RGG) + the ACP plugin acceptance floor (12 LIVE smokes: socket-citizen/raw-turn/overlay/provider/session-reuse/carrier-augment/memory-containment/rgg/mcp/skill/bundled-mcp/v2-send) + the one surviving axis the aggregate used to omit silently (claude-native-resume; Cortex stays a documented on-demand direct call) + the cross-harness delivery chain (smoke-entwurf-chain-live). TWO-TIER summary: MUST (release-blocking, owns the exit code — "green" applies here) + BEHAVIOR (advisory, non-blocking: RGG positives model-in-loop turn). STEP OUTCOME protocol: every step is INVOKED and reports its own PASS / SKIP (exit 97, a prerequisite it does not have) / FAIL — a skip is never counted as a pass. Without --cut this is the unattended diagnostic (SKIPs reported, exit 0). WITH --cut it is read as release acceptance and ANY MUST SKIP is red, which is what makes "a CUT needs LIVE=1, SKIP=0" executable instead of prose. --allow-skip-gemini accepted-but-ignored (back-compat). final cut authorization is GLG's.
|
|
77
124
|
./run.sh check-bridge # entwurf-bridge direct MCP smoke + protocol/negative-path test.sh (live substrate = v2 live smokes)
|
|
78
|
-
./run.sh check-entwurf-bridge-boot # deterministic gate (5d-5-pre, G1a/G1b, IN pnpm check): boot start.sh under strip-types + assert v2 fence graph loads + entwurf_v2 registered/schema; tools/list only, no auth/side-effect
|
|
125
|
+
./run.sh check-entwurf-bridge-boot # deterministic gate (5d-5-pre, G1a/G1b/G1e/G1f, IN pnpm run check:full): boot start.sh under strip-types + assert v2 fence graph loads + entwurf_v2 and entwurf_resume_call registered/schema + the tools/list surface is EXACTLY the seven shipped garden verbs; tools/list only, no auth/side-effect
|
|
79
126
|
./run.sh check-entwurf-bridge-pi-free # deterministic gate (0.12.1 A, IN pnpm check): static — bridge index eager value-import closure must carry no @earendil-works/pi-* (type-only + dynamic import excluded); proves the meta-bridge boots pi-free
|
|
80
127
|
./run.sh check-model-lock # deterministic unit test for pi-extensions/model-lock.ts (4-quadrant + edge cases, no API)
|
|
81
128
|
./run.sh check-shell-quote # POSIX-safety gate for shellQuote (remote SSH arg quoting in entwurf paths) — source parity + behavior matrix, no SSH
|
|
@@ -86,7 +133,7 @@ Usage:
|
|
|
86
133
|
./run.sh check-entwurf-capabilities # deterministic gate (0.11 Stage 0 step 3C): backend capability registry (pi/entwurf-capabilities.json) — coverage==META_CITIZEN_BACKENDS + agrees with live META_BACKEND_DESCRIPTORS + strict keyset, no API
|
|
87
134
|
./run.sh check-capability-bundle-reach # deterministic gate (IN pnpm check): re-ask EVERY shipped copy of meta-session (source + bridge bundle emit) whether metaCapabilitiesFilePath() reaches the registry — the artifact-depth check the source-path gates cannot make; needs a built dist, missing dist FAILS
|
|
88
135
|
./run.sh smoke-pi-attach # deterministic gate (#50 C2 checkpoint + C3 ACP tail): a pi session attaches as a V3 meta-record citizen (backend:"pi"), the gardenId is the RECORD's not pi's session id, the control socket is keyed on it, a re-open ATTACHES to the same address (never a second mint), the BUILT DIST ENTRY driven over MCP stdio lists the citizen + delivers entwurf_v2 to that socket with an RPC ack, and the ACP identity chain lands a send AS the host record (enrichMcpServersWithEnvelope env → bridge sender = host gardenId). mkdtemp-isolated; the live store is never read
|
|
89
|
-
./run.sh check-bridge-delivery # deterministic gate (IN pnpm check): demo scene 3 recovered — seed strict meta-sender + armed receiver citizens in an isolated temp world, scrub ambient pi/sender carriers, drive the BUILT DIST ENTRY over MCP stdio through a real tools/call entwurf_v2, assert the .msg landed under the seeded sender + doorbell poked. DELIVERS through the artifact, not from source. ENTWURF_DELIVERY_SUBJECT=<launcher> replays the same scene against another consumer artifact (check-pack-install passes the npm-installed bin). No model/network/cost; stale or missing dist FAILS
|
|
136
|
+
./run.sh check-bridge-delivery # deterministic gate (IN pnpm run check:full): demo scene 3 recovered — seed strict meta-sender + armed receiver citizens in an isolated temp world, scrub ambient pi/sender carriers, drive the BUILT DIST ENTRY over MCP stdio through a real tools/call entwurf_v2, assert the .msg landed under the seeded sender + doorbell poked. DELIVERS through the artifact, not from source. ENTWURF_DELIVERY_SUBJECT=<launcher> replays the same scene against another consumer artifact (check-pack-install passes the npm-installed bin). No model/network/cost; stale or missing dist FAILS
|
|
90
137
|
./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
138
|
./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
139
|
./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
|
|
@@ -94,24 +141,27 @@ Usage:
|
|
|
94
141
|
./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
142
|
./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
143
|
./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 control-socket domain (currently pi; claude/codex/agy=unsupported, not folded),
|
|
144
|
+
./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), 3-cell intent×liveness table (single verdict, 1 allow/2 reject after the visible-first cut), N1 indeterminate-no-spawn, R3 table↔receipt round-trip, R5 taxonomy, schema↔types drift; pure, no API
|
|
98
145
|
./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
146
|
./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
|
-
./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/
|
|
101
|
-
./run.sh check-entwurf-v2-release # deterministic gate (0.11 Stage 0 step 5c-1): PURE release-policy reducer (decideReleasePolicy + reduceRelease) —
|
|
147
|
+
./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/native-push + bad-target/conflict/locked/undeliverable/dormant/indeterminate rejects), coverage pass fails on a dropped cell; thin coverage not a decider re-impl; pure, no IO
|
|
148
|
+
./run.sh check-entwurf-v2-release # deterministic gate (0.11 Stage 0 step 5c-1): PURE release-policy reducer (decideReleasePolicy + reduceRelease) — the spawn-observation policy and its four release events went with the transport in the visible-first cut, so the shipped machine is meta-mailbox=never release (no lock) + control-socket=release once on send-final; decideReleasePolicy still enforces the lock-nullness invariant; pure, no IO
|
|
102
149
|
./run.sh check-entwurf-v2-send # deterministic gate (0.11 Stage 0 step 5c-2a): control-socket SEND hand (executeControlSocketSend) wiring transport IO onto the 5c-1 reducer — ack→sent, in-band reject→rejected (no fallback), dead→same-lock one-shot re-resolve (control retry / mailbox enqueue), indeterminate→failed+rethrow with NO fallback (no double-delivery); release exactly once, releaseLock throw never masks the send error; IO-via-dep
|
|
103
|
-
./run.sh check-entwurf-v2-send-fallback # deterministic gate (0.11 Stage 0 step 5c-2b): same-lock re-resolve RESOLVER (resolveDeadControlSendFallback) — fire-and-forget re-resolve: alive→control retry, dead→reject (
|
|
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/
|
|
150
|
+
./run.sh check-entwurf-v2-send-fallback # deterministic gate (0.11 Stage 0 step 5c-2b): same-lock re-resolve RESOLVER (resolveDeadControlSendFallback) — fire-and-forget re-resolve: alive→control retry, dead→reject (nothing is ever launched), indeterminate→reject, unsupported+deliverable→mailbox plan, undeliverable/bad-target/conflict→reject; resolver never releases, mis-wire fails loud, inspect/probe throws propagate; no IO (fakes)
|
|
151
|
+
./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/mailbox→matching hand with decision.lock verbatim / N3 rejectReason carried / N1 SendDeliveredReleaseFailedError→execution-failed{finalizedOutcome,releaseFailed,retrySafe:false}; fake hands, no IO
|
|
105
152
|
./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
|
-
./run.sh check-entwurf-
|
|
107
|
-
./run.sh check-
|
|
108
|
-
./run.sh check-
|
|
109
|
-
./run.sh
|
|
110
|
-
./run.sh
|
|
153
|
+
./run.sh check-entwurf-resume-args # deterministic gate: resume-argv SSOT (buildResumePiArgs) for the S1 VISIBLE resume. The headless shape was measured wrong for a window before the consumer was written (`-p` is pi's own non-interactive mode), so the one shipped posture is `--entwurf-control` FIRST + ext args exactly once + `--session <abs file>` + optional `--provider` + `--model <m>` — and the gate pins the ABSENCES as hard as the presences: no --mode, no -p, no positional prompt (a resume runs no turn), no --no-extensions, never --session-id (which MINTS a session instead of resuming one)
|
|
154
|
+
./run.sh check-mux-resume-call # deterministic gate: S1 resume PLACEMENT composition (mux-resume-call.ts). No fake tmux. cwd rules are MEASURED tmux 3.6a behaviours, each a way a resume looks successful while being wrong: a nonexistent `-c` exits 0 and lands the child in $HOME (so it is refused HERE), `-c` is FORMAT-EXPANDED so `#{…}` silently rewrites the path and `#(…)` was observed running a command (so `#` is refused), and whitespace measured SAFE (so no escaping layer is owed). Also pins `-c` reaching tmux, runtime after `--`, carrier-free argv, zero identity in this module, and the surface seam that keeps the v2 composition from importing mux
|
|
155
|
+
./run.sh check-mux-parent-artifact # deterministic gate for the tracked scrubbed parent-transcript fixture — a version-pinned sample of the PARENT-SIDE shape (fresh_call toolResult + the later callback custom_message) so downstream never opens a private transcript. Pins event order, the toolCallId join on the RESULT (pi writes no separate toolCall row), the launch nonce reappearing verbatim in the callback body, the <sender_info> envelope field names, and the absence of operator paths / real garden ids / real uuids. NOT placement evidence
|
|
156
|
+
./run.sh check-mux-launcher-fence # deterministic gate for the shared operator-launcher fence (issue #67): scripts/lib/claude-launcher-fence.ts + its wiring into BOTH mux LIVE smokes. Replants the observed install-destruction shape (real HOME + fixture XDG_DATA_HOME → self-update retargets the real `claude` launcher into the fixture tree, teardown deletes it) wholly inside disposable mkdtemp roots — the real launcher is never inspected. Pins fail-closed preflight, retarget/content-change detection before cleanup, removal BLOCKED on fixture reference / unproven safety / surviving tracked panes, exact operator-parity XDG restore (absent = DELETED, not canonical defaults), the lifecycle cell-branch topology, and one shared helper consumed by both smokes
|
|
157
|
+
./run.sh check-entwurf-v2-visible-resume # deterministic gate: S1 visible-resume COMPOSITION (entwurf-v2-visible-resume.ts) with every seam injected — the whole state machine incl. the timeout branch runs with no tmux/lock/socket/clock. Pins lock BEFORE liveness, identity under the lock and before any window (no-transcript citizen fails loud, opens nothing), live/indeterminate/address-conflict refused unlaunched, observation as a BOUNDED WAIT (measured: socket answers ~2–4s after launch, so one immediate probe would call a successful resume unobserved), exactly ONE launch on every path, timeout → lock released + window left open + nothing retried/killed, failed release throws, and the two receipts staying separate in type and text
|
|
158
|
+
./run.sh check-resume-launch-identity # deterministic gate for resume-launch-identity.ts, the record-authoritative launch-identity leaf preserved through the visible-first cut (spawn-bg and all its callers are gone; this leaf answers "which being is this, and which conversation is theirs"). Temp meta-store fixture: gardenId→record.transcriptPath happy path with header cwd/provider/model; C3 integrity (header id ≠ record.nativeSessionId → refused, never resumed); #52 ADDRESSABLE read (a gid that no longer holds its nativeSessionId alone is refused from EITHER side — the plain targeted read would resume one transcript twice under two locks); cause fidelity per impossible resume incl. the F7 pin (recorded-but-deleted transcript → MISSING, not "no recorded model"); header↔gate SSOT. No spawn/socket/timer
|
|
111
159
|
./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
|
-
./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),
|
|
160
|
+
./run.sh smoke-agy-native-push-live # 봉인 8 LIVE acceptance for the native-push (agy) rail — OUT of pnpm check, needs LIVE=1 + AGY_CONVERSATION_ID (a live agy conversation). Drives the REAL antigravity adapter + register core + runEntwurfV2 (production deps): doctor-static preflight (dangling→FAIL, the ③ gate), probe route, register create/attach idempotency, fire→native-push delivered, post-send re-probe (D7 partial), bogus-conv→native-push-probe-indeterminate. Meta-store isolated to a temp dir (only the agy round-trip is real; no real-store residue). LIVE=1 AGY_CONVERSATION_ID=<convId> ./run.sh smoke-agy-native-push-live
|
|
161
|
+
./run.sh smoke-mux-lifecycle-live # RELEASE MUST integrated LIVE lifecycle acceptance for mux, through the REAL MCP surface — OUT of pnpm check, needs LIVE=1 and spends model turns (two pi siblings: native + recorded-ACP provider, each resumed once; one Claude Code sibling). tools/call fresh_call -> nonce callback sender envelope -> v2 control send landing in the sibling's own transcript -> resume_call REFUSED while live (window count unchanged) -> stable-handle close (pane gone, socket dead, record kept) -> dormant delivery refused honestly -> public entwurf_resume_call with LAUNCH and OBSERVATION receipts kept apart, same-gid socket alive, zero new citizens, zero lock residue, resumed pane_start_path == RECORD cwd (separate tmux query), transcript byte-identical across the resume -> v2 recall of the pre-close fact. claude-code resume refused target-not-pi, no window opened and no lock residue. LIVE=1 ./run.sh smoke-mux-lifecycle-live
|
|
113
162
|
./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
163
|
./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
|
|
164
|
+
./run.sh check-meta-facts # deterministic gate for the meta-facts projection (#65): drives the REAL CLI — full-record join, parse-before-uniqueness, no-winner duplicates, drift/symlink/invalid-UTF-8 defects in-band, deterministic bytes, exit contract 0/2/3, dispatch+emit reachability
|
|
115
165
|
./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
166
|
./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
167
|
./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
|
|
@@ -129,9 +179,11 @@ Usage:
|
|
|
129
179
|
./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)
|
|
130
180
|
./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
181
|
./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)
|
|
182
|
+
./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
|
|
183
|
+
./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
|
|
132
184
|
./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 check-probe-ordering # §11-7 ordering-probe deterministic gate: raw-client SAMENESS pinned to backend.ts (sequence/args/timeouts/permission policy — the probe may never measure a lookalike), phase attribution incl. set-model, probe-mode fixture wire markers (delay honored, probeRunId REQUIRED, smoke-acp-mcp-live legacy compat), event-log door integrity (reserved keys refused at write; unknown marker name, broken sort axis, or a payload the classifier cannot judge on is MALFORMED, never a quiet event), and the §11-7 paired-verdict truth table (P0/I0 outside the space, phase-qualified D, B promotion ladder, C, A two-delay rule). Offline/deterministic;
|
|
134
|
-
./run.sh check-probe-cli-shim # §11-7-c B-name-snapshot PRODUCER gate: the CLI shim driven as a REAL process against fake CLIs (no API, no cost). Proves what a defect would buy — FABRICATED evidence (a malformed init is never reported as an empty name set; the boot report carries the true target path+sha256 the classifier verifies against the roster), a DESTROYED turn (byte transparency across mid-UTF8/CRLF/oversized/unterminated framing, exit-code fidelity, signal re-raise, inbound signal forwarding, stderr passthrough, stdout backpressure), and LEAKED operator state (exact-allowlist env scrub, no argv/env/prompt body in the log). Offline/deterministic;
|
|
185
|
+
./run.sh check-probe-ordering # §11-7 ordering-probe deterministic gate: raw-client SAMENESS pinned to backend.ts (sequence/args/timeouts/permission policy — the probe may never measure a lookalike), phase attribution incl. set-model, probe-mode fixture wire markers (delay honored, probeRunId REQUIRED, smoke-acp-mcp-live legacy compat), event-log door integrity (reserved keys refused at write; unknown marker name, broken sort axis, or a payload the classifier cannot judge on is MALFORMED, never a quiet event), and the §11-7 paired-verdict truth table (P0/I0 outside the space, phase-qualified D, B promotion ladder, C, A two-delay rule). Offline/deterministic; one product claim (no production prompt cutoff) is replant-qualified via scripts/mutants/probe-ordering.json, while the other assertions are direct [CHECK:*] contracts
|
|
186
|
+
./run.sh check-probe-cli-shim # §11-7-c B-name-snapshot PRODUCER gate: the CLI shim driven as a REAL process against fake CLIs (no API, no cost). Proves what a defect would buy — FABRICATED evidence (a malformed init is never reported as an empty name set; the boot report carries the true target path+sha256 the classifier verifies against the roster), a DESTROYED turn (byte transparency across mid-UTF8/CRLF/oversized/unterminated framing, exit-code fidelity, signal re-raise, inbound signal forwarding, stderr passthrough, stdout backpressure), and LEAKED operator state (exact-allowlist env scrub, no argv/env/prompt body in the log). Offline/deterministic; 20 direct [CHECK:*] contracts, deliberately no longer replant-qualified after #70 subtraction
|
|
135
187
|
./run.sh smoke-agy-statusline-state # agy ambient garden-id statusLine install/doctor/inverse regression. Offline/deterministic
|
|
136
188
|
./run.sh smoke-agy-hooks-state # agy PreInvocation birth/sender hook install/doctor/inverse + direct stdin→meta-record regression. Offline/deterministic
|
|
137
189
|
./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)
|
|
@@ -154,12 +206,13 @@ Usage:
|
|
|
154
206
|
./run.sh doctor-agy-hooks # fail-loud doctor for agy hooks.json imprint wiring
|
|
155
207
|
./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])
|
|
156
208
|
./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)
|
|
209
|
+
./run.sh meta-facts # #65 owner-normalized READ-ONLY store projection: deterministic JSON {schemaVersion:1, storeDir, citizens: full v3 records sorted by gardenId, defects: {filename,message}} — THE listing contract emitted by the owner so consumers stop copying the certification. No liveness/sockets/transcript contents. EXIT: 0 readable (defects in-band; missing store = empty), 2 usage, 3 unreadable ([dir])
|
|
157
210
|
./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)
|
|
158
211
|
./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)
|
|
159
212
|
./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)
|
|
160
213
|
./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
|
|
161
214
|
./run.sh check-pack # publish gate (dry-run): npm pack --dry-run + tarball invariants (runtime-critical present, dev residue absent)
|
|
162
|
-
./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
|
|
215
|
+
./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
|
|
163
216
|
./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)
|
|
164
217
|
./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)
|
|
165
218
|
./run.sh sync-auth # copy ~/.pi/agent/auth.json anthropic OAuth credentials to entwurf alias
|
|
@@ -362,7 +415,7 @@ preflight_dep_integrity() {
|
|
|
362
415
|
# pi-managed install — pi omits peers (--legacy-peer-deps) and its own loader
|
|
363
416
|
# supplies the runtime, so the trio is legitimately absent.
|
|
364
417
|
# neutral npm/pnpm install — nothing supplies it. The optional peer is simply
|
|
365
|
-
# unresolved (entwurf-preflight.ts:51), and the
|
|
418
|
+
# unresolved (entwurf-preflight.ts:51), and the project-trust lane that needs it
|
|
366
419
|
# is dead on that host. Excluding the trio from this probe is still right (a hard
|
|
367
420
|
# require would reject every consumer install), but it is a KNOWN GAP, not proof
|
|
368
421
|
# that the runtime is present by another route.
|
|
@@ -517,7 +570,7 @@ remove_user_scope_citizen() {
|
|
|
517
570
|
|
|
518
571
|
# The ~/.pi/agent/entwurf-targets.json symlink machinery (ensure_agent_dir_symlinks
|
|
519
572
|
# + the `setup:links` command) is GONE (#50 C3): the target registry it linked has
|
|
520
|
-
# no reader anymore — v2
|
|
573
|
+
# no reader anymore — v2 addresses record-backed citizens and never resolves a spawn
|
|
521
574
|
# model from a file. An operator's existing link/copy is inert; nothing reads it.
|
|
522
575
|
|
|
523
576
|
remove_local_package() {
|
|
@@ -649,7 +702,7 @@ smoke_pi_attach() {
|
|
|
649
702
|
# ARTIFACT routes that garden id to its control socket. Two halves, deliberately
|
|
650
703
|
# different in kind: the record+address half drives `birthPiCitizen` (the exact seam
|
|
651
704
|
# entwurf-control's session_start calls) so the gate is deterministic and lives in
|
|
652
|
-
# `pnpm check`; the delivery half spawns the dist entry as its own process and speaks
|
|
705
|
+
# `pnpm run check:full`; the delivery half spawns the dist entry as its own process and speaks
|
|
653
706
|
# MCP stdio (check-bridge-delivery's driver, socket-rail fixture). P4 is the one with
|
|
654
707
|
# teeth — re-opening the same pi session must ATTACH to the same gardenId, never mint
|
|
655
708
|
# a second address under peers that already hold it. P8 (#50 C3 tail) gates goal 3:
|
|
@@ -749,17 +802,17 @@ check_entwurf_v2_contract() {
|
|
|
749
802
|
# decision table is a constant; the "table cell ↔ dispatch receipt" round-trip
|
|
750
803
|
# is asserted exhaustively — THE executable proof F6 demands ("산문 금지").
|
|
751
804
|
# R1 control-socket capability domain (currently pi; claude-code/codex/antigravity =
|
|
752
|
-
# unsupported, never folded into dead/indeterminate).
|
|
753
|
-
# verdict per cell
|
|
754
|
-
#
|
|
755
|
-
# pre-claims bad-target/
|
|
805
|
+
# unsupported, never folded into dead/indeterminate). 3-cell table since the
|
|
806
|
+
# visible-first cut, single verdict per cell, 1 allow / 2 reject. N1
|
|
807
|
+
# indeterminate never dispatches, and nothing on any cell starts a process.
|
|
808
|
+
# R5 taxonomy covers table reasons + pre-claims bad-target/target-locked. Plus
|
|
756
809
|
# a schema↔types drift guard on the TypeBox input/receipt. Pure, no API.
|
|
757
810
|
run_ts scripts/check-entwurf-v2-contract.ts
|
|
758
811
|
}
|
|
759
812
|
|
|
760
813
|
check_entwurf_v2_lock() {
|
|
761
814
|
# Deterministic gate for 0.11 Stage 0 step 5a (버킷 B F2): the per-gid dispatch
|
|
762
|
-
# LOCK primitive —
|
|
815
|
+
# LOCK primitive — what serializes concurrent in-domain dispatch at one
|
|
763
816
|
# target (pi self-guards CREATE but not RESUME, 검증원장 F2). acquire =
|
|
764
817
|
# openSync(lockPath,"wx") atomic; a second acquire without release =
|
|
765
818
|
# target-locked conflict carrying the holder JSON (F2-P2 human cleanup). release
|
|
@@ -778,10 +831,8 @@ check_entwurf_v2_decider() {
|
|
|
778
831
|
# lookup / lock / socket inspect+probe / preflight / capability), tracking lock
|
|
779
832
|
# acquire+release so "reject ⇒ no plan AND no lock retained" is PROVEN. Covers:
|
|
780
833
|
# bad-target/target-locked/target-address-conflict carry observedLiveness=null
|
|
781
|
-
# (pre-probe), every other reject
|
|
782
|
-
#
|
|
783
|
-
# takes NO lock (?7); resume plan has no mode/wantsReply/provider/model but has
|
|
784
|
-
# expectedSocketPath/observeTimeoutMs/releaseWhen; an invalid gid throws before
|
|
834
|
+
# (pre-probe), every other reject carries a measured value; a control-socket send
|
|
835
|
+
# executes KEEPING the lock, meta-mailbox send takes NO lock (?7); an invalid gid throws before
|
|
785
836
|
# any lookup (F2-P1). Pure, no IO, no API.
|
|
786
837
|
run_ts scripts/check-entwurf-v2-decider.ts
|
|
787
838
|
}
|
|
@@ -791,9 +842,9 @@ check_entwurf_v2_matrix() {
|
|
|
791
842
|
# TABLE. Drives the REAL decideDispatch over minimal injected fakes and fixes, as
|
|
792
843
|
# one readable table, every (target kind → transport → lock class) cell the 5d-5
|
|
793
844
|
# claim covers: bad-target/address-conflict/target-locked rejects, unsupported
|
|
794
|
-
# meta-mailbox (deliverable) vs mailbox-undeliverable (inactive)
|
|
795
|
-
# in-domain control-socket (live) /
|
|
796
|
-
# (
|
|
845
|
+
# meta-mailbox (deliverable) vs mailbox-undeliverable (inactive) reject,
|
|
846
|
+
# in-domain control-socket (live) / released rejects
|
|
847
|
+
# (ff-dormant, indeterminate, under-lock conflict). A coverage pass
|
|
797
848
|
# FAILS if any transport / lock class / pre-probe reject is missing — a dropped
|
|
798
849
|
# decider cell cannot pass silently. Thin coverage, NOT a decider re-impl; surface
|
|
799
850
|
# parity stays in check-entwurf-v2-surface. Pure, no IO, no API.
|
|
@@ -804,11 +855,10 @@ check_entwurf_v2_release() {
|
|
|
804
855
|
# Deterministic gate for 0.11 Stage 0 step 5c-1: the PURE release-policy reducer
|
|
805
856
|
# (decideReleasePolicy + reduceRelease) for the 5c transport hand. Proves the
|
|
806
857
|
# Fable-3 "release-after-observation" timing as a pure state machine BEFORE any
|
|
807
|
-
#
|
|
808
|
-
# on send-final
|
|
809
|
-
#
|
|
810
|
-
#
|
|
811
|
-
# decideReleasePolicy enforces the lock-nullness invariant (?7). Pure, no IO.
|
|
858
|
+
# send IO: meta-mailbox=never release (no lock), control-socket=release once
|
|
859
|
+
# on send-final. The spawn-observation policy and its four release events went with
|
|
860
|
+
# the transport in the visible-first cut; decideReleasePolicy still enforces the
|
|
861
|
+
# lock-nullness invariant (?7). Pure, no IO.
|
|
812
862
|
run_ts scripts/check-entwurf-v2-release.ts
|
|
813
863
|
}
|
|
814
864
|
|
|
@@ -829,11 +879,11 @@ check_entwurf_v2_send_fallback() {
|
|
|
829
879
|
# (resolveDeadControlSendFallback) the 5c-2a hand calls on a dead connect. Proves the
|
|
830
880
|
# fire-and-forget re-resolve routing over injected fakes (no filesystem): alive->
|
|
831
881
|
# control-socket retry (inspected socketPath) / dead(absent)->reject (dormant-fire-
|
|
832
|
-
# forget-unsupported,
|
|
882
|
+
# forget-unsupported, and nothing is launched) / indeterminate->reject / unsupported+deliverable
|
|
833
883
|
# ->meta-mailbox plan (mini-table, no inspect/probe) / unsupported+undeliverable->reject
|
|
834
884
|
# / bad-target + address-conflict->reject pre-probe. Mis-wire (plan/lock gid) fails loud
|
|
835
885
|
# before IO; inspect/probe throws PROPAGATE (the hand owns failed+release); the resolver
|
|
836
|
-
# has NO release seam; every execute plan keeps the held gid
|
|
886
|
+
# has NO release seam; every execute plan keeps the held gid.
|
|
837
887
|
run_ts scripts/check-entwurf-v2-send-fallback.ts
|
|
838
888
|
}
|
|
839
889
|
|
|
@@ -871,8 +921,7 @@ check_entwurf_v2_runner() {
|
|
|
871
921
|
# routes an already-decided DispatchDecision to its 5c transport hand and maps the outcome
|
|
872
922
|
# to one outcome-rich EntwurfV2RunResult. Proves over injected fake hands (no socket/spawn/
|
|
873
923
|
# timer): reject -> rejected (receipt+diagnostic carried, NO hand called) / control-socket ->
|
|
874
|
-
# sendControl(plan, lock) /
|
|
875
|
-
# ride `executed`, fail-closed is not a failure) / meta-mailbox -> sendMailbox(plan, NULL
|
|
924
|
+
# sendControl(plan, lock) / meta-mailbox -> sendMailbox(plan, NULL
|
|
876
925
|
# lock, ?7). Carry-overs: N3 control `rejected` carries rejectReason verbatim; N1
|
|
877
926
|
# SendDeliveredReleaseFailedError -> execution-failed{finalizedOutcome, releaseFailed,
|
|
878
927
|
# retrySafe:false}; a plain hand throw -> execution-failed{retrySafe:false} with no
|
|
@@ -884,8 +933,9 @@ check_entwurf_v2_surface() {
|
|
|
884
933
|
# Deterministic gate for 0.11 Stage 0 step 5d-3a: the ctx-free surface adapter
|
|
885
934
|
# (entwurf-v2-surface.ts) + the entwurf-control.ts wiring contract. Proves the pure parts:
|
|
886
935
|
# toDispatchInput (wants_reply→wantsReply, absent mode/wants_reply undefined) / renderEntwurfV2Result
|
|
887
|
-
# per result kind ({text,isError} surfacing reject diagnostic, control N3 rejectReason,
|
|
888
|
-
#
|
|
936
|
+
# per result kind ({text,isError} surfacing reject diagnostic, control N3 rejectReason,
|
|
937
|
+
# N1 delivered-but-dirty) + the dormant/indeterminate reject HINTS an operator meets after the
|
|
938
|
+
# visible-first cut / surface ctx-free source guard / entwurf-control
|
|
889
939
|
# registers entwurf_v2 + reaches the fence via a NON-LITERAL dynamic import (no static fence
|
|
890
940
|
# import → TS5097 stays closed) + decorates sender origin:pi-session/replyable:true.
|
|
891
941
|
run_ts scripts/check-entwurf-v2-surface.ts
|
|
@@ -897,7 +947,7 @@ check_entwurf_bridge_boot() {
|
|
|
897
947
|
# source-shape gate check-entwurf-v2-surface cannot — that the whole v2 fence graph LOADS at
|
|
898
948
|
# boot under strip-types (G1a: a parseable tools/list proves it) and that entwurf_v2 is
|
|
899
949
|
# registered on the runtime surface with its schema (G1b). tools/list only → no tools/call,
|
|
900
|
-
# no lock/fs side effect, no auth → safe in pnpm check. Broad protocol/negative suite stays
|
|
950
|
+
# no lock/fs side effect, no auth → safe in pnpm run check:full. Broad protocol/negative suite stays
|
|
901
951
|
# in check-bridge/test.sh (D1=A안).
|
|
902
952
|
run_ts scripts/check-entwurf-bridge-boot.ts
|
|
903
953
|
}
|
|
@@ -916,10 +966,9 @@ check_entwurf_bridge_pi_free() {
|
|
|
916
966
|
check_entwurf_v2_production() {
|
|
917
967
|
# Deterministic gate for 0.11 Stage 0 step 5d-2b: makeProductionEntwurfV2Deps — the ctx-free
|
|
918
968
|
# PRODUCTION assembly of runEntwurfV2's deps. Proves the wiring over fake leaf-IO spies (no
|
|
919
|
-
# real socket/lock/
|
|
969
|
+
# real socket/lock/meta-record): decide wraps decideDispatch and acquires under the
|
|
920
970
|
# wired lockDir / control sendOverSocket builds the RpcSendCommand + maps + releases under
|
|
921
|
-
# lockDir /
|
|
922
|
-
# factory default) / the mailbox hand enqueues onto the wired dirs / a dead control send
|
|
971
|
+
# lockDir / the mailbox hand enqueues onto the wired dirs / a dead control send
|
|
923
972
|
# re-resolves to the SAME sendViaMailbox instance on the SAME dirs (Q3+Q5 no drift).
|
|
924
973
|
run_ts scripts/check-entwurf-v2-production.ts
|
|
925
974
|
}
|
|
@@ -935,62 +984,166 @@ check_entwurf_control_rpc() {
|
|
|
935
984
|
run_ts scripts/check-entwurf-control-rpc.ts
|
|
936
985
|
}
|
|
937
986
|
|
|
938
|
-
check_entwurf_v2_spawn() {
|
|
939
|
-
# Deterministic gate for 0.11 Stage 0 step 5c-3a: the spawn-bg RESUME watcher hand
|
|
940
|
-
# (executeSpawnBgResume) wiring spawn + socket-observe IO onto the 5c-1 reducer. Proves
|
|
941
|
-
# Fable-3 over injected deferred promises (no real child/socket/timer): TIMEOUT IS NOT A
|
|
942
|
-
# RELEASE — a bare observeTimeout escalates to killChild (release 0), then a BOUNDED
|
|
943
|
-
# killGrace waits for a real socket-alive / child-exited to release. socket-alive ∨
|
|
944
|
-
# child-exited(any code incl. null) -> release exactly once; the loser settling later is a
|
|
945
|
-
# no-op. spawnChild throw -> spawn-start-failed (release, nothing to watch). No observation
|
|
946
|
-
# obtainable (grace elapses, or a post-spawn watch dep throws and the exit can't be
|
|
947
|
-
# observed) -> lock-retained fail-closed (released:false, pid/socket/lockPath surfaced) —
|
|
948
|
-
# there is NO direct-release hatch; deps.releaseLock is reached ONLY via reduceRelease.
|
|
949
|
-
run_ts scripts/check-entwurf-v2-spawn.ts
|
|
950
|
-
}
|
|
951
|
-
|
|
952
987
|
check_entwurf_resume_args() {
|
|
953
|
-
# Deterministic gate for
|
|
954
|
-
#
|
|
955
|
-
#
|
|
956
|
-
#
|
|
957
|
-
#
|
|
958
|
-
# prompt
|
|
959
|
-
# (provider-resolution footgun
|
|
960
|
-
# null provider emitting no --provider.
|
|
988
|
+
# Deterministic gate for the resume-argv SSOT (buildResumePiArgs). S1 replaced the headless
|
|
989
|
+
# shape with the VISIBLE one, measured against the runtime before the consumer was written:
|
|
990
|
+
# `-p` is pi's own non-interactive mode, so the old `--mode json -p … <prompt>` prefix would
|
|
991
|
+
# put a JSON stream in the operator's window instead of a session they can use. Pins the one
|
|
992
|
+
# shipped posture — `--entwurf-control` FIRST (the resumed session stands its socket up), no
|
|
993
|
+
# --mode/-p/positional prompt (a resume runs no turn), explicitExtensionArgs exactly once
|
|
994
|
+
# between the control flag and --session (#29 provider-resolution footgun), --session <abs
|
|
995
|
+
# file> never --session-id (which MINTS), and a null provider emitting no --provider.
|
|
961
996
|
run_ts scripts/check-entwurf-resume-args.ts
|
|
962
997
|
}
|
|
963
998
|
|
|
964
|
-
|
|
965
|
-
# Deterministic gate for
|
|
966
|
-
#
|
|
967
|
-
#
|
|
968
|
-
#
|
|
969
|
-
#
|
|
970
|
-
#
|
|
971
|
-
#
|
|
972
|
-
#
|
|
973
|
-
#
|
|
974
|
-
#
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
#
|
|
981
|
-
#
|
|
982
|
-
#
|
|
983
|
-
#
|
|
984
|
-
#
|
|
985
|
-
#
|
|
986
|
-
#
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
999
|
+
check_mux_launcher_fence() {
|
|
1000
|
+
# Deterministic gate for the shared operator-launcher fence (issue #67):
|
|
1001
|
+
# scripts/lib/claude-launcher-fence.ts plus its wiring into BOTH mux LIVE smokes. Replants the
|
|
1002
|
+
# observed install-destruction shape (real HOME + fixture XDG_DATA_HOME → self-update retargets
|
|
1003
|
+
# the real `claude` launcher into the fixture tree, teardown deletes it) entirely inside
|
|
1004
|
+
# disposable mkdtemp roots — the operator's real launcher is never inspected or touched. Pins:
|
|
1005
|
+
# fail-closed preflight (launcher and resolved target present, regular, executable, OUTSIDE the
|
|
1006
|
+
# fixture cleanup root), retarget/content-change detection before cleanup, removal BLOCKED when
|
|
1007
|
+
# the launcher references the fixture OR safety cannot be proven OR tracked panes are not gone
|
|
1008
|
+
# (known reference and unproven state each named as itself), exact operator-parity XDG restore
|
|
1009
|
+
# (absent means DELETED, never canonical defaults; RUNTIME_DIR stays fixture by design), the
|
|
1010
|
+
# lifecycle pi/claude cell-branch topology, and both smokes consuming the one shared helper.
|
|
1011
|
+
run_ts scripts/check-mux-launcher-fence.ts
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
check_mux_parent_artifact() {
|
|
1015
|
+
# Deterministic gate for the tracked scrubbed parent-transcript fixture
|
|
1016
|
+
# (scripts/fixtures/mux-parent-transcript.scrubbed.jsonl). The fixture is a version-pinned
|
|
1017
|
+
# SAMPLE OF THE PARENT-SIDE SHAPE — what an entwurf_fresh_call and the sibling's nonce callback
|
|
1018
|
+
# look like in the transcript of the citizen that made the call — so a downstream parser never
|
|
1019
|
+
# has to open a private transcript to learn it. Structure came from a fixture-only real Pi
|
|
1020
|
+
# parent retake and was then scrubbed. Pins: event order (fresh_call toolResult, then the later
|
|
1021
|
+
# callback custom_message), the toolCallId join on the RESULT (measured: pi writes no separate
|
|
1022
|
+
# toolCall row), the launch nonce reappearing verbatim in the callback body, the <sender_info>
|
|
1023
|
+
# envelope field names, and the absence of any operator path / real garden id / real uuid.
|
|
1024
|
+
# It is NOT placement evidence and the gate says so.
|
|
1025
|
+
run_ts scripts/check-mux-parent-artifact.ts
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
check_mux_resume_call() {
|
|
1029
|
+
# Deterministic gate for the S1 resume placement composition (mux-resume-call.ts). Same scope
|
|
1030
|
+
# as check-mux-launch/check-mux-fresh-call: no fake tmux, only what is decidable without one.
|
|
1031
|
+
# The cwd rules are MEASURED tmux 3.6a behaviours, each a way a resume looks successful while
|
|
1032
|
+
# being wrong — a nonexistent `-c` exits 0 and lands the child in $HOME, and `-c` is
|
|
1033
|
+
# FORMAT-EXPANDED so `#{…}` rewrites the path and `#(…)` was observed running a command.
|
|
1034
|
+
# Whitespace measured SAFE, so the refusal set stays at two rules with no escaping layer.
|
|
1035
|
+
# Also pins: `-c` reaches tmux, runtime after `--`, carrier-free argv, no identity in this
|
|
1036
|
+
# module, and the surface seam that keeps the v2 composition from importing mux.
|
|
1037
|
+
run_ts scripts/check-mux-resume-call.ts
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
check_entwurf_v2_visible_resume() {
|
|
1041
|
+
# Deterministic gate for the S1 visible-resume composition (entwurf-v2-visible-resume.ts).
|
|
1042
|
+
# Every seam is injected, so the whole state machine — including the timeout branch — runs
|
|
1043
|
+
# without tmux, a lock file, a socket or a clock. Pins: lock BEFORE liveness, identity under
|
|
1044
|
+
# the lock and before any window (a citizen with no transcript fails loud and opens nothing),
|
|
1045
|
+
# live/indeterminate/address-conflict refused unlaunched, the observation as a BOUNDED WAIT
|
|
1046
|
+
# (measured: the socket answers ~2–4s after launch, so one immediate probe would report a
|
|
1047
|
+
# successful resume as unobserved), exactly one launch on every path, timeout releasing the
|
|
1048
|
+
# lock and leaving the window open, a failed release throwing, and the two receipts staying
|
|
1049
|
+
# separate in both the type and the rendered text.
|
|
1050
|
+
run_ts scripts/check-entwurf-v2-visible-resume.ts
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
check_resume_launch_identity() {
|
|
1054
|
+
# Deterministic gate for resume-launch-identity.ts, the record-authoritative launch-identity
|
|
1055
|
+
# leaf preserved when the visible-first cut deleted spawn-bg and every caller it had. Identity
|
|
1056
|
+
# authority is fail-closed risk, so the preserved leaf does not ship on its header comment:
|
|
1057
|
+
# a temp meta-store fixture drives gardenId → record.transcriptPath → header-id integrity
|
|
1058
|
+
# (a foreign/stale transcript is refused, never resumed), the #52 ADDRESSABLE read (a garden id
|
|
1059
|
+
# that no longer holds its nativeSessionId alone is refused from either side), and cause
|
|
1060
|
+
# fidelity for every impossible resume — including the F7 pin that a recorded-but-deleted
|
|
1061
|
+
# transcript is reported as MISSING rather than as "no recorded model". No spawn, socket, or
|
|
1062
|
+
# timer: the launch this identity would feed is deliberately out of scope.
|
|
1063
|
+
run_ts scripts/check-resume-launch-identity.ts
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
check_mux_placement() {
|
|
1067
|
+
# Deterministic gate for the T0-b placement primitives (mux-placement.ts): the argv shapes,
|
|
1068
|
+
# the anchor precondition, the parse, and the close classification — everything decidable
|
|
1069
|
+
# without tmux. It does NOT simulate tmux; no fake tmux exists in this repo on purpose.
|
|
1070
|
+
# Topology is judged by check-mux-placement-tmux against a real private server.
|
|
1071
|
+
run_ts scripts/check-mux-placement.ts
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
check_mux_placement_tmux() {
|
|
1075
|
+
# REAL tmux acceptance: drives the production placement functions against a private fixture
|
|
1076
|
+
# server (unique -S socket, never the operator's), with TMUX/TMUX_PANE actually INHERITED by
|
|
1077
|
+
# a fixture pane. Proves one session throughout, 1,2 -> 1,2,3 -> 1,2,3,4 -> 1,2, surviving
|
|
1078
|
+
# pane pids and focus, stable @window/%pane handles, the display-message rc=0 trap and its
|
|
1079
|
+
# refusal, and both close paths (closed / already-gone). Skips (97) without tmux or /proc.
|
|
1080
|
+
# Operator-run: kept OUT of pnpm check, and it is not a release-gate MUST at T0.
|
|
1081
|
+
run_ts scripts/check-mux-placement-tmux.ts
|
|
992
1082
|
}
|
|
993
1083
|
|
|
1084
|
+
check_mux_launch() {
|
|
1085
|
+
# Deterministic gate for the T1-a visible launch (mux-launch.ts): the named preconditions
|
|
1086
|
+
# that run BEFORE any window opens, the PATH resolution rule, the `--` argv shape, and the
|
|
1087
|
+
# docs §11 import boundary. It does NOT simulate tmux. The measured trap it exists for — a
|
|
1088
|
+
# failed exec exits 0, prints a handle, and its window is still listed on an immediate
|
|
1089
|
+
# re-read — is judged against a real server by check-mux-launch-tmux.
|
|
1090
|
+
run_ts scripts/check-mux-launch.ts
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
check_mux_fresh_call() {
|
|
1094
|
+
# Transition shim (issue #62): this lane is the vitest pilot, so the gate NAME is preserved
|
|
1095
|
+
# while the contracts live in test/*.test.ts. Same scope as before — the per-backend argv
|
|
1096
|
+
# dialects (both measured to fail the other way round), first-turn framing order, named
|
|
1097
|
+
# refusals, per-surface caller identity — PLUS the runtime axes the retired source-text gate
|
|
1098
|
+
# could not see: real bridge boot → tools/list schema/description, Rust-regex-family pattern
|
|
1099
|
+
# validity on every emitted pattern (the #62 escape), and the schema riding the actual
|
|
1100
|
+
# anthropic-messages request body. No fake tmux: the real-window axis is smoke-mux-fresh-call-live.
|
|
1101
|
+
run_vitest test/mux-fresh-call.test.ts test/fresh-call-surfaces.contract.test.ts test/fresh-call-provider.contract.test.ts
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
smoke_mux_fresh_call_live() {
|
|
1105
|
+
# LIVE acceptance for entwurf_fresh_call — OUT of pnpm check, needs LIVE=1, spends two model
|
|
1106
|
+
# turns. The one axis no deterministic gate reaches: a real window, a real runtime, a real first
|
|
1107
|
+
# turn, and a real nonce callback whose SENDER ENVELOPE carries the new sibling's garden id.
|
|
1108
|
+
# Entwurf-owned write axes (XDG, all four meta roots, v2 locks, cwd) are fixture-bound; Pi also
|
|
1109
|
+
# gets fixture HOME so its control socket is isolated. Runtime-owned auth/config stays real and
|
|
1110
|
+
# native transcripts remain as evidence. Private tmux servers plus entry-set/GID residue checks
|
|
1111
|
+
# prove no fixture citizen lands in the operator's real record or control-socket directories.
|
|
1112
|
+
run_ts scripts/smoke-mux-fresh-call-live.ts
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
smoke_mux_lifecycle_live() {
|
|
1116
|
+
# RELEASE MUST integrated LIVE acceptance for the whole mux lifecycle, through the REAL MCP
|
|
1117
|
+
# surface. Needs LIVE=1; spends model turns on the operator's configured runtimes (two pi
|
|
1118
|
+
# siblings — native provider and recorded-ACP provider — each resumed once, plus one Claude
|
|
1119
|
+
# Code sibling). Enters via tools/call on the shipped bridge launcher and follows one citizen
|
|
1120
|
+
# around: fresh_call launch receipt -> nonce callback SENDER ENVELOPE -> entwurf_v2 control
|
|
1121
|
+
# send landing in the sibling's own transcript -> resume_call REFUSED while live (window count
|
|
1122
|
+
# unchanged) -> stable-handle close proving pane/socket gone with the record preserved ->
|
|
1123
|
+
# dormant delivery refused honestly -> public entwurf_resume_call with its LAUNCH and
|
|
1124
|
+
# OBSERVATION receipts kept apart, same-gid socket alive, no new citizen, no lock residue,
|
|
1125
|
+
# resumed pane_start_path == the RECORD's cwd (separate tmux query, never pane text), and the
|
|
1126
|
+
# transcript byte-identical across the resume itself -> entwurf_v2 recalling the fact from
|
|
1127
|
+
# BEFORE the close, which is what proves the same CONVERSATION returned. Claude Code runs the
|
|
1128
|
+
# callback+mailbox half and its resume is refused as target-not-pi with no window opened and no lock residue.
|
|
1129
|
+
# Fixture-fenced writes (XDG, four meta roots, v2 lock dir, control socket via fixture HOME);
|
|
1130
|
+
# the runtime auth roots stay REAL and sibling transcripts remain in the real pi agent dir as
|
|
1131
|
+
# evidence. Private tmux server per cell, bounded teardown, operator real-root entry sets
|
|
1132
|
+
# proven unchanged.
|
|
1133
|
+
run_ts scripts/smoke-mux-lifecycle-live.ts
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
check_mux_launch_tmux() {
|
|
1137
|
+
# REAL tmux acceptance for T1-a: drives production launchPi against a private fixture server
|
|
1138
|
+
# (unique -S socket, never the operator's) with TMUX/TMUX_PANE actually INHERITED. Proves the
|
|
1139
|
+
# window lands at {end} of the caller's own session, the pane process IS the runtime (no
|
|
1140
|
+
# shell wrapper), focus and the original panes survive, a precondition refusal opens NO
|
|
1141
|
+
# window, and the failed-exec trap is real. The runtime is a fixture stand-in, never the
|
|
1142
|
+
# operator's pi. Skips (97) without tmux or /proc. Operator-run: kept OUT of pnpm check.
|
|
1143
|
+
run_ts scripts/check-mux-launch-tmux.ts
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
|
|
994
1147
|
smoke_acp_socket_citizen_live() {
|
|
995
1148
|
# S1 acceptance smoke (ACP plugin on v2) — OUT of pnpm check, needs LIVE=1.
|
|
996
1149
|
# Spawns a REAL `pi --entwurf-control` resident on an ACP model
|
|
@@ -1051,6 +1204,18 @@ smoke_acp_memory_containment_live() {
|
|
|
1051
1204
|
run_ts scripts/smoke-acp-memory-containment-live.ts
|
|
1052
1205
|
}
|
|
1053
1206
|
|
|
1207
|
+
smoke_acp_long_turn_live() {
|
|
1208
|
+
# 0.13.1 LIVE acceptance for the prompt-lifecycle contract — OUT of pnpm check,
|
|
1209
|
+
# needs LIVE=1. Drives ONE real pi provider turn whose tool work (default
|
|
1210
|
+
# 3 x 240s foreground wait) deliberately outlasts the RETIRED 600s prompt cutoff, and
|
|
1211
|
+
# requires it to finish as ONE turn: the nonce arrives, elapsed > 600000ms, the
|
|
1212
|
+
# persisted transcript shows exactly ONE cold ACP bootstrap (no replay), and no
|
|
1213
|
+
# retry/timeout is reported anywhere. Takes >12 minutes by construction.
|
|
1214
|
+
# Overrides: ENTWURF_ACP_LONG_TURN_{MODEL,SLEEP_SECONDS,ROUNDS,HORIZON_MS}.
|
|
1215
|
+
# LIVE=1 ./run.sh smoke-acp-long-turn-live
|
|
1216
|
+
run_ts scripts/smoke-acp-long-turn-live.ts
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1054
1219
|
smoke_acp_provider_live() {
|
|
1055
1220
|
# S2c acceptance smoke (ACP plugin on v2) — OUT of pnpm check, needs LIVE=1.
|
|
1056
1221
|
# Drives the REAL pi PROVIDER path end to end: a real `pi` loads this
|
|
@@ -1181,16 +1346,16 @@ smoke_acp_rgg_live() {
|
|
|
1181
1346
|
|
|
1182
1347
|
smoke_acp_cortex_live() {
|
|
1183
1348
|
# On-demand LIVE smoke for the Cortex (Snowflake Cortex Code) ACP backend — the
|
|
1184
|
-
# first NON-claude adapter on the rail (docs/acp-backend-rail.md
|
|
1349
|
+
# first NON-claude adapter on the rail (docs/acp-backend-rail.md, Cortex audit). OUT of
|
|
1185
1350
|
# `pnpm check` AND OUTSIDE the claude-only aggregate LIVE floor (capability
|
|
1186
1351
|
# dignity, invariant #7): a host with no cortex install / no Snowflake auth must
|
|
1187
1352
|
# not redden a release for a backend it does not run, so this is deliberately
|
|
1188
1353
|
# absent from release-gate's 11-smoke ACP acceptance floor. That is a WIRING
|
|
1189
1354
|
# decision, not a lower evidence bar — a cut that SHIPS cortex still owes a
|
|
1190
1355
|
# deliberate run of this smoke, and the aggregate gate's silence is not a pass
|
|
1191
|
-
# (rail
|
|
1356
|
+
# (ACP rail Cortex verification boundary). Drives one real
|
|
1192
1357
|
# cortex ACP turn through the entwurf provider path (outbound entwurf_v2 +
|
|
1193
|
-
# dual-HOME overlay facts + process-group reclaim — CP2
|
|
1358
|
+
# dual-HOME overlay facts + process-group reclaim — CP2).
|
|
1194
1359
|
# HONEST-SKIP (exit 0) when LIVE!=1 OR `cortex` is not on PATH OR no
|
|
1195
1360
|
# connection is pinned — the live turn needs `cortex` installed with the
|
|
1196
1361
|
# operator's own web-login auth already present (there is no `cortex auth`
|
|
@@ -1202,13 +1367,14 @@ smoke_acp_cortex_live() {
|
|
|
1202
1367
|
# operator settings.json where a default would live. PR #40 called this
|
|
1203
1368
|
# `smoke-cortex`; the canonical family name is smoke-acp-cortex-live.
|
|
1204
1369
|
# LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live
|
|
1370
|
+
entwurf_require_step_outcome
|
|
1205
1371
|
if [ "${LIVE:-}" != "1" ]; then
|
|
1206
|
-
echo "[smoke-acp-cortex-live
|
|
1207
|
-
return
|
|
1372
|
+
echo "[entwurf:skip] smoke-acp-cortex-live — set LIVE=1 (+ ENTWURF_ACP_CORTEX_CONNECTION) to run."
|
|
1373
|
+
return "$ENTWURF_STEP_SKIP_EXIT"
|
|
1208
1374
|
fi
|
|
1209
1375
|
if ! command -v cortex >/dev/null 2>&1; then
|
|
1210
|
-
echo "[smoke-acp-cortex-live
|
|
1211
|
-
return
|
|
1376
|
+
echo "[entwurf:skip] smoke-acp-cortex-live — cortex not on PATH (install Snowflake Cortex Code and complete its own login flow)."
|
|
1377
|
+
return "$ENTWURF_STEP_SKIP_EXIT"
|
|
1212
1378
|
fi
|
|
1213
1379
|
run_ts scripts/smoke-acp-cortex-live.ts
|
|
1214
1380
|
}
|
|
@@ -1225,35 +1391,14 @@ smoke_entwurf_v2_matrix_live() {
|
|
|
1225
1391
|
# stay deterministic. Honest skip when LIVE!=1 so the release-gate is runnable unattended.
|
|
1226
1392
|
# Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4).
|
|
1227
1393
|
# LIVE=1 ./run.sh smoke-entwurf-v2-matrix-live
|
|
1394
|
+
entwurf_require_step_outcome
|
|
1228
1395
|
if [ "${LIVE:-}" != "1" ]; then
|
|
1229
|
-
echo "[smoke-entwurf-v2-matrix-live
|
|
1230
|
-
return
|
|
1396
|
+
echo "[entwurf:skip] smoke-entwurf-v2-matrix-live — set LIVE=1 to run (spawns a real pi --entwurf-control + opens a real socket)."
|
|
1397
|
+
return "$ENTWURF_STEP_SKIP_EXIT"
|
|
1231
1398
|
fi
|
|
1232
1399
|
run_ts scripts/smoke-entwurf-v2-matrix-live.ts
|
|
1233
1400
|
}
|
|
1234
1401
|
|
|
1235
|
-
smoke_entwurf_v2_spawn_resume_live() {
|
|
1236
|
-
# The 0.11.0 (A) acceptance gate — kept OUT of `pnpm check`. Unlike matrix-live (a
|
|
1237
|
-
# transport/lock sentinel, model-in-loop OUT) and spawn-live (OS-substrate watcher, no real
|
|
1238
|
-
# pi), this drives the FULL production loop: mint a backend=pi meta identity → seed a REAL
|
|
1239
|
-
# dormant pi session (one-shot `pi --mode json -p --no-extensions` into the REAL
|
|
1240
|
-
# ~/.pi/agent/sessions) → runEntwurfV2(intent=owned-outcome) routes the dormant in-domain pi
|
|
1241
|
-
# citizen to spawn-bg resume → a REAL detached `pi --entwurf-control` child stands its socket
|
|
1242
|
-
# up, resumes, and DOES a model turn. Asserts: executed/spawn-bg/socket-alive/released, lock
|
|
1243
|
-
# released exactly once + no lock file, resident pid alive + socket connectable, and the
|
|
1244
|
-
# resume USER + assistant OK nonces appended to the session JSONL (real work, not just
|
|
1245
|
-
# "process up"). This is the evidence v1 deprecation (0.12) is predicated on. Model-in-loop is
|
|
1246
|
-
# IN. Honest skip when LIVE!=1 (skip = CI safety, NOT an acceptance PASS).
|
|
1247
|
-
# Model: ENTWURF_LIVE_TARGET=<provider>/<model> (default openai-codex/gpt-5.4);
|
|
1248
|
-
# ENTWURF_SPAWN_RESUME_ASSISTANT_TIMEOUT_MS (default 180000).
|
|
1249
|
-
# LIVE=1 ./run.sh smoke-entwurf-v2-spawn-resume-live
|
|
1250
|
-
if [ "${LIVE:-}" != "1" ]; then
|
|
1251
|
-
echo "[smoke-entwurf-v2-spawn-resume-live] skipped — set LIVE=1 to run (spawns a real pi resume child + opens a real socket)."
|
|
1252
|
-
return 0
|
|
1253
|
-
fi
|
|
1254
|
-
run_ts scripts/smoke-entwurf-v2-spawn-resume-live.ts
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
1402
|
check_entwurf_facts() {
|
|
1258
1403
|
# Deterministic gate for 0.11 Stage 0 step 4 (fact-provider slice 1): the PURE
|
|
1259
1404
|
# fact core. Locks the PeerFact shape + R1/R3b liveness invariant before any IO
|
|
@@ -1299,6 +1444,17 @@ check_meta_listing() {
|
|
|
1299
1444
|
run_ts scripts/check-meta-listing.ts
|
|
1300
1445
|
}
|
|
1301
1446
|
|
|
1447
|
+
check_meta_facts() {
|
|
1448
|
+
# Deterministic gate for the #65 owner-normalized store projection. Drives the
|
|
1449
|
+
# REAL scripts/meta-facts.ts as a subprocess against sandboxed fixture stores:
|
|
1450
|
+
# full verbatim v3 records in the join, parse-before-uniqueness (a schema-invalid
|
|
1451
|
+
# rival never quarantines a healthy citizen), no-winner duplicates, drift /
|
|
1452
|
+
# symlink / invalid-UTF-8 defects in-band with exit 0, byte-deterministic JSON,
|
|
1453
|
+
# missing store = readable empty store, unreadable store = exit 3 with NO JSON,
|
|
1454
|
+
# usage = exit 2, plus dispatch + compiled-twin emit reachability.
|
|
1455
|
+
run_ts scripts/check-meta-facts.ts
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1302
1458
|
check_entwurf_fact_provider() {
|
|
1303
1459
|
# Deterministic gate for 0.11 Stage 0 step 4 (fact-provider slice 4b): the
|
|
1304
1460
|
# ASSEMBLY layer listEntwurfFacts. listAllMetaIdentities → scanSocketProbes →
|
|
@@ -1416,7 +1572,7 @@ check_package_source_routing() {
|
|
|
1416
1572
|
# substrate entwurf used to stand on. C2 removed every entwurf use of that
|
|
1417
1573
|
# substrate (the record mints the address; pi owns id and name), so the smoke's
|
|
1418
1574
|
# subject no longer exists. The resident identity axis is covered by
|
|
1419
|
-
# smoke-pi-attach (deterministic, in pnpm check) + smoke-resident-garden-guard (LIVE).
|
|
1575
|
+
# smoke-pi-attach (deterministic, in pnpm run check:full) + smoke-resident-garden-guard (LIVE).
|
|
1420
1576
|
|
|
1421
1577
|
|
|
1422
1578
|
|
|
@@ -1425,7 +1581,7 @@ check_dep_versions() {
|
|
|
1425
1581
|
# docs. Concretely the kind of skew that produced commit 21de0f9's "0.11.1
|
|
1426
1582
|
# leftover" review comment: package.json bumped to 0.12.0 while README
|
|
1427
1583
|
# and run.sh's setup gate still claimed 0.11.1. Static check, no
|
|
1428
|
-
# subprocess — fast enough to run inside `pnpm check
|
|
1584
|
+
# subprocess — fast enough to run inside `pnpm check`.
|
|
1429
1585
|
# The doc half of that promise was prose only until 0.12.8 — see the
|
|
1430
1586
|
# BASELINE DOCS block below, which finally makes this comment true.
|
|
1431
1587
|
(cd "$REPO_DIR" && node --input-type=module <<'EOF'
|
|
@@ -1472,12 +1628,13 @@ assert.equal(peerTui, piAi,
|
|
|
1472
1628
|
// floor tracks the devDep pin so a consumer can't install against a pi lacking
|
|
1473
1629
|
// the public trust exports the bridge imports at the pinned minor, AND an upper
|
|
1474
1630
|
// bound at the next minor stops a fresh install from silently pulling a future
|
|
1475
|
-
// pi (past the declared ceiling — 0.
|
|
1631
|
+
// pi (past the declared ceiling — 0.85+ at the current 0.84.1 pin) whose
|
|
1476
1632
|
// internal export surface has drifted from the one we typecheck against.
|
|
1477
1633
|
// pi moves its public surface every minor (the 0.79→0.80 getModels→provider-
|
|
1478
1634
|
// factory churn is exactly this), so an open `>=` floor is exactly how the next
|
|
1479
|
-
// installer re-acquires the drift.
|
|
1480
|
-
//
|
|
1635
|
+
// installer re-acquires the drift. The floor is also the HARD MINIMUM a consumer
|
|
1636
|
+
// install resolves: at `>=0.84.1` an existing 0.83.x host is upgraded, not kept.
|
|
1637
|
+
// Expected shape: `>=<devDep> <0.<minor+1>` (e.g. `>=0.84.1 <0.85`).
|
|
1481
1638
|
const [piMaj, piMin] = piAi.split('.').map(Number);
|
|
1482
1639
|
assert.equal(piMaj, 0,
|
|
1483
1640
|
`pi pin major must stay 0 for the next-minor ceiling rule (got ${piAi}); revisit check-dep-versions when pi reaches 1.x`);
|
|
@@ -1923,9 +2080,13 @@ check_pi_import_surface() {
|
|
|
1923
2080
|
# pattern catches static `from`, dynamic `import()`, `require()`,
|
|
1924
2081
|
# `export … from`, side-effect `import "…"`, and whitespace variants alike.
|
|
1925
2082
|
# Root import `@earendil-works/pi-coding-agent` (no trailing slash) is allowed.
|
|
1926
|
-
# Scans
|
|
1927
|
-
# file list
|
|
1928
|
-
#
|
|
2083
|
+
# Scans the whole git WORK SURFACE (tracked + untracked-non-ignored), not a
|
|
2084
|
+
# hardcoded or index-only file list. The index-only corpus was the #62 measured
|
|
2085
|
+
# escape: a brand-new test file carrying a forbidden subpath was invisible to the
|
|
2086
|
+
# floor until it happened to be staged, so the gate went green on a candidate CI
|
|
2087
|
+
# then rejected. The denominator is re-proved every run against an EXTERNAL
|
|
2088
|
+
# throwaway git repo (never this worktree — the frozen candidate must not be
|
|
2089
|
+
# written to) holding one tracked-clean and one untracked-forbidden fixture.
|
|
1929
2090
|
#
|
|
1930
2091
|
# pi 0.80 EXCEPTION — exactly ONE allowlisted subpath:
|
|
1931
2092
|
# @earendil-works/pi-ai/compat
|
|
@@ -1938,24 +2099,57 @@ check_pi_import_surface() {
|
|
|
1938
2099
|
# the remainder, producing the unresolvable `…/dist/compat.js/providers/
|
|
1939
2100
|
# anthropic` (verified live: extension load crash — invisible to static
|
|
1940
2101
|
# typecheck, which resolves against node_modules `exports`). So `/compat` is the
|
|
1941
|
-
# sanctioned extension entrypoint
|
|
1942
|
-
#
|
|
2102
|
+
# sanctioned extension entrypoint, and the ONLY allowlisted exception. It has TWO
|
|
2103
|
+
# consumers: lib/acp/models.ts (`getModels`, the old global model-catalog API) and
|
|
2104
|
+
# test/fresh-call-provider.contract.test.ts (`stream`, the loopback provider-conversion
|
|
2105
|
+
# contract — pi-ai 0.84's package ROOT exports no stream/streamAnthropic at all, and
|
|
2106
|
+
# root `lazyStream(model, setup)` only defers the same private import into `setup`,
|
|
2107
|
+
# so /compat is the only surface that can observe the real anthropic request body). The
|
|
1943
2108
|
# allow-pattern is closing-quote-anchored (`@earendil-works/pi-ai/compat["'\`]`)
|
|
1944
2109
|
# so it permits ONLY that exact specifier: `/compat-foo`, `/oauth`, every
|
|
1945
2110
|
# `/providers/*`, and any deeper path stay FORBIDDEN (we use only `/compat`).
|
|
1946
2111
|
# Do NOT widen this to a `providers/*` subpath — it typechecks but CANNOT
|
|
1947
2112
|
# resolve under the extension loader.
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
2113
|
+
# ONE corpus, TWO callers. The real scan and the denominator fixture must run the
|
|
2114
|
+
# SAME two lines, or the fixture would prove a command the gate does not use.
|
|
2115
|
+
pi_import_work_surface() {
|
|
2116
|
+
git ls-files -z --cached --others --exclude-standard -- '*.ts' '*.js' '*.mjs' '*.cjs'
|
|
2117
|
+
}
|
|
2118
|
+
pi_import_scan() {
|
|
2119
|
+
pi_import_work_surface \
|
|
2120
|
+
| xargs -0r grep -HnE "[\"'\`]@earendil-works/pi-(ai|coding-agent|tui)/" 2>/dev/null \
|
|
2121
|
+
| grep -vE "[\"'\`]@earendil-works/pi-ai/compat[\"'\`]" 2>/dev/null || true
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
local probe_dir probe_hits hits
|
|
2125
|
+
probe_dir=$(mktemp -d "${TMPDIR:-/tmp}/entwurf-pi-import-denominator.XXXXXX")
|
|
2126
|
+
(
|
|
2127
|
+
cd "$probe_dir" || exit 1
|
|
2128
|
+
git -c init.defaultBranch=main init -q .
|
|
2129
|
+
printf '%s\n' 'import { getModels } from "@earendil-works/pi-ai/compat";' > tracked-allowed.ts
|
|
2130
|
+
git add tracked-allowed.ts
|
|
2131
|
+
printf '%s\n' 'import "@earendil-works/pi-ai/private-probe";' > untracked-forbidden.ts
|
|
2132
|
+
) || { fail "[check-pi-import-surface] could not build the denominator fixture in $probe_dir"; rm -rf "$probe_dir"; return 1; }
|
|
2133
|
+
probe_hits=$(cd "$probe_dir" && pi_import_scan)
|
|
2134
|
+
rm -rf "$probe_dir"
|
|
2135
|
+
# ONE assertion, ONE claim token: the manifest contract requires the signature to
|
|
2136
|
+
# occur exactly once in this file, so both fixture conditions are folded into a
|
|
2137
|
+
# single failure whose message still names which half broke.
|
|
2138
|
+
local saw_untracked_forbidden="no" saw_tracked_allowed="no"
|
|
2139
|
+
grep -qF 'untracked-forbidden.ts' <<<"$probe_hits" && saw_untracked_forbidden="yes"
|
|
2140
|
+
grep -qF 'tracked-allowed.ts' <<<"$probe_hits" && saw_tracked_allowed="yes"
|
|
2141
|
+
if [ "$saw_untracked_forbidden" != "yes" ] || [ "$saw_tracked_allowed" != "no" ]; then
|
|
2142
|
+
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)"
|
|
2143
|
+
return 1
|
|
2144
|
+
fi
|
|
2145
|
+
|
|
2146
|
+
hits=$(cd "$REPO_DIR" && pi_import_scan)
|
|
1953
2147
|
if [ -n "$hits" ]; then
|
|
1954
2148
|
echo "[check-pi-import-surface] FAIL: pi private subpath reference(s) — import @earendil-works/pi-* by the package ROOT only:"
|
|
1955
2149
|
echo "$hits"
|
|
1956
2150
|
exit 1
|
|
1957
2151
|
fi
|
|
1958
|
-
ok "[check-pi-import-surface] pi references are root-only
|
|
2152
|
+
ok "[check-pi-import-surface] pi references are root/compat-only across tracked + untracked-non-ignored ts/js; the untracked denominator is proved on an external fixture repo"
|
|
1959
2153
|
}
|
|
1960
2154
|
|
|
1961
2155
|
check_env_namespace() {
|
|
@@ -2261,22 +2455,21 @@ check_acp_provider_surface() {
|
|
|
2261
2455
|
}
|
|
2262
2456
|
|
|
2263
2457
|
check_acp_sdk_surface() {
|
|
2264
|
-
#
|
|
2265
|
-
# ACP
|
|
2266
|
-
#
|
|
2267
|
-
# peer
|
|
2268
|
-
#
|
|
2269
|
-
#
|
|
2270
|
-
# import / API-client use (the anthropic dep is a peer-pin ONLY).
|
|
2458
|
+
# Transition shim (issue #62 Phase 3): the gate NAME is preserved while the S2a
|
|
2459
|
+
# ACP SDK dependency-surface contracts live in the vitest lane. Same layers as
|
|
2460
|
+
# the retired scripts gate — exact dep pins, pnpm-lock peer-resolution lock,
|
|
2461
|
+
# runtime resolver probes (anthropic peer / shared wire SDK / MCP peer edge),
|
|
2462
|
+
# wire-SDK value-export surface, and the forbidden anthropic-import sweep. The
|
|
2463
|
+
# per-layer mapping table is in the test file's header.
|
|
2271
2464
|
section "ACP SDK surface (S2a dep pin + peer-resolution + no-client-use)"
|
|
2272
|
-
|
|
2465
|
+
run_vitest test/acp-sdk-surface.contract.test.ts
|
|
2273
2466
|
}
|
|
2274
2467
|
|
|
2275
2468
|
check_acp_overlay() {
|
|
2276
2469
|
# Deterministic gate for the S2b Claude config overlay materializer. Drives
|
|
2277
2470
|
# ensureClaudeConfigOverlay against injected temp realDir/overlayDir (no
|
|
2278
2471
|
# operator ~/.claude touched) and asserts: settings.json hooks:{} +
|
|
2279
|
-
# defaultMode
|
|
2472
|
+
# defaultMode bypassPermissions (unattended turns never prompt) + autoMemory off; whitelisted entries symlinked;
|
|
2280
2473
|
# projects/sessions overlay-private real dirs (NOT symlinks); operator
|
|
2281
2474
|
# personal config (CLAUDE.md/settings.local.json/plugins/agents) never leaks;
|
|
2282
2475
|
# stale symlinks cleaned; binary-owned files preserved; CLAUDE_CONFIG_DIR
|
|
@@ -2308,6 +2501,53 @@ check_acp_event_mapper() {
|
|
|
2308
2501
|
run_ts scripts/check-acp-event-mapper.ts
|
|
2309
2502
|
}
|
|
2310
2503
|
|
|
2504
|
+
check_acp_stop_reason() {
|
|
2505
|
+
# Deterministic gate for the ACP stop-reason contract. Drives every member of
|
|
2506
|
+
# the closed ACP terminal set (end_turn / max_tokens / max_turn_requests /
|
|
2507
|
+
# refusal / cancelled), plus an unrecognized reason and an ABSENT one, end to
|
|
2508
|
+
# end through streamAcpTurn against a fake connection — asserting the event
|
|
2509
|
+
# kind, the event reason, and the final message's stopReason / rawStopReason /
|
|
2510
|
+
# errorMessage together. Forbids the collapse-to-"stop" default that reported
|
|
2511
|
+
# refusals and exhausted turn budgets as finished answers. Also pins the
|
|
2512
|
+
# "pending" seed on the freshly created stream state.
|
|
2513
|
+
section "ACP stop reason (terminal set → pi verdict)"
|
|
2514
|
+
run_ts scripts/check-acp-stop-reason.ts
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
check_acp_prompt_lifecycle() {
|
|
2518
|
+
# Deterministic gate for the ACP prompt LIFECYCLE contract. A prompt has no
|
|
2519
|
+
# wall-clock cutoff: it ends when it resolves, when the operator aborts, or
|
|
2520
|
+
# when the child dies / its stdio ends. Drives streamAcpTurn against a fake
|
|
2521
|
+
# ACP child + connection for eight cells — a quiet in-flight turn is not
|
|
2522
|
+
# sealed and later completes on its ORIGINAL prompt; an abort sends ACP
|
|
2523
|
+
# session/cancel first (cancelled→aborted, no signal to a cooperating child);
|
|
2524
|
+
# a wedged agent is torn down after the bounded grace and still returns; a
|
|
2525
|
+
# mid-prompt child death reports exit status + stderr tail on BOTH the new and
|
|
2526
|
+
# the reuse path; a death BETWEEN turns is announced once by the next turn
|
|
2527
|
+
# while a teardown WE performed stays silent — plus pi's own
|
|
2528
|
+
# isRetryableAssistantError as
|
|
2529
|
+
# the oracle that our prompt-phase failure text is not a transient
|
|
2530
|
+
# (cold-replay) error.
|
|
2531
|
+
section "ACP prompt lifecycle (no wall clock; abort/child-death endings)"
|
|
2532
|
+
run_ts scripts/check-acp-prompt-lifecycle.ts
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
check_acp_stream_hooks() {
|
|
2536
|
+
# Deterministic gate for the pi 0.84 streamSimple hook contract on the ACP rail
|
|
2537
|
+
# (#63; upstream pi-mono #7372 → doc-only #7576). before_provider_request
|
|
2538
|
+
# (onPayload) receives the EXACT ACP session/prompt wire params on new AND
|
|
2539
|
+
# reuse turns and its replacement becomes the wire — fail-closed: a non-null/
|
|
2540
|
+
# non-array-object violation, a changed bootstrapped sessionId, or an emptied
|
|
2541
|
+
# prompt array refuses the turn loudly with zero sends, a hook rejection fails
|
|
2542
|
+
# loud, and an abort raised while the hook is awaited wins before the wire
|
|
2543
|
+
# write on BOTH the new and the reuse path. after_provider_response (onResponse)
|
|
2544
|
+
# is an explicit local non-HTTP exemption: ACP has no truthful {status,
|
|
2545
|
+
# headers} and its terminal result arrives after the body was consumed, so the
|
|
2546
|
+
# gate pins ZERO invocations across success/error/abort turns.
|
|
2547
|
+
section "ACP streamSimple hooks (truthful onPayload; onResponse exemption)"
|
|
2548
|
+
run_ts scripts/check-acp-stream-hooks.ts
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2311
2551
|
check_acp_prompt_builder() {
|
|
2312
2552
|
# Deterministic gate for the S2d bootstrapPath-scoped ACP prompt builder (핀4).
|
|
2313
2553
|
# Proves prompt SCOPE follows bootstrapPath: new=full transcript (history
|
|
@@ -2383,11 +2623,11 @@ check_acp_carrier_augment() {
|
|
|
2383
2623
|
check_acp_cortex() {
|
|
2384
2624
|
# Deterministic gate for the Cortex (Snowflake Cortex Code) ACP backend — the
|
|
2385
2625
|
# first non-claude adapter on the rail, landed 0.13.0 on the CP0-measured
|
|
2386
|
-
# contract (docs/acp-backend-rail.md
|
|
2626
|
+
# contract (docs/acp-backend-rail.md, Cortex audit D1–D10). The cortex source is one
|
|
2387
2627
|
# `cortexAdapter` object (backend-adapter.ts) + its curated surface (models.ts)
|
|
2388
2628
|
# + the dual-HOME overlay (overlay.ts); the 결합 규칙 requires the gate to land
|
|
2389
|
-
# WITH it,
|
|
2390
|
-
# deterministic axis lives here. Locks (each
|
|
2629
|
+
# WITH it, extending the check-acp-* family, so cortex's whole
|
|
2630
|
+
# deterministic axis lives here. Locks (each Cortex-audit D-pinned): the GLG-decided
|
|
2391
2631
|
# 4-row curation rides real registry bases and the `cortex-` prefix routes to
|
|
2392
2632
|
# cortexAdapter; launch is `cortex acp serve` with NO -m — the model is
|
|
2393
2633
|
# enforced per turn via session/set_config_option with the native id (E);
|
|
@@ -2505,6 +2745,9 @@ check_pack() {
|
|
|
2505
2745
|
# previous-generation store; without this twin the prescription every
|
|
2506
2746
|
# v3-only rejection names would be dead exactly where it matters.
|
|
2507
2747
|
"mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js"
|
|
2748
|
+
# #65 — the owner-normalized store projection consumers call INSTEAD of
|
|
2749
|
+
# parsing the store; installed hosts are exactly where those consumers live.
|
|
2750
|
+
"mcp/entwurf-bridge/dist/scripts/meta-facts.js"
|
|
2508
2751
|
# 0.12.5 — the node_modules-safe plugin hook + its lib. install-meta-bridge copies
|
|
2509
2752
|
# these compiled JS into the assembled plugin when installed (raw .ts can't
|
|
2510
2753
|
# strip-types under node_modules). meta-session.js is shared with the store-doctor
|
|
@@ -2551,7 +2794,7 @@ check_pack() {
|
|
|
2551
2794
|
'\.agent-(reports|shell)/'
|
|
2552
2795
|
'pi/meta-bridge/\.assembled/'
|
|
2553
2796
|
# Python bytecode residue — `scripts/` ships whole via the files allowlist,
|
|
2554
|
-
# which BYPASSES .gitignore/.npmignore for its contents, so a `pnpm check`
|
|
2797
|
+
# which BYPASSES .gitignore/.npmignore for its contents, so a `pnpm run check:full`
|
|
2555
2798
|
# run's generated scripts/__pycache__/*.pyc rode into the 0.12.6 tarball. The
|
|
2556
2799
|
# files-array `!**/__pycache__` / `!**/*.pyc` negations exclude it; this is the
|
|
2557
2800
|
# tripwire that fails loud if that negation is ever dropped (결합 규칙).
|
|
@@ -2639,7 +2882,7 @@ _check_pack_install_impl() {
|
|
|
2639
2882
|
|
|
2640
2883
|
echo "[check-pack-install] npm pack -> ${tgz_name}"
|
|
2641
2884
|
# with-dist-lock: same whole-pack serialization as check-pack — this heavy gate
|
|
2642
|
-
# and a background check-pack (via `pnpm check`) both pack, and unserialized they
|
|
2885
|
+
# and a background check-pack (via `pnpm run check:full`) both pack, and unserialized they
|
|
2643
2886
|
# race the shared dist dir. The stale-dist sentinel planted just above still
|
|
2644
2887
|
# proves build-bridge's own `rm -rf dist` clean step under the lock.
|
|
2645
2888
|
(cd "$REPO_DIR" && bash scripts/with-dist-lock.sh npm pack --dry-run=false --pack-destination "$pack_tmp" 2>&1 | tail -1) || {
|
|
@@ -2671,8 +2914,8 @@ _check_pack_install_impl() {
|
|
|
2671
2914
|
# Required tarball contents. The old 0.11.0 ACP root files (index.ts,
|
|
2672
2915
|
# acp-bridge.ts, event-mapper.ts, engraving.ts, pi-context-augment.ts,
|
|
2673
2916
|
# pi-extensions/entwurf.ts) were removed on v2-only and are GONE — keeping them
|
|
2674
|
-
# here made this heavy gate silently RED (publish-blocking) while
|
|
2675
|
-
# (
|
|
2917
|
+
# here made this heavy gate silently RED (publish-blocking) while the deterministic floor
|
|
2918
|
+
# (check:full runs only check-pack, not check-pack-install) stayed green. The ACP
|
|
2676
2919
|
# plugin re-enters on v2 as the provider entry + lib/acp/* modules below.
|
|
2677
2920
|
local tar_required=(
|
|
2678
2921
|
"package.json" "README.md" "LICENSE" "CHANGELOG.md"
|
|
@@ -2700,6 +2943,8 @@ _check_pack_install_impl() {
|
|
|
2700
2943
|
# The generation verb (see check-pack). The installed-command regression below
|
|
2701
2944
|
# opens a fresh generation on a 0-record sandbox through the real bin.
|
|
2702
2945
|
"mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js"
|
|
2946
|
+
# #65 — the owner-normalized store projection (see check-pack).
|
|
2947
|
+
"mcp/entwurf-bridge/dist/scripts/meta-facts.js"
|
|
2703
2948
|
# 0.12.5 — node_modules-safe plugin hook + lib (see check-pack). The installed
|
|
2704
2949
|
# hook regression below runs exactly this compiled JS from under node_modules.
|
|
2705
2950
|
"mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js"
|
|
@@ -2776,21 +3021,31 @@ _check_pack_install_impl() {
|
|
|
2776
3021
|
printf '%s\n' '{ "name": "entwurf-install-smoke", "version": "0.0.0", "private": true }' > "$tmp/package.json"
|
|
2777
3022
|
|
|
2778
3023
|
# pi-agent-core is pinned even though we never import it: pi-coding-agent depends
|
|
2779
|
-
# on it by CARET (`^0.
|
|
3024
|
+
# on it by CARET (`^0.84.1`), so with no lockfile in this fresh temp project it
|
|
2780
3025
|
# floats to whatever pi published last — and that newer core then drags a NESTED
|
|
2781
3026
|
# pi-ai of its own. Measured 2026-07-21: pinning only the three we import left
|
|
2782
3027
|
# pi-agent-core@0.80.10 + pi-ai@0.80.10 in the tree while the gate still announced
|
|
2783
3028
|
# "pinned pi 0.80.7". The gate would then be verifying an UNVERIFIED runtime — the
|
|
2784
3029
|
# exact class this cut exists to close. Pin every @earendil-works package that
|
|
2785
3030
|
# constitutes the pi runtime, not just the ones whose types we touch.
|
|
2786
|
-
|
|
3031
|
+
#
|
|
3032
|
+
# The constellation is re-measured at each pi bump, never carried forward. At
|
|
3033
|
+
# 0.84.0 it GREW: pi-coding-agent's @earendil-works caret set went from
|
|
3034
|
+
# {pi-agent-core, pi-ai, pi-tui} at 0.83.0 to {pi-agent-core, pi-ai, pi-client,
|
|
3035
|
+
# pi-protocol, pi-tui}, so pi-client and pi-protocol are pinned here for the
|
|
3036
|
+
# first time. Unpinned they would float exactly like pi-agent-core did in the
|
|
3037
|
+
# 2026-07-21 incident above. (pi-telemetry arrives transitively, not as a
|
|
3038
|
+
# direct caret; the leak assertion below covers it and every other pi package.)
|
|
3039
|
+
echo "[check-pack-install] pnpm add into $tmp (with 0.84.x peers + typebox)"
|
|
2787
3040
|
local install_log
|
|
2788
3041
|
install_log=$(cd "$tmp" && pnpm add \
|
|
2789
3042
|
"$tgz_path" \
|
|
2790
|
-
"@earendil-works/pi-ai@0.
|
|
2791
|
-
"@earendil-works/pi-coding-agent@0.
|
|
2792
|
-
"@earendil-works/pi-tui@0.
|
|
2793
|
-
"@earendil-works/pi-agent-core@0.
|
|
3043
|
+
"@earendil-works/pi-ai@0.84.1" \
|
|
3044
|
+
"@earendil-works/pi-coding-agent@0.84.1" \
|
|
3045
|
+
"@earendil-works/pi-tui@0.84.1" \
|
|
3046
|
+
"@earendil-works/pi-agent-core@0.84.1" \
|
|
3047
|
+
"@earendil-works/pi-client@0.84.1" \
|
|
3048
|
+
"@earendil-works/pi-protocol@0.84.1" \
|
|
2794
3049
|
"typebox@latest" \
|
|
2795
3050
|
--ignore-workspace --ignore-scripts 2>&1) || {
|
|
2796
3051
|
fail "[check-pack-install] pnpm add failed:"
|
|
@@ -2800,17 +3055,17 @@ _check_pack_install_impl() {
|
|
|
2800
3055
|
|
|
2801
3056
|
# A pin is a wish until the resolved tree is read back. Assert it: EVERY
|
|
2802
3057
|
# @earendil-works pi package present — direct or transitive, top level or nested —
|
|
2803
|
-
# must be the pinned 0.
|
|
3058
|
+
# must be the pinned 0.84.1. Anything else means an unpinned caret floated and the
|
|
2804
3059
|
# rest of this gate would be exercising a runtime nobody verified, while still
|
|
2805
|
-
# printing "pinned pi 0.
|
|
3060
|
+
# printing "pinned pi 0.84.1". Fail loud instead of proving the wrong floor.
|
|
2806
3061
|
local leaked_pi
|
|
2807
|
-
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | grep '^@earendil-works+pi-' | grep -v '@0\.
|
|
3062
|
+
leaked_pi=$(ls "$tmp/node_modules/.pnpm" 2>/dev/null | grep '^@earendil-works+pi-' | grep -v '@0\.84\.1' || true)
|
|
2808
3063
|
if [ -n "$leaked_pi" ]; then
|
|
2809
|
-
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 0.
|
|
3064
|
+
fail "[check-pack-install] UNVERIFIED pi runtime resolved into the install tree (expected only 0.84.1):"
|
|
2810
3065
|
printf '%s\n' "$leaked_pi" | sed 's/^/ /' >&2
|
|
2811
3066
|
return 1
|
|
2812
3067
|
fi
|
|
2813
|
-
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works pi package is 0.
|
|
3068
|
+
echo "[check-pack-install] pi runtime tree pin verified: every @earendil-works pi package is 0.84.1"
|
|
2814
3069
|
|
|
2815
3070
|
# Resolve the installed package.json and confirm pi.extensions
|
|
2816
3071
|
# arrived intact. If pi.extensions is empty or missing, the
|
|
@@ -3200,8 +3455,16 @@ function finish(trimmed) {
|
|
|
3200
3455
|
try { msg = JSON.parse(trimmed); }
|
|
3201
3456
|
catch { console.error('unparseable tools/list:', trimmed.slice(0, 300)); if (stderr.trim()) console.error(stderr.trim()); process.exit(1); }
|
|
3202
3457
|
const names = (msg?.result?.tools ?? []).map((t) => t?.name).sort();
|
|
3203
|
-
|
|
3204
|
-
|
|
3458
|
+
// EXACT set, not a floor. The subset form of this assertion named only the five
|
|
3459
|
+
// pre-0.14 verbs, so an ARTIFACT whose bridge boots and answers but carries an older
|
|
3460
|
+
// emitted surface — no entwurf_fresh_call, no entwurf_resume_call — passed the very
|
|
3461
|
+
// gate that exists to catch "green clone, dead consumer". Equality also catches the
|
|
3462
|
+
// other direction the narrow-surface rule cares about: an extra or duplicated verb
|
|
3463
|
+
// reaching hosts without a decision. Written sorted; `names` is sorted above.
|
|
3464
|
+
const EXPECT_TOOLS = ['entwurf_fresh_call', 'entwurf_inbox_read', 'entwurf_peers', 'entwurf_register_native', 'entwurf_resume_call', 'entwurf_self', 'entwurf_v2'];
|
|
3465
|
+
if (names.length !== EXPECT_TOOLS.length || EXPECT_TOOLS.some((n, i) => names[i] !== n)) {
|
|
3466
|
+
console.error('installed MCP tool set MISMATCH — want exactly [' + EXPECT_TOOLS.join(',') + '] got [' + names.join(',') + ']');
|
|
3467
|
+
process.exit(1);
|
|
3205
3468
|
}
|
|
3206
3469
|
console.log(names.join(','));
|
|
3207
3470
|
child.kill('SIGTERM');
|
|
@@ -3483,6 +3746,21 @@ JSON
|
|
|
3483
3746
|
echo "$devgate_out" | tail -6 | sed 's/^/ /' >&2
|
|
3484
3747
|
return 1
|
|
3485
3748
|
fi
|
|
3749
|
+
# The migrated fresh-call gate takes a third path: run_vitest. Drive that exact
|
|
3750
|
+
# installed branch and require both the nonzero refusal and its intended cause;
|
|
3751
|
+
# an incidental missing file or raw strip-types crash is not consumer evidence.
|
|
3752
|
+
local vitestgate_out vitestgate_rc=0
|
|
3753
|
+
vitestgate_out=$(HOME="$npmhome" XDG_DATA_HOME="$op_xdg_data" XDG_STATE_HOME="$op_xdg_state" XDG_CACHE_HOME="$op_xdg_cache" PI_CODING_AGENT_DIR="$op_agent" "$installed_entwurf" check-mux-fresh-call 2>&1) || vitestgate_rc=$?
|
|
3754
|
+
if [ "$vitestgate_rc" -eq 0 ]; then
|
|
3755
|
+
fail "[check-pack-install] the Vitest-backed check-mux-fresh-call exited 0 from an installed package — the devDependency runner is absent"
|
|
3756
|
+
return 1
|
|
3757
|
+
fi
|
|
3758
|
+
if ! printf '%s' "$vitestgate_out" | grep -q 'dev-clone-only surface' || ! printf '%s' "$vitestgate_out" | grep -q 'vitest is a devDependency'; then
|
|
3759
|
+
fail "[check-pack-install] installed check-mux-fresh-call did not refuse for run_vitest's intended devDependency/dev-clone-only reason:"
|
|
3760
|
+
echo "$vitestgate_out" | tail -6 | sed 's/^/ /' >&2
|
|
3761
|
+
return 1
|
|
3762
|
+
fi
|
|
3763
|
+
|
|
3486
3764
|
# Same rule, different mechanism. check-fresh-cut-gate is a SHELL gate, so run_ts
|
|
3487
3765
|
# never sees it — `scripts/` ships whole and the dispatch would happily run it
|
|
3488
3766
|
# from under node_modules, where the dev sandbox it builds has no business
|
|
@@ -3499,7 +3777,7 @@ JSON
|
|
|
3499
3777
|
echo "$shgate_out" | tail -6 | sed 's/^/ /' >&2
|
|
3500
3778
|
return 1
|
|
3501
3779
|
fi
|
|
3502
|
-
echo "[check-pack-install] dev-only gate refusal pass (installed package refuses
|
|
3780
|
+
echo "[check-pack-install] dev-only gate refusal pass (installed package refuses run_ts and run_vitest checks for their exact causes; shell-side check-fresh-cut-gate refuses on its own guard; no silent exit 0)"
|
|
3503
3781
|
|
|
3504
3782
|
# 0.12.4 — installed STORE-DOCTOR regression. meta-bridge-doctor.sh's full store
|
|
3505
3783
|
# scan runs the prebuilt dist JS when it lives under node_modules (strip-types
|
|
@@ -3599,7 +3877,7 @@ check_pack_install() {
|
|
|
3599
3877
|
# NOT run the legacy ACP/v1 Axis 1 interview gates (session-messaging/sentinel):
|
|
3600
3878
|
# those call removed surfaces and survive only as fail-loud reference subcommands
|
|
3601
3879
|
# until rewritten onto entwurf_v2. The release-gate owns the heavier live v2
|
|
3602
|
-
# substrate proof (matrix-live
|
|
3880
|
+
# substrate proof (matrix-live).
|
|
3603
3881
|
|
|
3604
3882
|
validate_entwurf_bridge() {
|
|
3605
3883
|
local bridge_dir="$REPO_DIR/mcp/entwurf-bridge"
|
|
@@ -3610,7 +3888,11 @@ validate_entwurf_bridge() {
|
|
|
3610
3888
|
return 1
|
|
3611
3889
|
fi
|
|
3612
3890
|
|
|
3613
|
-
|
|
3891
|
+
# The launcher picks its own mode by LOCATION (dev clone → strip-types source; under
|
|
3892
|
+
# node_modules → prebuilt dist), and this subcommand ships, so an operator running
|
|
3893
|
+
# `entwurf check-bridge` from an npm install reads this line too. Naming only the dev
|
|
3894
|
+
# branch here told that operator the installed bytes were never the subject.
|
|
3895
|
+
log "entwurf-bridge: direct MCP smoke (start.sh as it ships — source under a clone, prebuilt dist under node_modules)"
|
|
3614
3896
|
|
|
3615
3897
|
if ! raw=$(cd "$bridge_dir" && node --input-type=module <<'JS'
|
|
3616
3898
|
import { spawn } from 'node:child_process';
|
|
@@ -3632,12 +3914,16 @@ function finishOk(trimmed) {
|
|
|
3632
3914
|
process.exit(1);
|
|
3633
3915
|
}
|
|
3634
3916
|
const names = tools.map((t) => t?.name).sort();
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3917
|
+
// EXACT set, not a floor. This is the assertion behind the operator-facing claim that
|
|
3918
|
+
// `entwurf check-bridge` proves the installed bytes list the seven garden tools — and
|
|
3919
|
+
// under an installed package this launcher IS the dist branch of start.sh, so a subset
|
|
3920
|
+
// check here let an artifact missing entwurf_fresh_call / entwurf_resume_call read as a
|
|
3921
|
+
// green bridge. Equality also refuses an undecided extra verb. Written sorted; `names`
|
|
3922
|
+
// is sorted above.
|
|
3923
|
+
const expected = ['entwurf_fresh_call', 'entwurf_inbox_read', 'entwurf_peers', 'entwurf_register_native', 'entwurf_resume_call', 'entwurf_self', 'entwurf_v2'];
|
|
3924
|
+
if (names.length !== expected.length || expected.some((n, i) => names[i] !== n)) {
|
|
3925
|
+
console.error(`MCP tool set MISMATCH — want exactly [${expected.join(',')}] got [${names.join(',')}]`);
|
|
3926
|
+
process.exit(1);
|
|
3641
3927
|
}
|
|
3642
3928
|
console.log(names.join(','));
|
|
3643
3929
|
child.kill('SIGTERM');
|
|
@@ -3757,7 +4043,7 @@ setup_all() {
|
|
|
3757
4043
|
# native-harness meta-bridge, so a relocate/clone needs ONE command — not the
|
|
3758
4044
|
# install + install-meta-bridge two-pronged split that froze the Claude
|
|
3759
4045
|
# statusLine on the old path (the 2026-06-23 relocation gap). Detection-gated:
|
|
3760
|
-
# a pi-only host with no native harness skips it cleanly (
|
|
4046
|
+
# a pi-only host with no native harness skips it cleanly (rail “Shipped adapters” — "있으면 설정,
|
|
3761
4047
|
# 없으면 담아준다"); meta-bridge-install.sh is itself idempotent.
|
|
3762
4048
|
if command -v claude >/dev/null 2>&1; then
|
|
3763
4049
|
section "meta-bridge install (native harness detected: Claude Code)"
|
|
@@ -3788,8 +4074,8 @@ setup_all() {
|
|
|
3788
4074
|
# survives while the meta-record is created/attached by conversationId.
|
|
3789
4075
|
wire_agy_hooks
|
|
3790
4076
|
|
|
3791
|
-
# Deterministic preflight lives in `pnpm check`; live substrate acceptance lives
|
|
3792
|
-
# in `LIVE=1 ./run.sh release-gate <scratch
|
|
4077
|
+
# Deterministic preflight lives in `pnpm run check:full`; live substrate acceptance lives
|
|
4078
|
+
# in `LIVE=1 ./run.sh release-gate <scratch> --cut`. Setup is the install path, so it
|
|
3793
4079
|
# verifies the installed MCP bridge boundary only and does NOT run the legacy
|
|
3794
4080
|
# ACP/v1 session-messaging/sentinel gates.
|
|
3795
4081
|
section "v2 install smoke: entwurf-bridge (direct MCP protocol)"
|
|
@@ -3805,7 +4091,7 @@ setup_all() {
|
|
|
3805
4091
|
echo " ./run.sh doctor-agy-statusline"
|
|
3806
4092
|
echo " ./run.sh doctor-agy-hooks"
|
|
3807
4093
|
fi
|
|
3808
|
-
echo "Run 'LIVE=1 ./run.sh release-gate <scratch>' for live substrate acceptance."
|
|
4094
|
+
echo "Run 'LIVE=1 ./run.sh release-gate <scratch> --cut' for live substrate acceptance (--cut refuses any MUST SKIP)."
|
|
3809
4095
|
}
|
|
3810
4096
|
|
|
3811
4097
|
# wire_agy_bridge — detection-gated, NON-FATAL agy (Antigravity) MCP bridge wiring, folded into
|
|
@@ -3967,13 +4253,13 @@ expose_dev_bin() {
|
|
|
3967
4253
|
}
|
|
3968
4254
|
|
|
3969
4255
|
# release-gate — the single command that, when GREEN, is sufficient to cut
|
|
3970
|
-
# release cuts. Runs the full static floor (`pnpm check`) followed by the
|
|
4256
|
+
# release cuts. Runs the full static floor (`pnpm run check:full`) followed by the
|
|
3971
4257
|
# v2-native live gates, then emits one PASS/FAIL/SKIP summary. Everything is
|
|
3972
4258
|
# invoked through run.sh subcommands — never a script in scripts/ directly.
|
|
3973
4259
|
#
|
|
3974
4260
|
# Design invariants (NEXT Step 1e + GPT-5.5 reviews):
|
|
3975
4261
|
# - v2-native live floor: the MUST tier is the v2 dispatch substrate
|
|
3976
|
-
# (smoke-entwurf-v2-matrix-live
|
|
4262
|
+
# (smoke-entwurf-v2-matrix-live, opt-in
|
|
3977
4263
|
# LIVE), the MCP bridge (check-bridge), and the resident citizen guard
|
|
3978
4264
|
# (smoke-resident-garden-guard).
|
|
3979
4265
|
# - ACP plugin acceptance floor (S0~S2g): the 11 ACP LIVE smokes
|
|
@@ -3989,10 +4275,18 @@ expose_dev_bin() {
|
|
|
3989
4275
|
# - Final release authorization is GLG's, not this script's: a green
|
|
3990
4276
|
# run is necessary, and the operator closes the decision.
|
|
3991
4277
|
release_gate() {
|
|
4278
|
+
entwurf_require_step_outcome
|
|
3992
4279
|
local -a positional=()
|
|
3993
4280
|
local a
|
|
4281
|
+
# --cut is the EXECUTABLE half of "a CUT needs LIVE=1, SKIP=0" (P1). Without it
|
|
4282
|
+
# this stays the unattended diagnostic it has always been: SKIPs are reported
|
|
4283
|
+
# and the run still exits 0. With it, any MUST SKIP is red — including the
|
|
4284
|
+
# LIVE!=1 case, which needs no separate assertion because every LIVE-gated step
|
|
4285
|
+
# then skips on its own and the skip counter blocks.
|
|
4286
|
+
local cut_mode=0
|
|
3994
4287
|
for a in "$@"; do
|
|
3995
4288
|
case "$a" in
|
|
4289
|
+
--cut) cut_mode=1 ;;
|
|
3996
4290
|
--allow-skip-gemini) ;; # accepted-but-ignored: gemini removed from the claude-only floor (back-compat for existing scripts)
|
|
3997
4291
|
*) positional+=("$a") ;;
|
|
3998
4292
|
esac
|
|
@@ -4043,27 +4337,36 @@ release_gate() {
|
|
|
4043
4337
|
}
|
|
4044
4338
|
|
|
4045
4339
|
# LIVE-gated MUST step: a release-blocking gate that needs a real backend turn
|
|
4046
|
-
# (auth/model/credit).
|
|
4047
|
-
#
|
|
4048
|
-
#
|
|
4049
|
-
#
|
|
4050
|
-
#
|
|
4051
|
-
#
|
|
4340
|
+
# (auth/model/credit). It is ALWAYS INVOKED and the step itself reports whether
|
|
4341
|
+
# it could run — that is the whole point of P1. The old shape asked `LIVE=1?`
|
|
4342
|
+
# here and skipped without calling, which meant the summary asserted a skip it
|
|
4343
|
+
# had never confirmed, while a step that WAS called could still exit 0 on a
|
|
4344
|
+
# missing prerequisite (Cortex without a connection) and be counted PASS.
|
|
4345
|
+
# Now one protocol decides: exit 0 = PASS, $ENTWURF_STEP_SKIP_EXIT = SKIP,
|
|
4346
|
+
# anything else = FAIL. A SKIP is never rounded up, and `--cut` refuses any.
|
|
4347
|
+
#
|
|
4348
|
+
# `LIVE` is NOT forced here — it rides the operator's environment into the
|
|
4349
|
+
# child, so `LIVE=1 ./run.sh release-gate` runs the step for real and a bare
|
|
4350
|
+
# invocation gets the step's own honest skip.
|
|
4052
4351
|
run_live_step() {
|
|
4053
4352
|
local name="$1"; shift
|
|
4054
4353
|
section "release-gate step: $name"
|
|
4055
|
-
|
|
4056
|
-
|
|
4354
|
+
local rc=0
|
|
4355
|
+
"$@" || rc=$?
|
|
4356
|
+
case "$(entwurf_step_outcome "$rc")" in
|
|
4357
|
+
PASS)
|
|
4057
4358
|
ok "$name: PASS"
|
|
4058
4359
|
results+=("PASS $name"); pass=$((pass + 1))
|
|
4059
|
-
|
|
4060
|
-
|
|
4360
|
+
;;
|
|
4361
|
+
SKIP)
|
|
4362
|
+
warn "$name: SKIP — the step declined a prerequisite it does not have (see its [entwurf:skip] line above). NOT a live acceptance."
|
|
4363
|
+
results+=("SKIP $name"); skip=$((skip + 1))
|
|
4364
|
+
;;
|
|
4365
|
+
*)
|
|
4366
|
+
fail "$name: FAIL (exit $rc)"
|
|
4061
4367
|
results+=("FAIL $name"); failc=$((failc + 1))
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
warn "$name: LIVE!=1 — skipped (opt-in: needs auth/model — NOT a live acceptance run)"
|
|
4065
|
-
results+=("SKIP $name (LIVE!=1)"); skip=$((skip + 1))
|
|
4066
|
-
fi
|
|
4368
|
+
;;
|
|
4369
|
+
esac
|
|
4067
4370
|
}
|
|
4068
4371
|
|
|
4069
4372
|
# BEHAVIOR lane (0.11.0, GLG+GPT+Opus): a SEPARATE advisory counter for
|
|
@@ -4087,29 +4390,56 @@ release_gate() {
|
|
|
4087
4390
|
# deterministic/programmatic must-pass gates above (check-entwurf-v2-*,
|
|
4088
4391
|
# check-bridge) — this lane is autonomous-tool-selection *behavior*, not
|
|
4089
4392
|
# *function*. Residual bypass → 0.11.x usability lane.
|
|
4090
|
-
|
|
4393
|
+
# The lane speaks the same STEP OUTCOME protocol (P1) so a missing prerequisite
|
|
4394
|
+
# here is a BEHAVIOR-SKIP, not a fabricated BEHAVIOR-PASS or a misread
|
|
4395
|
+
# BEHAVIOR-FAIL. Advisory semantics are untouched: none of these counters ever
|
|
4396
|
+
# reaches `failc`, and `--cut` reads the MUST skip counter only.
|
|
4397
|
+
local behavior_pass=0 behavior_failc=0 behavior_skip=0
|
|
4091
4398
|
local -a behavior_results=()
|
|
4092
4399
|
|
|
4093
4400
|
run_behavior_step() {
|
|
4094
4401
|
local name="$1"; shift
|
|
4095
4402
|
section "release-gate BEHAVIOR step (advisory, non-blocking): $name"
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4403
|
+
local rc=0
|
|
4404
|
+
"$@" || rc=$?
|
|
4405
|
+
case "$(entwurf_step_outcome "$rc")" in
|
|
4406
|
+
PASS)
|
|
4407
|
+
ok "$name: BEHAVIOR-PASS"
|
|
4408
|
+
behavior_results+=("BEHAVIOR-PASS $name"); behavior_pass=$((behavior_pass + 1))
|
|
4409
|
+
;;
|
|
4410
|
+
SKIP)
|
|
4411
|
+
warn "$name: BEHAVIOR-SKIP — prerequisite absent (advisory lane; not a signal either way)"
|
|
4412
|
+
behavior_results+=("BEHAVIOR-SKIP $name"); behavior_skip=$((behavior_skip + 1))
|
|
4413
|
+
;;
|
|
4414
|
+
*)
|
|
4415
|
+
warn "$name: BEHAVIOR-FAIL (advisory — model-in-loop signal; S7=Bash-bypass stays hard-fail here; NOT a cut blocker)"
|
|
4416
|
+
behavior_results+=("BEHAVIOR-FAIL $name"); behavior_failc=$((behavior_failc + 1))
|
|
4417
|
+
;;
|
|
4418
|
+
esac
|
|
4103
4419
|
}
|
|
4104
4420
|
|
|
4105
|
-
# 1. Static floor (deterministic;
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4421
|
+
# 1. Static floor (deterministic; the FULL tier — core plus hermetic/package —
|
|
4422
|
+
# never the ≤60s everyday core alone).
|
|
4423
|
+
section "release-gate step: static (pnpm run check:full)"
|
|
4424
|
+
if (cd "$REPO_DIR" && pnpm run check:full); then
|
|
4425
|
+
ok "static (pnpm run check:full): PASS"
|
|
4426
|
+
results+=("PASS static (pnpm run check:full)"); pass=$((pass + 1))
|
|
4110
4427
|
else
|
|
4111
|
-
fail "static (pnpm check): FAIL"
|
|
4112
|
-
results+=("FAIL static (pnpm check)"); failc=$((failc + 1))
|
|
4428
|
+
fail "static (pnpm run check:full): FAIL"
|
|
4429
|
+
results+=("FAIL static (pnpm run check:full)"); failc=$((failc + 1))
|
|
4430
|
+
fi
|
|
4431
|
+
|
|
4432
|
+
# 1b. Discriminating power of that floor. check-gate-qualification left the
|
|
4433
|
+
# default check chains (operator inner-loop cost), so release acceptance
|
|
4434
|
+
# carries it explicitly as its own MUST step: a cut must re-prove the gates
|
|
4435
|
+
# still kill what they claim to kill.
|
|
4436
|
+
section "release-gate step: check-gate-qualification"
|
|
4437
|
+
if (cd "$REPO_DIR" && bash "$self" check-gate-qualification); then
|
|
4438
|
+
ok "check-gate-qualification: PASS"
|
|
4439
|
+
results+=("PASS check-gate-qualification"); pass=$((pass + 1))
|
|
4440
|
+
else
|
|
4441
|
+
fail "check-gate-qualification: FAIL"
|
|
4442
|
+
results+=("FAIL check-gate-qualification"); failc=$((failc + 1))
|
|
4113
4443
|
fi
|
|
4114
4444
|
|
|
4115
4445
|
# 2. (gemini-availability step removed — claude-only floor; gemini CLI is
|
|
@@ -4125,7 +4455,7 @@ release_gate() {
|
|
|
4125
4455
|
# the identity foundation is broken, every Entwurf live gate below is
|
|
4126
4456
|
# meaningless, so fail fast here. (The old smoke-session-id-name substrate
|
|
4127
4457
|
# proof is gone with the substrate itself — #50 C3; smoke-pi-attach carries
|
|
4128
|
-
# the deterministic half inside pnpm check.)
|
|
4458
|
+
# the deterministic half inside pnpm run check:full.)
|
|
4129
4459
|
# RGG split: the 0-token half (BIRTH: record + record-keyed socket / ATTACH:
|
|
4130
4460
|
# re-open keeps the address / REPLACEMENT: in-process /new is pi's again) is
|
|
4131
4461
|
# release-blocking and stays here as a must-pass with SMOKE_RGG_POSITIVE=0. The
|
|
@@ -4137,41 +4467,16 @@ release_gate() {
|
|
|
4137
4467
|
# production runEntwurfV2 deps + real pi control-socket RPC + real mailbox enqueue + v2 lock, not
|
|
4138
4468
|
# per-backend model behavior). Placed right after check-bridge: the MCP/protocol substrate must be
|
|
4139
4469
|
# green first so a matrix-live failure reads as "v2 transport/lock/enqueue", not bridge basics.
|
|
4140
|
-
# Opt-in LIVE: it spawns a real `pi --entwurf-control` (needs auth/model), so
|
|
4141
|
-
# SKIP (not a PASS) — an unattended release-gate stays runnable without
|
|
4142
|
-
# of --allow-skip-gemini (now a no-op back-compat flag on the
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
results+=("FAIL smoke-entwurf-v2-matrix-live"); failc=$((failc + 1))
|
|
4151
|
-
fi
|
|
4152
|
-
else
|
|
4153
|
-
warn "smoke-entwurf-v2-matrix-live: LIVE!=1 — skipped (v2 substrate sentinel, opt-in: needs auth/model)"
|
|
4154
|
-
results+=("SKIP smoke-entwurf-v2-matrix-live (LIVE!=1)"); skip=$((skip + 1))
|
|
4155
|
-
fi
|
|
4156
|
-
# 0.11.0 (A) acceptance: the FULL spawn-bg resident lifecycle — a real `pi` resume child stands
|
|
4157
|
-
# its control socket up, does a model turn, lock released ×1. Placed right after matrix-live (the
|
|
4158
|
-
# transport sentinel): a spawn-resume failure then reads as "resume/resident lifecycle", not
|
|
4159
|
-
# transport basics. Same opt-in LIVE rule — LIVE!=1 is an HONEST SKIP (model-in-loop, needs
|
|
4160
|
-
# auth/model). NOTE: a 0.11.0 tag REQUIRES `LIVE=1 ./run.sh release-gate` (or this step direct)
|
|
4161
|
-
# to PASS — the SKIP is CI safety, never acceptance.
|
|
4162
|
-
section "release-gate step: smoke-entwurf-v2-spawn-resume-live"
|
|
4163
|
-
if [ "${LIVE:-}" = "1" ]; then
|
|
4164
|
-
if gate env LIVE=1 bash "$self" smoke-entwurf-v2-spawn-resume-live; then
|
|
4165
|
-
ok "smoke-entwurf-v2-spawn-resume-live: PASS"
|
|
4166
|
-
results+=("PASS smoke-entwurf-v2-spawn-resume-live"); pass=$((pass + 1))
|
|
4167
|
-
else
|
|
4168
|
-
fail "smoke-entwurf-v2-spawn-resume-live: FAIL"
|
|
4169
|
-
results+=("FAIL smoke-entwurf-v2-spawn-resume-live"); failc=$((failc + 1))
|
|
4170
|
-
fi
|
|
4171
|
-
else
|
|
4172
|
-
warn "smoke-entwurf-v2-spawn-resume-live: LIVE!=1 — skipped (0.11.0 A acceptance, opt-in: needs auth/model)"
|
|
4173
|
-
results+=("SKIP smoke-entwurf-v2-spawn-resume-live (LIVE!=1)"); skip=$((skip + 1))
|
|
4174
|
-
fi
|
|
4470
|
+
# Opt-in LIVE: it spawns a real `pi --entwurf-control` (needs auth/model), so a missing
|
|
4471
|
+
# prerequisite is an HONEST SKIP (not a PASS) — an unattended release-gate stays runnable without
|
|
4472
|
+
# faking coverage. Independent of --allow-skip-gemini (now a no-op back-compat flag on the
|
|
4473
|
+
# claude-only floor; this gates substrate auth). It used to carry its own inline copy of the
|
|
4474
|
+
# PASS/FAIL/SKIP branch; P1 folded it onto `run_live_step` so there is exactly ONE classifier —
|
|
4475
|
+
# a second copy is how a lane silently keeps counting a skip as a pass.
|
|
4476
|
+
run_live_step "smoke-entwurf-v2-matrix-live (D4-c: v2 dispatch substrate sentinel)" gate bash "$self" smoke-entwurf-v2-matrix-live
|
|
4477
|
+
# The spawn-bg resident-lifecycle acceptance that used to sit here left with the transport in the
|
|
4478
|
+
# visible-first cut. A same-id resume lane will need its own acceptance step; it does not inherit
|
|
4479
|
+
# this one, because what that step proved was a HIDDEN child standing its socket up.
|
|
4175
4480
|
|
|
4176
4481
|
# 3b. ACP plugin acceptance floor (S0~S2f live). These prove the ACP plugin's
|
|
4177
4482
|
# programmatic transport/provider/backend invariants on the v2 core — NOT
|
|
@@ -4186,18 +4491,35 @@ release_gate() {
|
|
|
4186
4491
|
# → first-user augment delivery + empty-carrier billing-clean (핀1) →
|
|
4187
4492
|
# ACP-target garden guard (deterministic half). Opt-in LIVE: LIVE!=1 is an
|
|
4188
4493
|
# HONEST SKIP via run_live_step (see its note) — a CUT needs LIVE=1, SKIP=0.
|
|
4189
|
-
run_live_step "smoke-acp-socket-citizen-live (S1: turn-free socket citizenship)" gate
|
|
4190
|
-
run_live_step "smoke-acp-raw-turn-live (S2a: pinned ACP pipe + local auth)" gate
|
|
4191
|
-
run_live_step "smoke-acp-overlay-live (S2b: config overlay + hooks:{} + tool meta)" gate
|
|
4192
|
-
run_live_step "smoke-acp-provider-live (S2c/S2f: real pi provider path + progress/L3)" gate
|
|
4193
|
-
run_live_step "smoke-acp-session-reuse-live (S2d: process-scoped reuse + recall)" gate
|
|
4194
|
-
run_live_step "smoke-acp-carrier-augment-live (S2e-1: augment delivery + 핀1 billing)" gate
|
|
4195
|
-
run_live_step "smoke-acp-memory-containment-live (Gate D: no overlay memory leak)" gate
|
|
4196
|
-
run_live_step "smoke-acp-rgg-live (S2e-2: ACP-target garden guard, deterministic half)" gate
|
|
4197
|
-
run_live_step "smoke-acp-mcp-live (S2g: operator mcpServers reach the live ACP session)" gate
|
|
4198
|
-
run_live_step "smoke-acp-skill-live (S2g: operator skillPlugins reach the live ACP session)" gate
|
|
4199
|
-
run_live_step "smoke-acp-bundled-mcp-live (S2g axis 3: bundled entwurf-bridge via 0.11.0 resident/RPC circuit)" gate
|
|
4200
|
-
run_live_step "smoke-acp-v2-send-live (S2g axis 4: an ACP model SENDS via entwurf_v2, landing as itself)" gate
|
|
4494
|
+
run_live_step "smoke-acp-socket-citizen-live (S1: turn-free socket citizenship)" gate bash "$self" smoke-acp-socket-citizen-live
|
|
4495
|
+
run_live_step "smoke-acp-raw-turn-live (S2a: pinned ACP pipe + local auth)" gate bash "$self" smoke-acp-raw-turn-live
|
|
4496
|
+
run_live_step "smoke-acp-overlay-live (S2b: config overlay + hooks:{} + tool meta)" gate bash "$self" smoke-acp-overlay-live
|
|
4497
|
+
run_live_step "smoke-acp-provider-live (S2c/S2f: real pi provider path + progress/L3)" gate bash "$self" smoke-acp-provider-live
|
|
4498
|
+
run_live_step "smoke-acp-session-reuse-live (S2d: process-scoped reuse + recall)" gate bash "$self" smoke-acp-session-reuse-live
|
|
4499
|
+
run_live_step "smoke-acp-carrier-augment-live (S2e-1: augment delivery + 핀1 billing)" gate bash "$self" smoke-acp-carrier-augment-live
|
|
4500
|
+
run_live_step "smoke-acp-memory-containment-live (Gate D: no overlay memory leak)" gate bash "$self" smoke-acp-memory-containment-live
|
|
4501
|
+
run_live_step "smoke-acp-rgg-live (S2e-2: ACP-target garden guard, deterministic half)" gate bash "$self" smoke-acp-rgg-live
|
|
4502
|
+
run_live_step "smoke-acp-mcp-live (S2g: operator mcpServers reach the live ACP session)" gate bash "$self" smoke-acp-mcp-live
|
|
4503
|
+
run_live_step "smoke-acp-skill-live (S2g: operator skillPlugins reach the live ACP session)" gate bash "$self" smoke-acp-skill-live
|
|
4504
|
+
run_live_step "smoke-acp-bundled-mcp-live (S2g axis 3: bundled entwurf-bridge via 0.11.0 resident/RPC circuit)" gate bash "$self" smoke-acp-bundled-mcp-live
|
|
4505
|
+
run_live_step "smoke-acp-v2-send-live (S2g axis 4: an ACP model SENDS via entwurf_v2, landing as itself)" gate bash "$self" smoke-acp-v2-send-live
|
|
4506
|
+
|
|
4507
|
+
# 3c. The axes the aggregate used to leave out with no stated reason (P2,
|
|
4508
|
+
# 2026-07-31). Three LIVE smokes existed and were simply never wired, so a
|
|
4509
|
+
# green cut said nothing about them. Under the P1 outcome protocol wiring
|
|
4510
|
+
# them costs nothing on a host that cannot run them — they SKIP honestly and
|
|
4511
|
+
# `--cut` names the missing prerequisite — while a host that CAN run them now
|
|
4512
|
+
# must. Cortex is deliberately NOT here: its rail needs an external Snowflake
|
|
4513
|
+
# connection the HOST owns, so wiring it would block every cut taken without
|
|
4514
|
+
# that account; it stays a required DIRECT call for a Cortex-rail cut instead
|
|
4515
|
+
# (VERIFY 「Cortex is an on-demand axis」). Same for `smoke-acp-long-turn-live`,
|
|
4516
|
+
# `smoke-agy-native-push-live` and `smoke-acp-ordering-probe-live`: >12min by
|
|
4517
|
+
# construction, no aggregate-owned agy conversation id, and an opt-in instrument
|
|
4518
|
+
# rather than acceptance. check-release-gate-outcomes pins that every LIVE smoke
|
|
4519
|
+
# is either wired here or excluded by a reason the docs still carry.
|
|
4520
|
+
run_live_step "smoke-claude-native-resume-live (native Claude Code resume + meta-bridge neutrality)" gate bash "$self" smoke-claude-native-resume-live
|
|
4521
|
+
run_live_step "smoke-entwurf-chain-live (P3: Claude Code -> pi GPT -> pi ACP Sonnet -> mailbox, identity + receipt)" gate bash "$self" smoke-entwurf-chain-live
|
|
4522
|
+
run_live_step "smoke-mux-lifecycle-live (mux public-harness lifecycle: fresh -> send -> dormant -> same-id visible resume -> recall)" gate bash "$self" smoke-mux-lifecycle-live
|
|
4201
4523
|
|
|
4202
4524
|
# 4. BEHAVIOR lane (advisory, non-blocking). Model-in-loop gates that probe
|
|
4203
4525
|
# whether the model AUTONOMOUSLY drives the MCP entwurf surface. These never
|
|
@@ -4227,21 +4549,44 @@ release_gate() {
|
|
|
4227
4549
|
if [ "${#behavior_results[@]}" -gt 0 ]; then
|
|
4228
4550
|
printf ' %s\n' "${behavior_results[@]}"
|
|
4229
4551
|
fi
|
|
4230
|
-
echo " BEHAVIOR: PASS=$behavior_pass FAIL=$behavior_failc"
|
|
4552
|
+
echo " BEHAVIOR: PASS=$behavior_pass FAIL=$behavior_failc SKIP=$behavior_skip"
|
|
4231
4553
|
echo " (per-step artifact paths are printed in each step's output above)"
|
|
4232
4554
|
if [ "$behavior_failc" -gt 0 ]; then
|
|
4233
4555
|
echo ""
|
|
4234
4556
|
warn "BEHAVIOR FAIL present ($behavior_failc) — advisory model-in-loop signal (e.g. S7 Bash-bypass / entwurf_self not autonomously called). Tracked, NOT a cut blocker; see the 0.11.x usability lane."
|
|
4235
4557
|
fi
|
|
4236
|
-
|
|
4237
|
-
if [ "$
|
|
4558
|
+
echo ""
|
|
4559
|
+
if [ "$cut_mode" = "1" ]; then
|
|
4560
|
+
echo " mode: --cut (a MUST SKIP is a BLOCKER — this run is being read as release acceptance)"
|
|
4561
|
+
else
|
|
4562
|
+
echo " mode: diagnostic (MUST SKIPs are reported, not blocking — re-run with --cut to read this as acceptance)"
|
|
4563
|
+
fi
|
|
4564
|
+
# The verdict as one greppable token, so release evidence can distinguish a
|
|
4565
|
+
# step that RAN AND BROKE from one that NEVER RAN without reading prose. The
|
|
4566
|
+
# counters above stay literal — a policy block is `FAIL=0 SKIP=n` plus
|
|
4567
|
+
# `BLOCKED (MUST SKIP)`, never a synthesized failure.
|
|
4568
|
+
echo " $(entwurf_release_verdict "$failc" "$skip" "$cut_mode")"
|
|
4569
|
+
|
|
4570
|
+
# Exit authority — MUST tier only, BEHAVIOR never blocks. The releasable
|
|
4571
|
+
# decision lives in scripts/lib/step-outcome.sh so it is one testable function
|
|
4572
|
+
# rather than a branch re-derived here (and re-derived wrong: the pre-P1 branch
|
|
4573
|
+
# read `failc` alone, so a run with 14 SKIPs still printed "all green").
|
|
4574
|
+
if ! entwurf_release_releasable "$failc" "$skip" "$cut_mode"; then
|
|
4238
4575
|
echo ""
|
|
4239
|
-
|
|
4576
|
+
if [ "$failc" -gt 0 ]; then
|
|
4577
|
+
fail "release-gate MUST NOT green — $failc release-blocking step(s) failed. Current release is NOT releasable."
|
|
4578
|
+
else
|
|
4579
|
+
fail "release-gate --cut REFUSED — $skip release-blocking step(s) SKIPPED, so this run does not prove they were called."
|
|
4580
|
+
echo " A skipped step is not acceptance. Supply each missing prerequisite (usually LIVE=1 plus the"
|
|
4581
|
+
echo " per-step env the [entwurf:skip] lines above name) and re-run, or drop --cut to keep this a diagnostic."
|
|
4582
|
+
fi
|
|
4240
4583
|
echo " A green MUST gate is necessary but not sufficient; GLG closes the call."
|
|
4241
4584
|
return 1
|
|
4242
4585
|
fi
|
|
4243
|
-
if [ "$
|
|
4244
|
-
|
|
4586
|
+
if [ "$skip" -gt 0 ]; then
|
|
4587
|
+
warn "release-gate MUST has no failures, but $skip step(s) SKIPPED — this is a DIAGNOSTIC run, not live acceptance. A cut needs \`LIVE=1 ./run.sh release-gate <scratch> --cut\` with SKIP=0."
|
|
4588
|
+
elif [ "$behavior_failc" -gt 0 ]; then
|
|
4589
|
+
ok "release-gate MUST PASS (all release-blocking steps ran and are green); BEHAVIOR FAIL present (advisory). Necessary condition met — GLG authorizes the cut."
|
|
4245
4590
|
else
|
|
4246
4591
|
ok "release-gate MUST PASS + BEHAVIOR PASS — all green. Necessary condition met — GLG authorizes the cut."
|
|
4247
4592
|
fi
|
|
@@ -4363,20 +4708,44 @@ case "$cmd" in
|
|
|
4363
4708
|
check-entwurf-bridge-pi-free)
|
|
4364
4709
|
check_entwurf_bridge_pi_free
|
|
4365
4710
|
;;
|
|
4366
|
-
check-entwurf-v2-spawn)
|
|
4367
|
-
check_entwurf_v2_spawn
|
|
4368
|
-
;;
|
|
4369
4711
|
check-entwurf-resume-args)
|
|
4370
4712
|
check_entwurf_resume_args
|
|
4371
4713
|
;;
|
|
4372
|
-
check-
|
|
4373
|
-
|
|
4714
|
+
check-resume-launch-identity)
|
|
4715
|
+
check_resume_launch_identity
|
|
4716
|
+
;;
|
|
4717
|
+
check-mux-placement)
|
|
4718
|
+
check_mux_placement
|
|
4719
|
+
;;
|
|
4720
|
+
check-mux-placement-tmux)
|
|
4721
|
+
check_mux_placement_tmux
|
|
4722
|
+
;;
|
|
4723
|
+
check-mux-launch)
|
|
4724
|
+
check_mux_launch
|
|
4374
4725
|
;;
|
|
4375
|
-
|
|
4376
|
-
|
|
4726
|
+
check-mux-fresh-call)
|
|
4727
|
+
check_mux_fresh_call
|
|
4377
4728
|
;;
|
|
4378
|
-
|
|
4379
|
-
|
|
4729
|
+
check-mux-resume-call)
|
|
4730
|
+
check_mux_resume_call
|
|
4731
|
+
;;
|
|
4732
|
+
check-mux-parent-artifact)
|
|
4733
|
+
check_mux_parent_artifact
|
|
4734
|
+
;;
|
|
4735
|
+
check-mux-launcher-fence)
|
|
4736
|
+
check_mux_launcher_fence
|
|
4737
|
+
;;
|
|
4738
|
+
check-entwurf-v2-visible-resume)
|
|
4739
|
+
check_entwurf_v2_visible_resume
|
|
4740
|
+
;;
|
|
4741
|
+
smoke-mux-fresh-call-live)
|
|
4742
|
+
smoke_mux_fresh_call_live
|
|
4743
|
+
;;
|
|
4744
|
+
smoke-mux-lifecycle-live)
|
|
4745
|
+
smoke_mux_lifecycle_live
|
|
4746
|
+
;;
|
|
4747
|
+
check-mux-launch-tmux)
|
|
4748
|
+
check_mux_launch_tmux
|
|
4380
4749
|
;;
|
|
4381
4750
|
smoke-entwurf-v2-matrix-live)
|
|
4382
4751
|
smoke_entwurf_v2_matrix_live
|
|
@@ -4393,6 +4762,9 @@ case "$cmd" in
|
|
|
4393
4762
|
smoke-acp-provider-live)
|
|
4394
4763
|
smoke_acp_provider_live
|
|
4395
4764
|
;;
|
|
4765
|
+
smoke-acp-long-turn-live)
|
|
4766
|
+
smoke_acp_long_turn_live
|
|
4767
|
+
;;
|
|
4396
4768
|
smoke-acp-session-reuse-live)
|
|
4397
4769
|
smoke_acp_session_reuse_live
|
|
4398
4770
|
;;
|
|
@@ -4405,6 +4777,15 @@ case "$cmd" in
|
|
|
4405
4777
|
smoke-acp-bundled-mcp-live)
|
|
4406
4778
|
smoke_acp_bundled_mcp_live
|
|
4407
4779
|
;;
|
|
4780
|
+
smoke-entwurf-chain-live)
|
|
4781
|
+
# P3 — the cross-harness delivery CHAIN on real authenticated rails:
|
|
4782
|
+
# native Claude Code -> pi GPT -> pi ACP Claude Sonnet -> mailbox terminus,
|
|
4783
|
+
# with sender identity at every hop and a read receipt at the end. Needs
|
|
4784
|
+
# `claude` on PATH plus pi credentials for both pi backends; each missing
|
|
4785
|
+
# prerequisite is an honest protocol SKIP, never a pass.
|
|
4786
|
+
# LIVE=1 ./run.sh smoke-entwurf-chain-live
|
|
4787
|
+
run_ts scripts/smoke-entwurf-chain-live.ts
|
|
4788
|
+
;;
|
|
4408
4789
|
smoke-acp-v2-send-live)
|
|
4409
4790
|
smoke_acp_v2_send_live
|
|
4410
4791
|
;;
|
|
@@ -4432,6 +4813,9 @@ case "$cmd" in
|
|
|
4432
4813
|
check-meta-listing)
|
|
4433
4814
|
check_meta_listing
|
|
4434
4815
|
;;
|
|
4816
|
+
check-meta-facts)
|
|
4817
|
+
check_meta_facts
|
|
4818
|
+
;;
|
|
4435
4819
|
check-entwurf-fact-provider)
|
|
4436
4820
|
check_entwurf_fact_provider
|
|
4437
4821
|
;;
|
|
@@ -4608,7 +4992,7 @@ case "$cmd" in
|
|
|
4608
4992
|
# 봉인 8 LIVE acceptance gate for the native-push (agy) delivery rail. Drives the REAL
|
|
4609
4993
|
# antigravity adapter + register core + runEntwurfV2 (production deps) against a live agy
|
|
4610
4994
|
# conversation (AGY_CONVERSATION_ID): probe route, register create/attach idempotency,
|
|
4611
|
-
# fire→native-push delivered,
|
|
4995
|
+
# fire→native-push delivered, bogus-conv probe-indeterminate reject.
|
|
4612
4996
|
# Meta-store is isolated to a temp dir (only the agy round-trip is real); honest SKIP when
|
|
4613
4997
|
# LIVE!=1. doctor-static preflight FAILs before the agy bridge is wired (③).
|
|
4614
4998
|
run_ts scripts/smoke-agy-native-push-live.ts
|
|
@@ -4775,6 +5159,16 @@ case "$cmd" in
|
|
|
4775
5159
|
shift || true
|
|
4776
5160
|
run_ts scripts/meta-bridge-prune.ts "$@"
|
|
4777
5161
|
;;
|
|
5162
|
+
meta-facts)
|
|
5163
|
+
# #65 owner-normalized READ-ONLY projection of the meta-record store: the
|
|
5164
|
+
# (gardenId, nativeSessionId, transcriptPath) join as deterministic JSON,
|
|
5165
|
+
# emitted by THE listing contract (listAllMetaIdentities) so consumers stop
|
|
5166
|
+
# carrying a decaying copy of the certification. Defects ride in-band with
|
|
5167
|
+
# exit 0; an unreadable store is exit 3 and never looks empty. No liveness,
|
|
5168
|
+
# no socket paths, no transcript contents, no state.
|
|
5169
|
+
shift || true
|
|
5170
|
+
run_ts scripts/meta-facts.ts "$@"
|
|
5171
|
+
;;
|
|
4778
5172
|
meta-bridge-managed-keys)
|
|
4779
5173
|
# 0.10.0 meta-bridge: emit the SSOT of settings.json/~/.claude.json keys that
|
|
4780
5174
|
# entwurf's install OWNS. Consumers (agent-config fragment, future
|
|
@@ -4834,6 +5228,15 @@ case "$cmd" in
|
|
|
4834
5228
|
check-acp-event-mapper)
|
|
4835
5229
|
check_acp_event_mapper
|
|
4836
5230
|
;;
|
|
5231
|
+
check-acp-stop-reason)
|
|
5232
|
+
check_acp_stop_reason
|
|
5233
|
+
;;
|
|
5234
|
+
check-acp-prompt-lifecycle)
|
|
5235
|
+
check_acp_prompt_lifecycle
|
|
5236
|
+
;;
|
|
5237
|
+
check-acp-stream-hooks)
|
|
5238
|
+
check_acp_stream_hooks
|
|
5239
|
+
;;
|
|
4837
5240
|
check-acp-prompt-builder)
|
|
4838
5241
|
check_acp_prompt_builder
|
|
4839
5242
|
;;
|
|
@@ -4849,6 +5252,9 @@ case "$cmd" in
|
|
|
4849
5252
|
check-acp-session-reuse)
|
|
4850
5253
|
check_acp_session_reuse
|
|
4851
5254
|
;;
|
|
5255
|
+
check-release-gate-outcomes)
|
|
5256
|
+
run_ts scripts/check-release-gate-outcomes.ts
|
|
5257
|
+
;;
|
|
4852
5258
|
check-acp-carrier-augment)
|
|
4853
5259
|
check_acp_carrier_augment
|
|
4854
5260
|
;;
|