@junghanacs/entwurf 0.25.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/BASELINE.md +1 -1
- package/CHANGELOG.md +182 -0
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +1 -1
- package/README.md +178 -674
- package/VERIFY.md +17 -16
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +6 -2
- package/docs/external-mcp-host.md +1 -1
- package/docs/setup-clean-host.md +346 -10
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +27 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +12 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-mailbox.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +3 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +3 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +13 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +3 -3
- package/mcp/entwurf-bridge/src/index.ts +30 -3
- package/package.json +11 -11
- package/pi-extensions/entwurf-control.ts +50 -637
- package/pi-extensions/lib/acp/backend-adapter.ts +13 -1
- package/pi-extensions/lib/entwurf-fact-provider.ts +2 -2
- package/pi-extensions/lib/entwurf-mcp-server.ts +74 -0
- package/pi-extensions/lib/entwurf-peers-render.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-decider.ts +2 -2
- package/pi-extensions/lib/entwurf-v2-mailbox.ts +2 -2
- package/pi-extensions/lib/entwurf-v2-production.ts +3 -3
- package/pi-extensions/lib/entwurf-v2-surface.ts +3 -5
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +3 -3
- package/pi-extensions/lib/fresh-call-composition.ts +13 -6
- package/pi-extensions/lib/meta-mailbox-body.ts +1 -1
- package/pi-extensions/lib/mux-fresh-call.ts +3 -3
- package/run.sh +168 -54
- package/scripts/check-entwurf-peers-surface.ts +8 -15
- package/scripts/check-entwurf-self-address.ts +7 -11
- package/scripts/check-entwurf-v2-surface.ts +20 -112
- package/scripts/check-fresh-call-dispatch.ts +12 -13
- package/scripts/check-gate-qualification.ts +2741 -157
- package/scripts/check-install-surface.ts +3 -2
- package/scripts/check-mux-resume-call.ts +24 -35
- package/scripts/check-pi-bridge-sender.ts +130 -0
- package/scripts/check-pi-mcp-bridge.ts +251 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +17 -5
- package/scripts/lib/codex-fresh-source-receipts.ts +21 -2
- package/scripts/lib/mutation-qualify.ts +269 -44
- package/scripts/lib/pi-mcp-bridge-probe.mjs +170 -0
- package/scripts/lib/qualification-acceptance.ts +146 -0
- package/scripts/lib/qualification-artifact.ts +359 -0
- package/scripts/lib/qualification-collection.ts +384 -0
- package/scripts/lib/qualification-gh.ts +231 -0
- package/scripts/lib/qualification-ledger.ts +669 -0
- package/scripts/lib/qualification-oracle-core.ts +279 -0
- package/scripts/lib/qualification-receipt.ts +561 -0
- package/scripts/lib/qualification-release.ts +271 -0
- package/scripts/meta-bridge-doctor.sh +16 -5
- package/scripts/mutants/acp-foreground-only.json +17 -0
- package/scripts/mutants/codex-native.json +11 -11
- package/scripts/mutants/control-send-receipt.json +6 -4
- package/scripts/mutants/copilot-birth.json +2 -1
- package/scripts/mutants/fresh-call-dispatch.json +3 -14
- package/scripts/mutants/gate-qualification.json +59 -0
- package/scripts/mutants/mux-fresh-call.json +43 -45
- package/scripts/mutants/mux-resume-call.json +11 -35
- package/scripts/mutants/pack-install.json +15 -4
- package/scripts/mutants/pi-bridge-sender.json +54 -0
- package/scripts/mutants/pi-floor.json +6 -2
- package/scripts/mutants/pi-mcp-bridge.json +36 -0
- package/scripts/mutants/pi-mcp-register.json +51 -0
- package/scripts/mutants/qualification-ledger.json +489 -0
- package/scripts/mutants/v2-surface.json +6 -6
- package/scripts/qualification-oracle.ts +124 -0
- package/scripts/resident-rpc-drive.ts +5 -1
- package/scripts/smoke-acp-bundled-mcp-live.ts +3 -1
- package/scripts/smoke-acp-cortex-live.ts +3 -1
- package/scripts/smoke-acp-session-reuse-live.ts +29 -12
- package/scripts/smoke-acp-socket-citizen-live.ts +3 -1
- package/scripts/smoke-acp-v2-send-live.ts +3 -1
- package/scripts/smoke-codex-fresh-live.ts +20 -1
- package/scripts/smoke-entwurf-chain-live.ts +6 -2
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -1
- package/scripts/smoke-herdr-raw-install-live.sh +8 -3
- package/scripts/smoke-mux-lifecycle-live.ts +1 -1
- package/scripts/smoke-resident-garden-guard.sh +3 -1
|
@@ -142,7 +142,7 @@ function assertRailSemantics(tag: string, longDescRaw: string, intentDescRaw: st
|
|
|
142
142
|
}
|
|
143
143
|
ok(`${tag} — mode param is isolated (non-vacuous)`, modeDesc.length > 60);
|
|
144
144
|
ok(
|
|
145
|
-
`${tag} — mode param scopes itself to a CONTROL-SOCKET send and denies the other rails [QK:V2SURF-
|
|
145
|
+
`${tag} — mode param scopes itself to a CONTROL-SOCKET send and denies the other rails [QK:V2SURF-MODE-SCOPE]`,
|
|
146
146
|
/CONTROL-SOCKET send/.test(modeDesc) && /no mode/.test(modeDesc),
|
|
147
147
|
);
|
|
148
148
|
ok(
|
|
@@ -692,39 +692,21 @@ async function main(): Promise<void> {
|
|
|
692
692
|
ok("3: surface is ctx-free — no ExtensionAPI", !code.includes("ExtensionAPI"));
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
-
// ── 4: pi-native control
|
|
695
|
+
// ── 4: pi-native control surface — the RECEIVER half, and no second caller route ──
|
|
696
|
+
// #125: the Entwurf verbs are no longer native pi tools. A pi session reaches them through Pi's
|
|
697
|
+
// built-in MCP as `mcp__entwurf_bridge__<verb>` — the SAME bridge §5 certifies — so the pi-native
|
|
698
|
+
// copies of §5's model-facing checks (rail semantics, dormant honesty, host cap, peers dead row)
|
|
699
|
+
// and the fence/senderProvider wiring they needed are retired with them, not re-proved against a
|
|
700
|
+
// file that no longer has them. What stays here is what this file still owns: the control
|
|
701
|
+
// socket's RECEIVER answer, and the absence of a second caller route.
|
|
696
702
|
{
|
|
697
703
|
const src = await fs.readFile(CONTROL_SRC, "utf8");
|
|
698
704
|
const code = src.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
699
|
-
|
|
705
|
+
// Hard Rule 1: one surface name, no dual route. A native registration of any Entwurf verb
|
|
706
|
+
// beside the MCP one would put the bare and the prefixed name in the same session.
|
|
700
707
|
ok(
|
|
701
|
-
"4: pi-native —
|
|
702
|
-
|
|
703
|
-
);
|
|
704
|
-
// The whole point of the dynamic import: NO static import of the fence v2 chain into the
|
|
705
|
-
// emit-capable root program (those literal `.ts` imports would be TS5097).
|
|
706
|
-
ok(
|
|
707
|
-
"4: pi-native — NO static import of the v2 fence (runner/production/surface) — TS5097 stays closed",
|
|
708
|
-
!/import[^;]*from\s*"\.\/lib\/entwurf-v2-(runner|production|surface)\.(js|ts)"/.test(code),
|
|
709
|
-
);
|
|
710
|
-
// SE-1 2e-a: senderProvider decorates origin:'pi-session' but `replyable` is now an
|
|
711
|
-
// HONEST fact (canonical socket existsSync via computeSelfAddressability), NOT a
|
|
712
|
-
// hardcoded true. The self-address fence lib is reached through the same non-literal
|
|
713
|
-
// dynamic import pattern as the v2 surface.
|
|
714
|
-
ok(
|
|
715
|
-
"4: pi-native — senderProvider decorates origin:'pi-session' (no hardcoded replyable:true)",
|
|
716
|
-
/origin:\s*"pi-session"/.test(code) && !/replyable:\s*true/.test(code),
|
|
717
|
-
);
|
|
718
|
-
ok(
|
|
719
|
-
"4: pi-native — replyability via computeSelfAddressability + existsSync, dynamic-imported",
|
|
720
|
-
/const ENTWURF_SELF_ADDRESS_MODULE\s*=/.test(code) &&
|
|
721
|
-
/await import\(ENTWURF_SELF_ADDRESS_MODULE\)/.test(code) &&
|
|
722
|
-
/computeSelfAddressability/.test(code) &&
|
|
723
|
-
/existsSync\(/.test(code),
|
|
724
|
-
);
|
|
725
|
-
ok(
|
|
726
|
-
"4: pi-native — NO static import of the self-address fence (TS5097 stays closed)",
|
|
727
|
-
!/import[^;]*from\s*"\.\/lib\/entwurf-self-address\.(js|ts)"/.test(code),
|
|
708
|
+
"4: pi-native — entwurf-control registers NO native tool (the verbs live on the one MCP bridge, #125)",
|
|
709
|
+
!/\bregisterTool\s*\(/.test(code) && !/name:\s*"entwurf_/.test(code),
|
|
728
710
|
);
|
|
729
711
|
// #120 P2: the RECEIVER's own answer. The sender can only render a boundary the receiver
|
|
730
712
|
// actually names, so this is the far end of the same contract — and the bare `delivered`
|
|
@@ -745,82 +727,6 @@ async function main(): Promise<void> {
|
|
|
745
727
|
);
|
|
746
728
|
})(),
|
|
747
729
|
);
|
|
748
|
-
// Every SHIPPED rail must appear in the model-facing text. Measured 2026-07-27: both
|
|
749
|
-
// surfaces described only control-socket/mailbox and told the model that an
|
|
750
|
-
// `unsupported` citizen is reached "→ mailbox" — false for Antigravity, whose native-push
|
|
751
|
-
// rail is intercepted BEFORE the mailbox mini-table and has no mailbox at all. A model
|
|
752
|
-
// reading that would pick mailbox semantics for a citizen that has none.
|
|
753
|
-
//
|
|
754
|
-
// Scope this to the registration block, NOT the whole file: the first version of this
|
|
755
|
-
// assertion swept `src`, so deleting the sentence from the description still passed on an
|
|
756
|
-
// unrelated `native-push` string elsewhere in the module. A rail-completeness claim that
|
|
757
|
-
// any import line can satisfy is not a claim.
|
|
758
|
-
const piV2Start = src.indexOf("function registerEntwurfV2Tool");
|
|
759
|
-
const piV2End = src.indexOf("\nfunction ", piV2Start + 1);
|
|
760
|
-
// Require a REAL end marker. `piV2End === -1 ? undefined : …` would silently widen the
|
|
761
|
-
// block to end-of-file and keep passing, which is the opposite of the fail-loud this
|
|
762
|
-
// scope exists for.
|
|
763
|
-
ok(
|
|
764
|
-
"4: pi-native — registration block is isolated (non-vacuous scope for the description checks)",
|
|
765
|
-
piV2Start !== -1 && piV2End > piV2Start,
|
|
766
|
-
);
|
|
767
|
-
const piV2Block = src.slice(piV2Start, piV2End);
|
|
768
|
-
ok("4: pi-native — registration block is substantial", piV2Block.length > 500);
|
|
769
|
-
// BLOCK SCOPE IS NOT ENOUGH — the two model-facing strings mask each other. Measured
|
|
770
|
-
// 2026-07-27 (round 4): the `intent` param description was corrected to split the two
|
|
771
|
-
// reject reasons while the LONG tool description still advertised the merged, false one,
|
|
772
|
-
// and this gate stayed green at 51 checks because both live in the same block and only
|
|
773
|
-
// ONE had to carry each literal. So slice them apart and require EACH to be true.
|
|
774
|
-
// The start marker MUST be unique to the long description. Measured 2026-07-27 (round 5):
|
|
775
|
-
// a bare `description:` matched the `target` PARAM first, so this "long description"
|
|
776
|
-
// slice was 4,468 chars spanning target + intent + the long text — the very masking the
|
|
777
|
-
// split was added to remove. An over-wide slice is a silent pass, so pin the exact
|
|
778
|
-
// backtick opening instead, and assert the two slices are actually disjoint.
|
|
779
|
-
const piLongDesc = sliceDescription(piV2Block, "description: `CANONICAL", "\n\t\tparameters:");
|
|
780
|
-
const piIntentDesc = sliceDescription(piV2Block, "intent: StringEnum(", "message:");
|
|
781
|
-
ok(
|
|
782
|
-
"4: pi-native — long/intent slices are disjoint (neither can satisfy the other's claim)",
|
|
783
|
-
piLongDesc.length > 0 &&
|
|
784
|
-
piIntentDesc.length > 0 &&
|
|
785
|
-
!piLongDesc.includes(piIntentDesc) &&
|
|
786
|
-
!piIntentDesc.includes(piLongDesc),
|
|
787
|
-
);
|
|
788
|
-
for (const [what, text] of [
|
|
789
|
-
["long tool description", piLongDesc],
|
|
790
|
-
["intent param description", piIntentDesc],
|
|
791
|
-
] as const) {
|
|
792
|
-
ok(`4: pi-native — ${what} is isolated (non-vacuous)`, text.length > 120);
|
|
793
|
-
ok(`4: pi-native — ${what} names the native-push rail`, /native-push/.test(text));
|
|
794
|
-
assertDormantHonesty(`4: pi-native — ${what}`, text);
|
|
795
|
-
}
|
|
796
|
-
ok("4: pi-native — long description denies native-push a mailbox", /NO mailbox/.test(piLongDesc));
|
|
797
|
-
ok(
|
|
798
|
-
"4: pi-native — long description steers live/alive peer → fire-and-forget",
|
|
799
|
-
/liveness=alive/.test(piLongDesc) && /fire-and-forget/.test(piLongDesc),
|
|
800
|
-
);
|
|
801
|
-
assertLongDescExcludesParams("4: pi-native", piLongDesc, [
|
|
802
|
-
"target: Type.String(",
|
|
803
|
-
"intent: StringEnum(",
|
|
804
|
-
"mode: Type.Optional(",
|
|
805
|
-
"wants_reply: Type.Optional(",
|
|
806
|
-
]);
|
|
807
|
-
const piModeDesc = sliceDescription(piV2Block, "mode: Type.Optional(", "wants_reply:");
|
|
808
|
-
assertRailSemantics("4: pi-native", piLongDesc, piIntentDesc, piModeDesc);
|
|
809
|
-
assertDescriptionFitsHostCap("4: pi-native", piLongDesc);
|
|
810
|
-
|
|
811
|
-
// 4b: pi-native entwurf_peers. Asserted on THIS surface too, not only the MCP one: the two
|
|
812
|
-
// descriptions are read by different callers (a resident pi model vs a sibling reaching in
|
|
813
|
-
// over MCP), and a correction that lands on one of them is a correction half the garden
|
|
814
|
-
// never sees. Same real-boundary rule as every other slice here.
|
|
815
|
-
const piPeersStart = src.indexOf('name: "entwurf_peers"');
|
|
816
|
-
const piPeersEnd = src.indexOf("parameters:", piPeersStart + 1);
|
|
817
|
-
ok(
|
|
818
|
-
"4b: pi-native — entwurf_peers description block has a REAL end boundary",
|
|
819
|
-
piPeersStart !== -1 && piPeersEnd > piPeersStart,
|
|
820
|
-
);
|
|
821
|
-
const piPeersBlock = src.slice(piPeersStart, piPeersEnd);
|
|
822
|
-
ok("4b: pi-native — entwurf_peers description is isolated (non-vacuous)", piPeersBlock.length > 200);
|
|
823
|
-
assertPeersDeadRowHonesty("4b: pi-native", piPeersBlock);
|
|
824
730
|
}
|
|
825
731
|
|
|
826
732
|
// ── 5: MCP bridge wiring guard ────────────────────────────────────────────
|
|
@@ -1052,15 +958,16 @@ async function main(): Promise<void> {
|
|
|
1052
958
|
);
|
|
1053
959
|
}
|
|
1054
960
|
|
|
1055
|
-
// ── #120 P2 (D8): the OUTCOME list in
|
|
1056
|
-
// A caller reads
|
|
961
|
+
// ── #120 P2 (D8): the OUTCOME list in the tool description names every rail ──
|
|
962
|
+
// A caller reads this blurb and nothing else before dispatching. (#125: the pi-native copy is
|
|
963
|
+
// retired with the native verbs; a pi session reads the bridge's own blurb.) The control
|
|
1057
964
|
// rail's four boundaries are the ONLY receiver-acceptance values; a mailbox answers with an
|
|
1058
965
|
// ENQUEUE receipt and native-push with an INJECTION, and folding those into the boundary union
|
|
1059
966
|
// would tell a caller that `mailbox-enqueued` is something a receiver observed about its own
|
|
1060
967
|
// queues. Missing either rail is red — the earlier draft listed `mailbox-enqueued` beside the
|
|
1061
968
|
// four and left native-push out entirely, and nothing noticed.
|
|
1062
969
|
{
|
|
1063
|
-
const outcomeSites = ["mcp/entwurf-bridge/src/index.ts"
|
|
970
|
+
const outcomeSites = ["mcp/entwurf-bridge/src/index.ts"];
|
|
1064
971
|
const missing: string[] = [];
|
|
1065
972
|
for (const rel of outcomeSites) {
|
|
1066
973
|
const text = await fs.readFile(path.join(REPO, rel), "utf8");
|
|
@@ -1080,12 +987,14 @@ async function main(): Promise<void> {
|
|
|
1080
987
|
}
|
|
1081
988
|
}
|
|
1082
989
|
ok(
|
|
1083
|
-
`[QK:SEND-OUTCOME-LIST-NAMES-EVERY-RAIL]
|
|
990
|
+
`[QK:SEND-OUTCOME-LIST-NAMES-EVERY-RAIL] the tool description names each rail's own result — the control receiver's four acceptance boundaries (and that those four are the whole union), the mailbox ENQUEUE receipt, the native-push INJECTION, a rejection, and accepted-but-lock-dirty — so a caller is never told that one rail's vocabulary describes another's (missing: ${JSON.stringify(missing)})`,
|
|
1084
991
|
missing.length === 0,
|
|
1085
992
|
);
|
|
1086
993
|
}
|
|
1087
994
|
|
|
1088
|
-
// ── #120 P2: the
|
|
995
|
+
// ── #120 P2: the caller-facing prose sites, checked for what they SAY ──
|
|
996
|
+
// (#125: three sites now — the pi-native copy left with the native verbs; a pi session reads
|
|
997
|
+
// the bridge's own `mode` text, which stays the first site below.)
|
|
1089
998
|
// `[측정 2026-09-22, pi-agent-core 0.87.0; 재측정 2026-09-23, 0.87.1 — 좌표 동일]` neither mode interrupts anything: `agent-loop.js:186`
|
|
1090
999
|
// drains steering after a turn ENDS and `:191-197` drains follow-ups only once the inner loop
|
|
1091
1000
|
// has ended. A caller who reads "interrupt the current turn" picks `steer` for urgency and gets
|
|
@@ -1099,7 +1008,6 @@ async function main(): Promise<void> {
|
|
|
1099
1008
|
{
|
|
1100
1009
|
const sites = [
|
|
1101
1010
|
"mcp/entwurf-bridge/src/index.ts",
|
|
1102
|
-
"pi-extensions/entwurf-control.ts",
|
|
1103
1011
|
"pi-extensions/lib/entwurf-v2-contract.ts",
|
|
1104
1012
|
"pi-extensions/lib/entwurf-v2-contract-schema.ts",
|
|
1105
1013
|
];
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
* FCD-HERDR-BACKEND-FIRST a non-pilot backend refuses before any preflight and any mutation
|
|
21
21
|
* FCD-CODEX-PREFLIGHT-TMUX the Codex preflight still gates the tmux rail, and only that rail
|
|
22
22
|
* FCD-ONE-NONCE one nonce is minted per call and reaches the selected rail
|
|
23
|
-
* FCD-SURFACE-
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* FCD-SURFACE-ROOT-ONLY the one public surface (the bridge; pi reaches it through Pi's
|
|
24
|
+
* built-in MCP since #125) calls the dispatcher and renderer, with
|
|
25
|
+
* no copy of the rail choice or preflight, and pi keeps no second path
|
|
26
26
|
* FCD-RENDER-PER-RAIL each rail renders its own receipt; no universal tmux prose
|
|
27
27
|
* FCD-HERDR-VIEW-NOT-ADDRESS the herdr receipt says its coordinates are a view
|
|
28
28
|
* FCD-RECOVERY-VISIBLE a post-split failure shows closed vs orphan-unreclaimed:reason
|
|
@@ -190,11 +190,16 @@ async function main(): Promise<void> {
|
|
|
190
190
|
/result: await herdrFreshCall\(/.test(dispatchCode),
|
|
191
191
|
);
|
|
192
192
|
|
|
193
|
-
// ── one composition root,
|
|
193
|
+
// ── one composition root, one public surface ─────────────────────────────────────────
|
|
194
|
+
// #125: the pi-native fresh-call copy is retired — a pi session reaches the bridge's through Pi's
|
|
195
|
+
// built-in MCP — so the claim is no longer parity between two copies. It is that the ONE
|
|
196
|
+
// surface reaches the root without carrying rail choice, preflight or render of its own, and
|
|
197
|
+
// that the pi extension did not keep a second path to the root beside it.
|
|
194
198
|
ok(
|
|
195
|
-
"[QK:FCD-SURFACE-
|
|
196
|
-
PI_SRC.includes("dispatchFreshCall(") &&
|
|
197
|
-
PI_SRC.includes("renderDispatchedFreshCall(") &&
|
|
199
|
+
"[QK:FCD-SURFACE-ROOT-ONLY] the bridge reaches the dispatcher and its renderer and carries no rail choice, Codex preflight or rail-specific render of its own; the pi extension carries no fresh-call path at all",
|
|
200
|
+
!PI_SRC.includes("dispatchFreshCall(") &&
|
|
201
|
+
!PI_SRC.includes("renderDispatchedFreshCall(") &&
|
|
202
|
+
!PI_SRC.includes("fresh-call-dispatch") &&
|
|
198
203
|
MCP_SRC.includes("dispatchFreshCall({") &&
|
|
199
204
|
MCP_SRC.includes("renderDispatchedFreshCall(") &&
|
|
200
205
|
// Both DESCRIBE the rule to callers ("inside herdr (HERDR_ENV=1)…") and must keep
|
|
@@ -206,12 +211,6 @@ async function main(): Promise<void> {
|
|
|
206
211
|
!MCP_SRC.includes("renderHerdrFreshCall") &&
|
|
207
212
|
!PI_SRC.includes("renderHerdrFreshCall"),
|
|
208
213
|
);
|
|
209
|
-
ok(
|
|
210
|
-
"[QK:FCD-PI-DYNAMIC-IMPORT] pi still reaches the composition root through its LAZY dynamic import — a static import would pull the rails into pi's startup path, which is the fence that keeps extension load cheap",
|
|
211
|
-
/const FRESH_CALL_DISPATCH_MODULE = "\.\/lib\/fresh-call-dispatch\.ts";/.test(PI_SRC) &&
|
|
212
|
-
PI_SRC.includes("await import(FRESH_CALL_DISPATCH_MODULE)") &&
|
|
213
|
-
!/^import .*fresh-call-dispatch/m.test(PI_SRC),
|
|
214
|
-
);
|
|
215
214
|
|
|
216
215
|
// ── rendering stays rail-honest ──────────────────────────────────────────────────────
|
|
217
216
|
const herdrRefusal = renderDispatchedFreshCall({
|