@junghanacs/entwurf 0.12.10 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +2 -1
  2. package/BASELINE.md +45 -6
  3. package/CHANGELOG.md +16 -0
  4. package/CONTRIBUTING.md +4 -2
  5. package/DELIVERY.md +1 -1
  6. package/README.md +20 -5
  7. package/VERIFY.md +7 -4
  8. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +148 -5
  9. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +16 -4
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +66 -7
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +190 -5
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +12 -4
  13. package/package.json +4 -2
  14. package/pi/settings.reference.json +1 -1
  15. package/pi-extensions/acp-provider.ts +20 -10
  16. package/pi-extensions/lib/acp/augment.ts +60 -2
  17. package/pi-extensions/lib/acp/backend-adapter.ts +183 -8
  18. package/pi-extensions/lib/acp/backend.ts +5 -1
  19. package/pi-extensions/lib/acp/config.ts +19 -5
  20. package/pi-extensions/lib/acp/engraving.ts +3 -1
  21. package/pi-extensions/lib/acp/event-mapper.ts +10 -3
  22. package/pi-extensions/lib/acp/models.ts +69 -7
  23. package/pi-extensions/lib/acp/overlay.ts +234 -5
  24. package/pi-extensions/lib/acp/tool-surface.ts +12 -4
  25. package/run.sh +152 -21
  26. package/scripts/check-acp-cortex.ts +668 -0
  27. package/scripts/check-acp-provider-surface.ts +50 -6
  28. package/scripts/check-acp-session-reuse.ts +64 -1
  29. package/scripts/check-gate-qualification.ts +2 -0
  30. package/scripts/check-probe-cli-shim.ts +879 -0
  31. package/scripts/check-probe-ordering.ts +2450 -0
  32. package/scripts/check-shell-quote.ts +4 -4
  33. package/scripts/fixtures/probe-cli-shim +20 -0
  34. package/scripts/fixtures/probe-mcp-server.ts +168 -12
  35. package/scripts/lib/probe-acp-turn.ts +207 -0
  36. package/scripts/lib/probe-cli-shim.ts +464 -0
  37. package/scripts/lib/probe-cli-target.ts +165 -0
  38. package/scripts/lib/probe-event-log.ts +383 -0
  39. package/scripts/lib/probe-verdict.ts +1213 -0
  40. package/scripts/mutants/acp-cortex.json +196 -0
  41. package/scripts/mutants/probe-ordering.json +1032 -0
  42. package/scripts/smoke-acp-cortex-live.ts +392 -0
  43. package/scripts/smoke-acp-ordering-probe-live.ts +848 -0
package/run.sh CHANGED
@@ -130,6 +130,8 @@ Usage:
130
130
  ./run.sh smoke-agy-install-state # agy MCP + exact permission ownership regression: isolated HOME+XDG, adopt/state/inverse, symlink refuse, setup degrade. Offline/deterministic
131
131
  ./run.sh check-agy-permission-matrix # AGY permission CONTRACT SPACE as a literal table (55 cells): parser-state × operation × settings × ownership × precedence with stated exclusion rules; expectations are hand-written literals, never read from the SUT. Offline/deterministic (deps: python3)
132
132
  ./run.sh check-gate-qualification # kill-proof qualification (the gate-of-gates): runner self-test (classifier truth table + synthetic negatives incl. wrong-reason/hang/control-red/impurity) + committed mutant manifests (scripts/mutants/*.json) run in an isolated snapshot repo under control→mutant→restore→control; the real checkout is never written. Evidence = claim IDs + killed mutant IDs, never assertion counts
133
+ ./run.sh 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; kill-proofed via scripts/mutants/probe-ordering.json
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; kill-proofed via scripts/mutants/probe-ordering.json
133
135
  ./run.sh smoke-agy-statusline-state # agy ambient garden-id statusLine install/doctor/inverse regression. Offline/deterministic
134
136
  ./run.sh smoke-agy-hooks-state # agy PreInvocation birth/sender hook install/doctor/inverse + direct stdin→meta-record regression. Offline/deterministic
135
137
  ./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)
@@ -1177,6 +1179,40 @@ smoke_acp_rgg_live() {
1177
1179
  (cd "$REPO_DIR" && ENTWURF_LIVE_TARGET="$target" SMOKE_RGG_POSITIVE=0 bash scripts/smoke-resident-garden-guard.sh)
1178
1180
  }
