@junghanacs/entwurf 0.17.2 → 0.18.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 +2 -1
- package/CHANGELOG.md +127 -0
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +14 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +76 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +9 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +11 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peer-observe.js +66 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +10 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +8 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +25 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +6 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +38 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +64 -4
- package/mcp/entwurf-bridge/src/index.ts +16 -8
- package/package.json +3 -2
- package/pi-extensions/lib/entwurf-deliverability.ts +104 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +20 -6
- package/pi-extensions/lib/entwurf-facts.ts +52 -3
- package/pi-extensions/lib/entwurf-peer-observe.ts +77 -0
- package/pi-extensions/lib/entwurf-peers-render.ts +12 -1
- package/pi-extensions/lib/entwurf-v2-decider.ts +26 -8
- package/pi-extensions/lib/entwurf-v2-production.ts +32 -12
- package/pi-extensions/lib/entwurf-v2-surface.ts +6 -0
- package/pi-extensions/lib/meta-session.ts +44 -0
- package/pi-extensions/meta-bridge-hook.ts +72 -3
- package/run.sh +21 -0
- package/scripts/check-bridge-delivery.ts +42 -1
- package/scripts/check-entwurf-fact-provider.ts +22 -1
- package/scripts/check-entwurf-facts.ts +17 -2
- package/scripts/check-entwurf-peers-surface.ts +20 -2
- package/scripts/check-entwurf-self-address.ts +20 -2
- package/scripts/check-entwurf-v2-decider.ts +6 -3
- package/scripts/check-entwurf-v2-matrix.ts +10 -5
- package/scripts/check-entwurf-v2-production.ts +72 -1
- package/scripts/check-gate-qualification.ts +1 -0
- package/scripts/check-meta-hook-session-switch.ts +560 -0
- package/scripts/meta-bridge-doctor.sh +29 -4
- package/scripts/mutants/meta-hook-session-switch.json +223 -0
- package/scripts/raw-claude-session-switch/README.md +170 -0
- package/scripts/smoke-acp-cortex-live.ts +22 -2
- package/scripts/smoke-acp-v2-send-live.ts +23 -2
- package/scripts/smoke-entwurf-chain-live.ts +85 -13
- package/scripts/smoke-entwurf-v2-matrix-live.ts +23 -1
- package/scripts/smoke-mux-fresh-call-live.ts +13 -3
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* E. Q3 + Q5 — a dead control send re-resolves (claude-code citizen) to the mailbox and
|
|
14
14
|
* enqueues through the SAME sendViaMailbox instance (same enqueue spy) on the SAME dirs
|
|
15
15
|
* the direct hand used — direct send and fallback send never drift.
|
|
16
|
+
* E4. #101 — the deliverability seam reads BOTH markers: a live receiver marker whose
|
|
17
|
+
* owner's sender marker names ANOTHER garden is undeliverable. The SAME closure serves
|
|
18
|
+
* the direct send and the dead-control fallback, so neither can be fooled alone.
|
|
16
19
|
*
|
|
17
20
|
* No real IO — every seam is a spy; the factory's COMPOSITION is what is under test.
|
|
18
21
|
*/
|
|
@@ -26,7 +29,7 @@ import {
|
|
|
26
29
|
} from "../pi-extensions/lib/entwurf-v2-production.ts";
|
|
27
30
|
import { runEntwurfV2 } from "../pi-extensions/lib/entwurf-v2-runner.ts";
|
|
28
31
|
import type { ControlSocketPlan, MetaMailboxPlan } from "../pi-extensions/lib/entwurf-v2-send.ts";
|
|
29
|
-
import type { MetaIdentity, MetaReceiverMarker } from "../pi-extensions/lib/meta-session.ts";
|
|
32
|
+
import type { MetaIdentity, MetaReceiverMarker, MetaSenderMarker } from "../pi-extensions/lib/meta-session.ts";
|
|
30
33
|
import type { NativePushAdapter, NativePushProbeResult } from "../pi-extensions/lib/native-push/adapter.ts";
|
|
31
34
|
import type { TargetSocketInspection } from "../pi-extensions/lib/socket-discovery.ts";
|
|
32
35
|
|
|
@@ -38,6 +41,8 @@ function ok(label: string, cond: boolean): void {
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
const GID = "20260613T100000-aaaaaa";
|
|
44
|
+
/** The garden a switched-away owner serves instead (#101). */
|
|
45
|
+
const OTHER_GID = "20260613T100000-bbbbbb";
|
|
41
46
|
const LOCK_DIR = "/fake/locks";
|
|
42
47
|
const SESSIONS_DIR = "/fake/sessions";
|
|
43
48
|
const MAILBOX_DIR = "/fake/mailbox";
|
|
@@ -74,6 +79,19 @@ function receiverMarker(gid: string, backend: string, nativeSessionId = "n"): Me
|
|
|
74
79
|
};
|
|
75
80
|
}
|
|
76
81
|
|
|
82
|
+
/** The receiver owner's sender marker — "which garden does this pid serve NOW?" (#101). */
|
|
83
|
+
function senderMarker(gardenId: string, backend: string, ownerPid: number): MetaSenderMarker {
|
|
84
|
+
return {
|
|
85
|
+
gardenId,
|
|
86
|
+
backend: backend as MetaSenderMarker["backend"],
|
|
87
|
+
nativeSessionId: "n",
|
|
88
|
+
cwd: "/cwd",
|
|
89
|
+
ownerPid,
|
|
90
|
+
ownerStartKey: "x",
|
|
91
|
+
updatedAt: "t",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
77
95
|
function lockClaim(gardenId = GID): LockClaim {
|
|
78
96
|
return {
|
|
79
97
|
gardenId,
|
|
@@ -133,6 +151,11 @@ function makeSpiedFactory(over: {
|
|
|
133
151
|
/** SE-2 2d-3 — the target's receiver presence marker: "active" (matches identity,
|
|
134
152
|
* default), "absent" (terminated/never-armed), or "mismatch" (drifted native id). */
|
|
135
153
|
receiverMarker?: "active" | "absent" | "mismatch";
|
|
154
|
+
/** #101 — the receiver owner's SENDER marker, i.e. which garden that pid serves NOW:
|
|
155
|
+
* "same" (still this one, default), "other-garden" (the owner switched sessions in
|
|
156
|
+
* place — a live marker whose watch is retired), or "absent" (no sender marker at all).
|
|
157
|
+
* Injected rather than defaulted so this gate never stats the operator's real roots. */
|
|
158
|
+
senderMarker?: "same" | "other-garden" | "absent";
|
|
136
159
|
}) {
|
|
137
160
|
const spies: Spies = {
|
|
138
161
|
acquire: [],
|
|
@@ -161,6 +184,10 @@ function makeSpiedFactory(over: {
|
|
|
161
184
|
const nsid = over.receiverMarker === "mismatch" ? "DRIFT" : "n";
|
|
162
185
|
return receiverMarker(gid, over.backend ?? "pi", nsid);
|
|
163
186
|
},
|
|
187
|
+
readSenderMarker: (backend, ownerPid) => {
|
|
188
|
+
if (over.senderMarker === "absent") return null;
|
|
189
|
+
return senderMarker(over.senderMarker === "other-garden" ? OTHER_GID : GID, backend, ownerPid);
|
|
190
|
+
},
|
|
164
191
|
inspectPath: async (socketPath) => {
|
|
165
192
|
spies.inspectPath.push({ socketPath });
|
|
166
193
|
if (over.inspectKind === "indeterminate") {
|
|
@@ -388,6 +415,50 @@ async function main(): Promise<void> {
|
|
|
388
415
|
ok("E3: drifted marker → enqueue NEVER called (presence ≠ identity match)", spies.enqueue.length === 0);
|
|
389
416
|
}
|
|
390
417
|
|
|
418
|
+
// ── E4: #101 — a LIVE receiver marker whose owner switched gardens. Every axis the
|
|
419
|
+
// pre-#101 seam looked at says "active": the marker exists, its owner is live, and it
|
|
420
|
+
// matches this identity exactly. Only the owner's sender marker — which garden that pid
|
|
421
|
+
// serves NOW — says the watch is retired. This is the cell where a real message was
|
|
422
|
+
// enqueued into a mailbox nobody was draining (oracle, 2026-09-04). ─────────────────
|
|
423
|
+
{
|
|
424
|
+
const { deps, spies } = makeSpiedFactory({
|
|
425
|
+
backend: "claude-code",
|
|
426
|
+
rpc: "dead-throw",
|
|
427
|
+
classifyDead: true,
|
|
428
|
+
receiverMarker: "active",
|
|
429
|
+
senderMarker: "other-garden",
|
|
430
|
+
});
|
|
431
|
+
const res = await deps.executor.sendControl(CONTROL_PLAN, lockClaim());
|
|
432
|
+
ok(
|
|
433
|
+
"E4: owner switched gardens → rejected (mailbox-undeliverable), never fallback-sent",
|
|
434
|
+
res.outcome === "rejected" && res.rejectReason === "mailbox-undeliverable",
|
|
435
|
+
);
|
|
436
|
+
ok("E4: nothing enqueued into the retired garden's mailbox", spies.enqueue.length === 0);
|
|
437
|
+
// …and the same wiring still DELIVERS when that owner is serving this garden, so the
|
|
438
|
+
// join is a measurement and not a blanket refusal.
|
|
439
|
+
const served = makeSpiedFactory({
|
|
440
|
+
backend: "claude-code",
|
|
441
|
+
rpc: "dead-throw",
|
|
442
|
+
classifyDead: true,
|
|
443
|
+
receiverMarker: "active",
|
|
444
|
+
senderMarker: "same",
|
|
445
|
+
});
|
|
446
|
+
const ok2 = await served.deps.executor.sendControl(CONTROL_PLAN, lockClaim());
|
|
447
|
+
ok("E4: the served garden still falls back to a real mailbox enqueue", ok2.outcome === "fallback-sent");
|
|
448
|
+
ok(
|
|
449
|
+
"E4: a MISSING sender marker is fail-closed, not optimistic",
|
|
450
|
+
(
|
|
451
|
+
await makeSpiedFactory({
|
|
452
|
+
backend: "claude-code",
|
|
453
|
+
rpc: "dead-throw",
|
|
454
|
+
classifyDead: true,
|
|
455
|
+
receiverMarker: "active",
|
|
456
|
+
senderMarker: "absent",
|
|
457
|
+
}).deps.executor.sendControl(CONTROL_PLAN, lockClaim())
|
|
458
|
+
).outcome === "rejected",
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
391
462
|
// ── F: #50 C4 — record-LESS control socket → pre-probe record-less-socket reject ──
|
|
392
463
|
// resolveTarget finds no meta-record, does ONE record-side lstat (inspectPath), sees a
|
|
393
464
|
// non-symlink socket → recordLessSocket. EVERY intent then rejects pre-probe as
|