1179
1181
 
1182
+ smoke_acp_cortex_live() {
1183
+ # 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 §6). OUT of
1185
+ # `pnpm check` AND OUTSIDE the claude-only aggregate LIVE floor (capability
1186
+ # dignity, invariant #7): a host with no cortex install / no Snowflake auth must
1187
+ # not redden a release for a backend it does not run, so this is deliberately
1188
+ # absent from release-gate's 11-smoke ACP acceptance floor. That is a WIRING
1189
+ # decision, not a lower evidence bar — a cut that SHIPS cortex still owes a
1190
+ # deliberate run of this smoke, and the aggregate gate's silence is not a pass
1191
+ # (rail §11-8 tail). Drives one real
1192
+ # cortex ACP turn through the entwurf provider path (outbound entwurf_v2 +
1193
+ # dual-HOME overlay facts + process-group reclaim — CP2, rail §11-8).
1194
+ # HONEST-SKIP (exit 0) when LIVE!=1 OR `cortex` is not on PATH OR no
1195
+ # connection is pinned — the live turn needs `cortex` installed with the
1196
+ # operator's own web-login auth already present (there is no `cortex auth`
1197
+ # subcommand — CP0 D6), reached through the overlay's narrow credential
1198
+ # symlinks — narrow in WHICH paths are reachable (D5), not read-only: a symlink
1199
+ # carries no write protection (AGENTS §ACP Plugin Boundary: entwurf never
1200
+ # provides/proxies the Snowflake credential). The connection must ride the adapter seam
1201
+ # (ENTWURF_ACP_CORTEX_CONNECTION) because the dual-HOME overlay denies the
1202
+ # operator settings.json where a default would live. PR #40 called this
1203
+ # `smoke-cortex`; the canonical family name is smoke-acp-cortex-live.
1204
+ # LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live
1205
+ if [ "${LIVE:-}" != "1" ]; then
1206
+ echo "[smoke-acp-cortex-live] skipped — set LIVE=1 (+ ENTWURF_ACP_CORTEX_CONNECTION) to run."
1207
+ return 0
1208
+ fi
1209
+ if ! command -v cortex >/dev/null 2>&1; then
1210
+ echo "[smoke-acp-cortex-live] skipped — cortex not on PATH (install Snowflake Cortex Code and complete its own login flow)."
1211
+ return 0
1212
+ fi
1213
+ run_ts scripts/smoke-acp-cortex-live.ts
1214
+ }
1215
+
1180
1216
  smoke_entwurf_v2_matrix_live() {
1181
1217
  # LIVE sentinel for 0.11 Stage 0 step 5d-5 (D4-b) — kept OUT of `pnpm check`. The deterministic
1182
1218
  # sibling (check-entwurf-v2-matrix) fixes every (target kind → transport → lock) cell over fakes
@@ -2211,12 +2247,16 @@ EOF
2211
2247
  }
2212
2248
 
2213
2249
  check_acp_provider_surface() {
2214
- # Deterministic gate for the S0 ACP provider loader/fence slice. Loads the REAL
2215
- # provider lib modules and asserts the registration surface: one surface name,
2216
- # curated Claude anchor present with full ProviderModelConfig rows, no-auth
2217
- # sentinel shape, and a FAIL-LOUD streamSimple (calling it throws no native
2218
- # fallback, no empty-but-successful stream). Pure, no pi runtime, no API.
2219
- section "ACP provider surface (S0 loader/fence)"
2250
+ # Deterministic gate for the ACP provider registration surface. Loads the REAL
2251
+ # provider lib modules AND compiles + drives the REAL entry against a fake pi,
2252
+ # asserting: one surface name, the no-auth sentinel shape, full
2253
+ # ProviderModelConfig rows on the curated claude anchor, the EXACT curated model
2254
+ # set both adapters contribute (claude 2 + cortex 4
2255
+ # [QK:CORTEX-PROVIDER-SIX-ROW-SURFACE], the claim that catches an entry which
2256
+ # silently drops a whole backend), and that streamSimple is the real
2257
+ # streamShellAcp backend (checked BY NAME, never invoked — invoking spawns an
2258
+ # ACP child). Pure, no pi runtime, no API.
2259
+ section "ACP provider surface (registration + both-adapter model set)"
2220
2260
  run_ts scripts/check-acp-provider-surface.ts
2221
2261
  }
2222
2262
 
@@ -2340,6 +2380,33 @@ check_acp_carrier_augment() {
2340
2380
  run_ts scripts/check-acp-carrier-augment.ts
2341
2381
  }
2342
2382
 
2383
+ check_acp_cortex() {
2384
+ # Deterministic gate for the Cortex (Snowflake Cortex Code) ACP backend — the
2385
+ # first non-claude adapter on the rail, landed 0.13.0 on the CP0-measured
2386
+ # contract (docs/acp-backend-rail.md §4/§6/§11-8). The cortex source is one
2387
+ # `cortexAdapter` object (backend-adapter.ts) + its curated surface (models.ts)
2388
+ # + the dual-HOME overlay (overlay.ts); the 결합 규칙 requires the gate to land
2389
+ # WITH it, and §6 said EXTEND the check-acp-* family, so cortex's whole
2390
+ # deterministic axis lives here. Locks (each §11-8 D-pinned): the GLG-decided
2391
+ # 4-row curation rides real registry bases and the `cortex-` prefix routes to
2392
+ # cortexAdapter; launch is `cortex acp serve` with NO -m — the model is
2393
+ # enforced per turn via session/set_config_option with the native id (E);
2394
+ # CORTEX_HOME presence (empty included) refuses the spawn (D3); the dual-HOME
2395
+ # overlay isolates HOME+SNOWFLAKE_HOME per session key (P0-1: scope =
2396
+ # backend-passed resolveSessionKey, never ambient), passes through only
2397
+ # connections.toml / optional config.toml / credential_cache (D5/F — never the
2398
+ # whole cache, never skills; symlink-through, no copies — AGENTS §ACP Plugin
2399
+ # Boundary), authors autoUpdate:false (D4), and projects envelope-enriched
2400
+ # explicit servers into cortex/mcp.json with the real HOME restored on
2401
+ # entwurf-bridge alone (D9/D10), non-stdio failing loud; the
2402
+ # CORTEX_ACP_COMMAND override single-quotes shell-metachar connection tokens.
2403
+ # The gate self-manages the tsc-emit layer for the .js-suffixed backend-adapter
2404
+ # imports; no auth, no spawn, no live cortex needed. Kill-qualified via the
2405
+ # `acp-cortex` mutant lane under check-gate-qualification.
2406
+ section "ACP cortex backend (Snowflake Cortex Code — 1st non-claude adapter)"
2407
+ run_ts scripts/check-acp-cortex.ts
2408
+ }
2409
+
2343
2410
  check_pack() {
2344
2411
  # Dry-run tarball invariant gate for the public npm surface.
2345
2412
  #
@@ -2824,18 +2891,45 @@ _check_pack_install_impl() {
2824
2891
  echo "$loader_out" | tail -10 | sed 's/^/ /' >&2
2825
2892
  return 1
2826
2893
  fi
2827
- # Verify the full curated Claude surface is visible: the Sonnet row AND the
2828
- # opus anchor (CURATED_ANCHOR_MODEL_ID in lib/acp/models.ts the model whose
2829
- # absence is a hard registry regression). Checking only one would let half the
2830
- # surface drop silently.
2831
- for anchor in "claude-sonnet-5" "claude-opus-5"; do
2832
- if ! grep -q "$anchor" <<<"$loader_out"; then
2833
- fail "[check-pack-install] pi loader output missing curated Claude model $anchor:"
2834
- echo "$loader_out" | tail -10 | sed 's/^/ /' >&2
2835
- return 1
2836
- fi
2837
- done
2838
- echo "[check-pack-install] pi loader smoke pass (entwurf registered, claude-sonnet-5 + claude-opus-5 anchor)"
2894
+ # Verify the EXACT curated surface the installed package registers both
2895
+ # backends (claude 2 rows + cortex 4 rows = 6), as a SET, not as anchors.
2896
+ #
2897
+ # Why exact-set and not `grep -q <id>`: the cortex ids CONTAIN the claude ids
2898
+ # as substrings (`cortex-claude-sonnet-5` matches a bare `claude-sonnet-5`
2899
+ # grep), so a substring probe could go green on a surface that dropped every
2900
+ # unprefixed Claude row. And an anchor-only probe cannot see a MISSING cortex
2901
+ # row at all — that is exactly the installed-consumer gap this assertion
2902
+ # closes: the source-side sets are pinned by check-acp-cortex /
2903
+ # check-acp-provider-surface, but only THIS gate proves the ids survive the
2904
+ # pack → install → pi-loader path into a real consumer's model list.
2905
+ #
2906
+ # Parse rows whose FIRST field is the provider `entwurf` (pi prints a
2907
+ # `provider model context …` table; the header row's first field is
2908
+ # `provider`, so it drops out) and take the second field as the model id.
2909
+ local loader_ids loader_expected
2910
+ loader_ids=$(awk '$1 == "entwurf" { print $2 }' <<<"$loader_out" | LC_ALL=C sort)
2911
+ loader_expected=$(printf '%s\n' \
2912
+ claude-opus-5 \
2913
+ claude-sonnet-5 \
2914
+ cortex-auto \
2915
+ cortex-claude-opus-5 \
2916
+ cortex-claude-sonnet-5 \
2917
+ cortex-openai-gpt-5.4 | LC_ALL=C sort)
2918
+ if [ "$loader_ids" != "$loader_expected" ]; then
2919
+ fail "[check-pack-install] installed provider model set drifted — expected exactly 6 curated ids (claude 2 + cortex 4):"
2920
+ echo " expected:" >&2
2921
+ echo "$loader_expected" | sed 's/^/ /' >&2
2922
+ echo " actual (entwurf rows):" >&2
2923
+ echo "${loader_ids:-<none>}" | sed 's/^/ /' >&2
2924
+ echo " raw loader output:" >&2
2925
+ echo "$loader_out" | tail -15 | sed 's/^/ /' >&2
2926
+ return 1
2927
+ fi
2928
+ # Name the set on SUCCESS too, not only in the failure branch — same principle as
2929
+ # the pinned-pi version assert above: a gate that cannot name what it proved has
2930
+ # proved nothing, and "6 rows" without the ids cannot be audited from a CI log.
2931
+ echo "[check-pack-install] pi loader smoke pass (entwurf registered; exact 6-row curated set: claude 2 + cortex 4):"
2932
+ echo "$loader_ids" | sed 's/^/ /'
2839
2933
 
2840
2934
  # npm-managed neutral install regression — the README's PRIMARY install path is
2841
2935
  # now `npm install @junghanacs/entwurf` (NOT `pi install npm:...`). This layout
@@ -3727,7 +3821,7 @@ wire_agy_bridge() {
3727
3821
  # whatever agy the CI/dev host happens to have — production leaves it unset (= `command -v
3728
3822
  # agy`, no regression). Same override spirit as agy-bridge.sh's AGY_MCP_CONFIG/AGY_BRIDGE_COMMAND.
3729
3823
  if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
3730
- echo "[setup] no agy on PATH — skipping agy bridge wiring (no state; pi/Claude-only host)"
3824
+ echo "[setup] no agy on PATH — skipping agy bridge wiring (no state; this host runs no Antigravity)"
3731
3825
  return 0
3732
3826
  fi
3733
3827
  section "agy bridge install (native harness detected: Antigravity)"
@@ -3780,7 +3874,7 @@ wire_agy_bridge() {
3780
3874
  # stable bin entwurf-agy-statusline, exposed by expose_dev_bin above.
3781
3875
  wire_agy_statusline() {
3782
3876
  if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
3783
- echo "[setup] no agy on PATH — skipping agy statusLine wiring (no state; pi/Claude-only host)"
3877
+ echo "[setup] no agy on PATH — skipping agy statusLine wiring (no state; this host runs no Antigravity)"
3784
3878
  return 0
3785
3879
  fi
3786
3880
  section "agy statusLine install (native harness detected: Antigravity)"
@@ -3818,7 +3912,7 @@ wire_agy_statusline() {
3818
3912
  # garden id after the first invocation.
3819
3913
  wire_agy_hooks() {
3820
3914
  if ! command -v "${AGY_BIN:-agy}" >/dev/null 2>&1; then
3821
- echo "[setup] no agy on PATH — skipping agy hooks wiring (no state; pi/Claude-only host)"
3915
+ echo "[setup] no agy on PATH — skipping agy hooks wiring (no state; this host runs no Antigravity)"
3822
3916
  return 0
3823
3917
  fi
3824
3918
  section "agy hooks install (native harness detected: Antigravity)"
@@ -4320,6 +4414,9 @@ case "$cmd" in
4320
4414
  smoke-acp-rgg-live)
4321
4415
  smoke_acp_rgg_live
4322
4416
  ;;
4417
+ smoke-acp-cortex-live)
4418
+ smoke_acp_cortex_live
4419
+ ;;
4323
4420
  smoke-acp-socket-citizen-live)
4324
4421
  smoke_acp_socket_citizen_live
4325
4422
  ;;
@@ -4452,6 +4549,37 @@ case "$cmd" in
4452
4549
  # control-red/impurity all must classify red before any real manifest counts.
4453
4550
  run_ts scripts/check-gate-qualification.ts
4454
4551
  ;;
4552
+ check-probe-ordering)
4553
+ # §11-7 ordering-probe gate (docs/acp-backend-rail.md §11-7): the raw-client seam is
4554
+ # only admissible "bound by a gate asserting it issues the same calls, arguments, and
4555
+ # order as the backend's real sequence" — this is that gate. Sameness over a recording
4556
+ # fake + backend.ts SOURCE pins (order/clientInfo/timeouts/permission policy), phase
4557
+ # attribution (set-model included), the probe-mode fixture's wire instrumentation
4558
+ # (real child, raw JSON-RPC, no API), the shared log's contract at its door — envelope
4559
+ # (the evidence line's own runId/marker/sort axis cannot be rewritten by a payload) AND
4560
+ # payload (every field the classifier judges on is typed there) — and the PURE
4561
+ # paired-verdict truth table.
4562
+ run_ts scripts/check-probe-ordering.ts
4563
+ ;;
4564
+ check-probe-cli-shim)
4565
+ # §11-7-c producer gate (docs/acp-backend-rail.md §11-7-c condition 5: "Byte-transparency,
4566
+ # backpressure, and exit/signal propagation are proved by a fake-CLI deterministic gate").
4567
+ # The shim sits on the production spawn path of a paid LIVE turn, so this drives it as a
4568
+ # REAL process against fake CLIs and asks what each defect would buy: fabricated absence
4569
+ # evidence (a malformed init reported as an empty name set, a boot report that does not
4570
+ # name what was actually exec'd), a destroyed turn (mangled bytes, a swallowed signal, a
4571
+ # crash reported as exit 0), or leaked operator state (a prefix env scrub, argv/env/prompt
4572
+ # body in the shared log). No API, no network, no cost.
4573
+ run_ts scripts/check-probe-cli-shim.ts
4574
+ ;;
4575
+ smoke-acp-ordering-probe-live)
4576
+ # §11-7 ordering probe — LIVE paired-run instrument, OUT of pnpm check. Control
4577
+ # (delay=0, must be visible AND callable) + interventions D1/D2 against the SAME
4578
+ # pins/config/fixture; classifies A/A-withheld/B/C/D-<phase> or P0/I0, preserves
4579
+ # the shared NDJSON log + classification under .probe-artifacts/ (gitignored).
4580
+ # LIVE=1 ./run.sh smoke-acp-ordering-probe-live
4581
+ run_ts scripts/smoke-acp-ordering-probe-live.ts
4582
+ ;;
4455
4583
  smoke-agy-statusline-state)
4456
4584
  # #46 Task 1 regression gate for the agy statusLine install adapter: install→doctor→uninstall
4457
4585
  # in an ISOLATED HOME+XDG with a fake stable bin (entwurf-agy-statusline) + fake pgrep —
@@ -4724,6 +4852,9 @@ case "$cmd" in
4724
4852
  check-acp-carrier-augment)
4725
4853
  check_acp_carrier_augment
4726
4854
  ;;
4855
+ check-acp-cortex)
4856
+ check_acp_cortex
4857
+ ;;
4727
4858
  check-fresh-cut-gate)
4728
4859
  # SOURCE cell of the generation-boundary proof: a host whose store the live
4729
4860
  # schema cannot read must be refused BEFORE any write, told the fresh-cut