@cello-protocol/daemon 0.0.52 → 0.0.54
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/dist/agent-handlers.d.ts +57 -0
- package/dist/agent-handlers.d.ts.map +1 -0
- package/dist/agent-handlers.js +360 -0
- package/dist/agent-handlers.js.map +1 -0
- package/dist/agent-id-migration.d.ts.map +1 -1
- package/dist/agent-id-migration.js +1 -0
- package/dist/agent-id-migration.js.map +1 -1
- package/dist/agent-loader.d.ts +3 -4
- package/dist/agent-loader.d.ts.map +1 -1
- package/dist/agent-loader.js +3 -4
- package/dist/agent-loader.js.map +1 -1
- package/dist/cbor-blob-migration.d.ts +8 -0
- package/dist/cbor-blob-migration.d.ts.map +1 -0
- package/dist/cbor-blob-migration.js +115 -0
- package/dist/cbor-blob-migration.js.map +1 -0
- package/dist/close-session-handler.d.ts +41 -0
- package/dist/close-session-handler.d.ts.map +1 -0
- package/dist/close-session-handler.js +399 -0
- package/dist/close-session-handler.js.map +1 -0
- package/dist/consortium-bootstrap.d.ts +83 -0
- package/dist/consortium-bootstrap.d.ts.map +1 -0
- package/dist/consortium-bootstrap.js +120 -0
- package/dist/consortium-bootstrap.js.map +1 -0
- package/dist/contact-handlers.d.ts +56 -0
- package/dist/contact-handlers.d.ts.map +1 -0
- package/dist/contact-handlers.js +303 -0
- package/dist/contact-handlers.js.map +1 -0
- package/dist/content-park-client.d.ts.map +1 -1
- package/dist/content-park-client.js +7 -7
- package/dist/content-park-client.js.map +1 -1
- package/dist/content-park.d.ts +15 -0
- package/dist/content-park.d.ts.map +1 -0
- package/dist/content-park.js +227 -0
- package/dist/content-park.js.map +1 -0
- package/dist/daemon.d.ts +0 -11
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +407 -4552
- package/dist/daemon.js.map +1 -1
- package/dist/db-identity-store.d.ts +31 -35
- package/dist/db-identity-store.d.ts.map +1 -1
- package/dist/db-identity-store.js +62 -66
- package/dist/db-identity-store.js.map +1 -1
- package/dist/directory-bootstrap.d.ts +27 -31
- package/dist/directory-bootstrap.d.ts.map +1 -1
- package/dist/directory-bootstrap.js +18 -21
- package/dist/directory-bootstrap.js.map +1 -1
- package/dist/frame-values.d.ts +3 -0
- package/dist/frame-values.d.ts.map +1 -0
- package/dist/frame-values.js +73 -0
- package/dist/frame-values.js.map +1 -0
- package/dist/identity-migration.d.ts +8 -8
- package/dist/identity-migration.d.ts.map +1 -1
- package/dist/identity-migration.js +30 -31
- package/dist/identity-migration.js.map +1 -1
- package/dist/inbound-seal-request.d.ts +17 -0
- package/dist/inbound-seal-request.d.ts.map +1 -0
- package/dist/inbound-seal-request.js +155 -0
- package/dist/inbound-seal-request.js.map +1 -0
- package/dist/inbound-sessions.d.ts +54 -0
- package/dist/inbound-sessions.d.ts.map +1 -0
- package/dist/inbound-sessions.js +603 -0
- package/dist/inbound-sessions.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -10
- package/dist/index.js.map +1 -1
- package/dist/initiate-session-handler.d.ts +22 -0
- package/dist/initiate-session-handler.d.ts.map +1 -0
- package/dist/initiate-session-handler.js +150 -0
- package/dist/initiate-session-handler.js.map +1 -0
- package/dist/network-directory-node.d.ts +6 -6
- package/dist/network-directory-node.d.ts.map +1 -1
- package/dist/network-directory-node.js +29 -28
- package/dist/network-directory-node.js.map +1 -1
- package/dist/notification-handlers.d.ts +32 -0
- package/dist/notification-handlers.d.ts.map +1 -0
- package/dist/notification-handlers.js +73 -0
- package/dist/notification-handlers.js.map +1 -0
- package/dist/outbound-sessions.d.ts +54 -0
- package/dist/outbound-sessions.d.ts.map +1 -0
- package/dist/outbound-sessions.js +429 -0
- package/dist/outbound-sessions.js.map +1 -0
- package/dist/park-envelope.d.ts.map +1 -1
- package/dist/park-envelope.js +3 -2
- package/dist/park-envelope.js.map +1 -1
- package/dist/register-handler.d.ts +35 -0
- package/dist/register-handler.d.ts.map +1 -0
- package/dist/register-handler.js +179 -0
- package/dist/register-handler.js.map +1 -0
- package/dist/registration-manager.d.ts.map +1 -1
- package/dist/registration-manager.js +3 -6
- package/dist/registration-manager.js.map +1 -1
- package/dist/relay-receipt-store.d.ts.map +1 -1
- package/dist/relay-receipt-store.js +1 -2
- package/dist/relay-receipt-store.js.map +1 -1
- package/dist/retry-queue.d.ts +18 -60
- package/dist/retry-queue.d.ts.map +1 -1
- package/dist/retry-queue.js +46 -97
- package/dist/retry-queue.js.map +1 -1
- package/dist/seal-coordinator.d.ts +47 -0
- package/dist/seal-coordinator.d.ts.map +1 -0
- package/dist/seal-coordinator.js +551 -0
- package/dist/seal-coordinator.js.map +1 -0
- package/dist/seal-flows.d.ts +50 -0
- package/dist/seal-flows.d.ts.map +1 -0
- package/dist/seal-flows.js +454 -0
- package/dist/seal-flows.js.map +1 -0
- package/dist/seal-frontier-verify.d.ts +9 -9
- package/dist/seal-frontier-verify.d.ts.map +1 -1
- package/dist/seal-frontier-verify.js +11 -12
- package/dist/seal-frontier-verify.js.map +1 -1
- package/dist/seal-leaf.d.ts +58 -0
- package/dist/seal-leaf.d.ts.map +1 -0
- package/dist/seal-leaf.js +111 -0
- package/dist/seal-leaf.js.map +1 -0
- package/dist/seal-receipt-upgrade.d.ts +1 -1
- package/dist/seal-receipt-upgrade.js +1 -1
- package/dist/seal-upgrade.d.ts +10 -10
- package/dist/seal-upgrade.d.ts.map +1 -1
- package/dist/seal-upgrade.js +23 -24
- package/dist/seal-upgrade.js.map +1 -1
- package/dist/session-assignment-parser.d.ts +16 -19
- package/dist/session-assignment-parser.d.ts.map +1 -1
- package/dist/session-assignment-parser.js +30 -29
- package/dist/session-assignment-parser.js.map +1 -1
- package/dist/session-ceremony.d.ts +3 -6
- package/dist/session-ceremony.d.ts.map +1 -1
- package/dist/session-ceremony.js +7 -9
- package/dist/session-ceremony.js.map +1 -1
- package/dist/session-content-handlers.d.ts +25 -0
- package/dist/session-content-handlers.d.ts.map +1 -0
- package/dist/session-content-handlers.js +436 -0
- package/dist/session-content-handlers.js.map +1 -0
- package/dist/session-name.d.ts +35 -0
- package/dist/session-name.d.ts.map +1 -0
- package/dist/session-name.js +60 -0
- package/dist/session-name.js.map +1 -0
- package/dist/session-node-manager.d.ts +26 -62
- package/dist/session-node-manager.d.ts.map +1 -1
- package/dist/session-node-manager.js +115 -92
- package/dist/session-node-manager.js.map +1 -1
- package/dist/session-read-handlers.d.ts +38 -0
- package/dist/session-read-handlers.d.ts.map +1 -0
- package/dist/session-read-handlers.js +233 -0
- package/dist/session-read-handlers.js.map +1 -0
- package/dist/session-relay-client.d.ts +8 -8
- package/dist/session-relay-client.d.ts.map +1 -1
- package/dist/session-relay-client.js +44 -46
- package/dist/session-relay-client.js.map +1 -1
- package/dist/session-tree.d.ts +11 -23
- package/dist/session-tree.d.ts.map +1 -1
- package/dist/session-tree.js +14 -26
- package/dist/session-tree.js.map +1 -1
- package/dist/signaling-connect.d.ts +2 -5
- package/dist/signaling-connect.d.ts.map +1 -1
- package/dist/signaling-connect.js +7 -12
- package/dist/signaling-connect.js.map +1 -1
- package/dist/sqlcipher-db.d.ts +18 -19
- package/dist/sqlcipher-db.d.ts.map +1 -1
- package/dist/sqlcipher-db.js +30 -30
- package/dist/sqlcipher-db.js.map +1 -1
- package/dist/telegram-doorbell.d.ts +38 -0
- package/dist/telegram-doorbell.d.ts.map +1 -0
- package/dist/telegram-doorbell.js +139 -0
- package/dist/telegram-doorbell.js.map +1 -0
- package/dist/types.d.ts +86 -79
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -1
- package/dist/types.js.map +1 -1
- package/dist/vocabulary.d.ts +30 -30
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +41 -49
- package/dist/vocabulary.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SignalingManager } from "@cello-protocol/transport";
|
|
2
|
+
import type { KeyProvider } from "@cello-protocol/crypto";
|
|
3
|
+
import type { SessionNodeManager } from "./session-node-manager.js";
|
|
4
|
+
import type { AgentInfo, Logger } from "./types.js";
|
|
5
|
+
export type SealFlowResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
status: "seal_interrupted_pending";
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
reason: string;
|
|
12
|
+
guidance: string;
|
|
13
|
+
};
|
|
14
|
+
export type ActiveSealResult = {
|
|
15
|
+
ok: true;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
status: "seal_interrupted_pending";
|
|
18
|
+
rootHex: string;
|
|
19
|
+
} | {
|
|
20
|
+
ok: false;
|
|
21
|
+
reason: string;
|
|
22
|
+
guidance: string;
|
|
23
|
+
};
|
|
24
|
+
export interface SealFlowDeps {
|
|
25
|
+
logger: Logger;
|
|
26
|
+
sessionNodeManager: SessionNodeManager;
|
|
27
|
+
agents: AgentInfo[];
|
|
28
|
+
getKeyProvider: (agentName: string) => KeyProvider | undefined;
|
|
29
|
+
/** This agent's directory signaling stream, or undefined if it has none. */
|
|
30
|
+
signalingFor: (agentName: string) => SignalingManager | undefined;
|
|
31
|
+
sendOver: (agentName: string, frame: Record<string, unknown>) => Promise<{
|
|
32
|
+
ok: boolean;
|
|
33
|
+
reason?: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare function createSealFlows(deps: SealFlowDeps): {
|
|
37
|
+
awaitSealAck: (sessionId: string, mgr: SignalingManager | undefined) => Promise<{
|
|
38
|
+
type: "seal_interrupted_ack";
|
|
39
|
+
sealInterruptedLeaf: Record<string, unknown>;
|
|
40
|
+
nonce: string | null;
|
|
41
|
+
} | {
|
|
42
|
+
type: "seal_interrupted_rejection";
|
|
43
|
+
reason: string;
|
|
44
|
+
} | {
|
|
45
|
+
type: "timeout";
|
|
46
|
+
}>;
|
|
47
|
+
handleSealInterruptedFlow: (sessionId: string, record: import("./types.js").SessionRecord, correlationId: string, merkleRootAtInterruption: string) => Promise<SealFlowResult>;
|
|
48
|
+
handleActiveSealFlow: (sessionId: string, record: import("./types.js").SessionRecord, correlationId: string) => Promise<ActiveSealResult>;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=seal-flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal-flows.d.ts","sourceRoot":"","sources":["../src/seal-flows.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,0BAA0B,CAAA;CAAE,GACnE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,0BAA0B,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;IAC/D,4EAA4E;IAC5E,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,gBAAgB,GAAG,SAAS,CAAC;IAClE,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC5G;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY;8BAyCf,MAAM,OAAO,gBAAgB,GAAG,SAAS,KAAG,OAAO;cAJxE,sBAAsB;6BAAuB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;eAAS,MAAM,GAAG,IAAI;;cAC1F,4BAA4B;gBAAU,MAAM;;cAC5C,SAAS;MAE8E;2CAmCtF,MAAM,UACT,OAAO,YAAY,EAAE,aAAa,iBAC3B,MAAM,4BACK,MAAM,KAC/B,OAAO,CAAC,cAAc,CAAC;sCA4Nb,MAAM,UACT,OAAO,YAAY,EAAE,aAAa,iBAC3B,MAAM,KACpB,OAAO,CAAC,gBAAgB,CAAC;EA+K7B"}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two seal-initiation flows that cello_close_session dispatches into.
|
|
3
|
+
*
|
|
4
|
+
* handleSealInterruptedFlow — the counterparty is GONE. Exchange seal-interrupted leaves over the
|
|
5
|
+
* directory pass-through, then freeze the session at seal_interrupted_pending.
|
|
6
|
+
* handleActiveSealFlow — the counterparty is LIVE. Run the bilateral close.
|
|
7
|
+
*
|
|
8
|
+
* The daemon holds no FrostThresholdSigner and no directory FROST ceremony client, so it CANNOT
|
|
9
|
+
* produce a threshold signature by itself. That is the sovereign-node invariant, and it is why these
|
|
10
|
+
* functions only ever assemble and exchange leaves — the notarization happens at the directory.
|
|
11
|
+
*/
|
|
12
|
+
import { randomUUID } from "node:crypto";
|
|
13
|
+
import { buildSignedSealInterruptedLeaf, verifyCounterpartySealLeaf } from "./seal-leaf.js";
|
|
14
|
+
export function createSealFlows(deps) {
|
|
15
|
+
const { logger, sessionNodeManager, agents, getKeyProvider, signalingFor, sendOver } = deps;
|
|
16
|
+
const keyProviders = { get: getKeyProvider };
|
|
17
|
+
// Seal-interrupted bilateral INITIATOR flow.
|
|
18
|
+
//
|
|
19
|
+
// ⚠️ SCOPE — this flow does NOT complete a FROST-notarized seal, and must not pretend to.
|
|
20
|
+
//
|
|
21
|
+
// What it DOES: both parties produce and exchange real K_local Ed25519-signed SEAL-INTERRUPTED
|
|
22
|
+
// leaves over an agreed {leafCount, merkleRoot}; the initiator verifies the signature, the
|
|
23
|
+
// echoed nonce, and the cross-checks; the verified bilateral commitment is persisted; the
|
|
24
|
+
// session advances to the NON-TERMINAL 'seal_interrupted_pending' state.
|
|
25
|
+
//
|
|
26
|
+
// What it does NOT do: the FROST threshold notarization. The daemon holds no
|
|
27
|
+
// FrostThresholdSigner and no directory FROST ceremony client, so it CANNOT produce a threshold
|
|
28
|
+
// seal here. The session therefore STOPS at the persisted bilateral commitment rather than
|
|
29
|
+
// claim a completed seal. Wiring the real seal means injecting a SealManager adapter.
|
|
30
|
+
//
|
|
31
|
+
// Merkle-ROOT agreement is deliberately NOT compared at this layer. Under concurrent
|
|
32
|
+
// bidirectional traffic the two sides' local append orders — and therefore their roots — can
|
|
33
|
+
// legitimately diverge until the relay-assigned canonical sequence exists. Comparing roots here
|
|
34
|
+
// would reject honest sessions. leafCount agreement (each side against its own tree size, or
|
|
35
|
+
// message_count when no tree exists) is the bilateral check available at this layer; true root
|
|
36
|
+
// agreement belongs to the FROST seal against the directory-held tree.
|
|
37
|
+
//
|
|
38
|
+
// Both sides bind over their OWN tree root + size (SI-001) whenever a non-empty tree exists —
|
|
39
|
+
// e.g. reloaded from session_tree_leaves after a restart. Only sessions with no persisted tree
|
|
40
|
+
// fall back to message_count plus the caller-supplied root.
|
|
41
|
+
// M7-SESSION-001 / DAEMON-004: shared bilateral ack-await machinery. The
|
|
42
|
+
// interrupted-seal flow AND the active-session seal flow both send a
|
|
43
|
+
// `seal_interrupted_request` and wait on the directory signaling stream for the
|
|
44
|
+
// counterparty's `seal_interrupted_ack` / `seal_interrupted_rejection` (or time
|
|
45
|
+
// out). Extracted so the two flows wait identically — the directory pass-through
|
|
46
|
+
// routing (directory-node.ts) is the only wired transport for this exchange.
|
|
47
|
+
const SEAL_INTERRUPTED_TIMEOUT_MS = 30_000;
|
|
48
|
+
function awaitSealAck(sessionId, mgr) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
// CONN-001: await the ack on the OWNING agent's own stream (per-agent in prod, shared in test).
|
|
51
|
+
if (!mgr) {
|
|
52
|
+
resolve({ type: "timeout" });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const timeoutHandle = setTimeout(() => {
|
|
56
|
+
unregister();
|
|
57
|
+
resolve({ type: "timeout" });
|
|
58
|
+
}, SEAL_INTERRUPTED_TIMEOUT_MS);
|
|
59
|
+
const unregister = mgr.registerInboundHandler((frame) => {
|
|
60
|
+
if (frame.type !== "seal_interrupted_ack" && frame.type !== "seal_interrupted_rejection") {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (typeof frame.sessionId !== "string" || frame.sessionId !== sessionId)
|
|
64
|
+
return;
|
|
65
|
+
clearTimeout(timeoutHandle);
|
|
66
|
+
unregister();
|
|
67
|
+
if (frame.type === "seal_interrupted_ack") {
|
|
68
|
+
resolve({
|
|
69
|
+
type: "seal_interrupted_ack",
|
|
70
|
+
sealInterruptedLeaf: frame.sealInterruptedLeaf ?? {},
|
|
71
|
+
nonce: typeof frame.nonce === "string" ? frame.nonce : null,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
resolve({
|
|
76
|
+
type: "seal_interrupted_rejection",
|
|
77
|
+
reason: typeof frame.reason === "string" ? frame.reason : "unknown",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async function handleSealInterruptedFlow(sessionId, record, correlationId, merkleRootAtInterruption) {
|
|
84
|
+
const nonce = randomUUID();
|
|
85
|
+
// Retrieve the agent's own pubkey from the agent list
|
|
86
|
+
// (the agent_name stored in the session record identifies which agent was in session)
|
|
87
|
+
const agent = agents.find((a) => a.name === record.agent_name);
|
|
88
|
+
const myPubkeyHex = agent?.pubkey ?? "";
|
|
89
|
+
const counterpartyPubkey = record.counterparty_pubkey;
|
|
90
|
+
// DAEMON-004 (AC-007 / SI-001 / finding #2): prefer the daemon-owned tree.
|
|
91
|
+
// After a SIGKILL+restart the active session is forced to 'interrupted' and
|
|
92
|
+
// its Merkle tree is reloaded from session_tree_leaves. When that reloaded
|
|
93
|
+
// tree is non-empty it is the authoritative transcript: the seal binds over
|
|
94
|
+
// the daemon's OWN reloaded root + size, and any caller-supplied
|
|
95
|
+
// merkleRootAtInterruption is IGNORED (SI-001). Only when no tree was ever
|
|
96
|
+
// persisted (legacy / pre-DAEMON-004 sessions) do we fall back to the
|
|
97
|
+
// caller-supplied root and the message_count column (SESSION-001 behavior).
|
|
98
|
+
const reloadedTree = sessionNodeManager.getSessionTree(record.agent_name, sessionId);
|
|
99
|
+
const hasOwnTree = reloadedTree.size() > 0;
|
|
100
|
+
const ownLeafCount = hasOwnTree ? reloadedTree.size() : (record.message_count ?? 0);
|
|
101
|
+
const effectiveRoot = hasOwnTree
|
|
102
|
+
? sessionNodeManager.getSessionTreeRootHex(record.agent_name, sessionId)
|
|
103
|
+
: merkleRootAtInterruption;
|
|
104
|
+
// DB-001: check signaling status before attempting to send
|
|
105
|
+
if (signalingFor(record.agent_name)?.status === "reconnecting") {
|
|
106
|
+
logger.error("session.interrupted.seal.failed", {
|
|
107
|
+
sessionId,
|
|
108
|
+
agentName: record.agent_name,
|
|
109
|
+
reason: "signaling_reconnecting",
|
|
110
|
+
error: "directory_signaling_reconnecting",
|
|
111
|
+
correlationId,
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
reason: "signaling_reconnecting",
|
|
116
|
+
guidance: "The directory signaling stream is reconnecting. Wait for directory_signaling to show connected in cello status before initiating seal-interrupted. The daemon reconnects automatically — no manual intervention required.",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// H-1: construct and K_local-sign our OWN SEAL-INTERRUPTED leaf before sending.
|
|
120
|
+
const myKeyProvider = keyProviders.get(record.agent_name);
|
|
121
|
+
if (!myKeyProvider) {
|
|
122
|
+
logger.error("session.interrupted.seal.failed", {
|
|
123
|
+
sessionId,
|
|
124
|
+
agentName: record.agent_name,
|
|
125
|
+
reason: "signing_key_unavailable",
|
|
126
|
+
error: "no_key_provider_for_agent",
|
|
127
|
+
correlationId,
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
reason: "signing_key_unavailable",
|
|
132
|
+
guidance: "The signing key for the agent that owned this session could not be loaded. Confirm the agent's key file exists under ~/.cello/agents and restart the daemon.",
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const ownLeaf = await buildSignedSealInterruptedLeaf(myKeyProvider, {
|
|
136
|
+
sessionId,
|
|
137
|
+
leafCount: ownLeafCount,
|
|
138
|
+
merkleRootAtInterruption: effectiveRoot,
|
|
139
|
+
signerPubkeyHex: myPubkeyHex,
|
|
140
|
+
});
|
|
141
|
+
// Send SealInterruptedRequest via directory signaling
|
|
142
|
+
const request = {
|
|
143
|
+
type: "seal_interrupted_request",
|
|
144
|
+
sessionId,
|
|
145
|
+
initiatorPubkey: myPubkeyHex,
|
|
146
|
+
counterpartyPubkey,
|
|
147
|
+
leafCountAtInterruption: ownLeafCount,
|
|
148
|
+
merkleRootAtInterruption: effectiveRoot,
|
|
149
|
+
nonce,
|
|
150
|
+
};
|
|
151
|
+
const sendResult = await sendOver(record.agent_name, request);
|
|
152
|
+
if (!sendResult.ok) {
|
|
153
|
+
logger.error("session.interrupted.seal.failed", {
|
|
154
|
+
sessionId,
|
|
155
|
+
agentName: record.agent_name,
|
|
156
|
+
reason: "seal_interrupted_counterparty_unavailable",
|
|
157
|
+
error: sendResult.reason,
|
|
158
|
+
correlationId,
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
ok: false,
|
|
162
|
+
reason: "seal_interrupted_counterparty_unavailable",
|
|
163
|
+
guidance: "The counterparty is not currently reachable to complete the seal-interrupted flow. Retry when the counterparty is online — check their connection status via cello_status.",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Wait for counterparty ack/rejection via the shared signaling await machinery.
|
|
167
|
+
const ackResult = await awaitSealAck(sessionId, signalingFor(record.agent_name));
|
|
168
|
+
if (ackResult.type === "timeout") {
|
|
169
|
+
logger.error("session.interrupted.seal.failed", {
|
|
170
|
+
sessionId,
|
|
171
|
+
agentName: record.agent_name,
|
|
172
|
+
reason: "seal_interrupted_counterparty_unavailable",
|
|
173
|
+
error: "seal_interrupted_response_timeout",
|
|
174
|
+
correlationId,
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
reason: "seal_interrupted_counterparty_unavailable",
|
|
179
|
+
guidance: "The counterparty is not currently reachable to complete the seal-interrupted flow. Retry when the counterparty is online — check their connection status via cello_status.",
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (ackResult.type === "seal_interrupted_rejection") {
|
|
183
|
+
logger.error("session.interrupted.seal.failed", {
|
|
184
|
+
sessionId,
|
|
185
|
+
agentName: record.agent_name,
|
|
186
|
+
reason: "seal_interrupted_rejected_by_counterparty",
|
|
187
|
+
error: ackResult.reason,
|
|
188
|
+
correlationId,
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
ok: false,
|
|
192
|
+
reason: "seal_interrupted_rejected_by_counterparty",
|
|
193
|
+
guidance: "The counterparty rejected the seal-interrupted request. This may indicate their session state is inconsistent. Ask the counterparty to check their interrupted sessions via cello status on their end.",
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// ackResult.type === "seal_interrupted_ack"
|
|
197
|
+
{
|
|
198
|
+
const leaf = ackResult.sealInterruptedLeaf;
|
|
199
|
+
// C-1 / SI-002 / SI-003: nonce (L-2), leafCount agreement, and the
|
|
200
|
+
// counterparty's own Ed25519 signature are verified by the shared helper.
|
|
201
|
+
// We compare against our OWN ownLeafCount (an independent value) so a real
|
|
202
|
+
// divergence in transcript length is caught. Merkle-root agreement is NOT
|
|
203
|
+
// verified at this leaf-exchange layer (it is the FROST-seal step's job
|
|
204
|
+
// against the directory-held tree); see the H-1 SCOPE note above.
|
|
205
|
+
const verified = verifyCounterpartySealLeaf({
|
|
206
|
+
leaf,
|
|
207
|
+
sentNonce: nonce,
|
|
208
|
+
ackNonce: ackResult.nonce,
|
|
209
|
+
ownLeafCount,
|
|
210
|
+
expectedCounterpartyPubkey: record.counterparty_pubkey,
|
|
211
|
+
});
|
|
212
|
+
if (!verified.ok) {
|
|
213
|
+
const reasonMap = {
|
|
214
|
+
nonce_mismatch: "seal_interrupted_nonce_mismatch",
|
|
215
|
+
leaf_count_mismatch: "seal_interrupted_leaf_count_mismatch",
|
|
216
|
+
leaf_signature_invalid: "seal_interrupted_leaf_signature_invalid",
|
|
217
|
+
};
|
|
218
|
+
const guidanceMap = {
|
|
219
|
+
nonce_mismatch: "The counterparty's acknowledgement did not echo the expected nonce. This indicates a stale or replayed response. The session remains interrupted — retry cello_close_session.",
|
|
220
|
+
leaf_count_mismatch: "The counterparty's recorded message count at interruption does not match ours. The two sides have divergent session histories and cannot form a bilateral commitment. Compare cello status on both ends before retrying.",
|
|
221
|
+
leaf_signature_invalid: "The counterparty's SEAL-INTERRUPTED leaf signature did not verify. The seal flow has been aborted. The session remains interrupted — retry cello_close_session after confirming the counterparty is using a compatible version.",
|
|
222
|
+
};
|
|
223
|
+
logger.error("session.interrupted.seal.failed", {
|
|
224
|
+
sessionId,
|
|
225
|
+
agentName: record.agent_name,
|
|
226
|
+
reason: reasonMap[verified.reason],
|
|
227
|
+
error: verified.error,
|
|
228
|
+
correlationId,
|
|
229
|
+
});
|
|
230
|
+
return { ok: false, reason: reasonMap[verified.reason], guidance: guidanceMap[verified.reason] };
|
|
231
|
+
}
|
|
232
|
+
// H-1: signature + nonce + cross-checks all passed. We have a VERIFIED
|
|
233
|
+
// bilateral commitment (both K_local-signed leaves over the same
|
|
234
|
+
// {leafCount, merkleRoot}). Persist BOTH leaves and advance the session to
|
|
235
|
+
// the NON-TERMINAL 'seal_interrupted_pending' state. We do NOT write
|
|
236
|
+
// 'sealed' — the FROST threshold notarization has not run (see the H-1
|
|
237
|
+
// SCOPE note above for exactly what blocks it).
|
|
238
|
+
const advanced = sessionNodeManager.persistSealInterruptedCommitment({
|
|
239
|
+
agentName: record.agent_name,
|
|
240
|
+
sessionId,
|
|
241
|
+
role: "initiator",
|
|
242
|
+
ownLeaf,
|
|
243
|
+
counterpartyLeaf: leaf,
|
|
244
|
+
merkleRoot: effectiveRoot,
|
|
245
|
+
nonce,
|
|
246
|
+
});
|
|
247
|
+
if (!advanced) {
|
|
248
|
+
logger.error("session.interrupted.seal.failed", {
|
|
249
|
+
sessionId,
|
|
250
|
+
agentName: record.agent_name,
|
|
251
|
+
reason: "seal_interrupted_persist_failed",
|
|
252
|
+
error: "session row was not in 'interrupted' state at commit time",
|
|
253
|
+
correlationId,
|
|
254
|
+
});
|
|
255
|
+
return {
|
|
256
|
+
ok: false,
|
|
257
|
+
reason: "seal_interrupted_persist_failed",
|
|
258
|
+
guidance: "The bilateral commitment could not be persisted because the session was no longer in the interrupted state. Re-check cello status — it may already be pending or sealed.",
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
logger.info("session.interrupted.pending", {
|
|
262
|
+
sessionId,
|
|
263
|
+
agentName: record.agent_name,
|
|
264
|
+
leafCount: ownLeafCount,
|
|
265
|
+
correlationId,
|
|
266
|
+
});
|
|
267
|
+
return { ok: true, sessionId, status: "seal_interrupted_pending" };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// ─── CELLO-M7-DAEMON-004: active-session seal initiation ─────────────────────
|
|
271
|
+
//
|
|
272
|
+
// Pseudocode (SPARC Phase P):
|
|
273
|
+
// 1. DB-002: if signaling reconnecting → return signaling_reconnecting and do
|
|
274
|
+
// NOT initiate a partial seal that cannot be notarized.
|
|
275
|
+
// 2. SI-001: read the merkle root from the daemon's OWN tree (never a caller param).
|
|
276
|
+
// 3. K_local-sign a SEAL ctrl leaf over that root (SI-003: signed by our own node).
|
|
277
|
+
// 4. Fire session.seal.initiated with rootHex == our own tree root, role:'initiator'.
|
|
278
|
+
// 5. Submit the SEAL to the relay/counterparty + coordinate FROST via signaling,
|
|
279
|
+
// reusing the same signaling stream the interrupted-seal flow (SESSION-001) uses.
|
|
280
|
+
// The bilateral counterparty ack + FROST threshold notarization complete the
|
|
281
|
+
// seal end-to-end (AC-004, exercised under CELLO_E2E_LIVE) — the daemon never
|
|
282
|
+
// synthesizes the counterparty's signature.
|
|
283
|
+
// round-2 [medium]: the IPC return status MUST match the persisted row. The
|
|
284
|
+
// active-seal flow advances the session to 'seal_interrupted_pending' (the same
|
|
285
|
+
// non-terminal bilateral-commitment state the interrupted flow uses); returning
|
|
286
|
+
// a distinct 'seal_initiated' here meant the close response and a subsequent
|
|
287
|
+
// cello_status / cello_list_sessions showed two names for one state. One name.
|
|
288
|
+
async function handleActiveSealFlow(sessionId, record, correlationId) {
|
|
289
|
+
const agent = agents.find((a) => a.name === record.agent_name);
|
|
290
|
+
const myPubkeyHex = agent?.pubkey ?? "";
|
|
291
|
+
const kp = keyProviders.get(record.agent_name);
|
|
292
|
+
// DB-002: never initiate a partial seal while signaling is reconnecting.
|
|
293
|
+
if (signalingFor(record.agent_name)?.status === "reconnecting") {
|
|
294
|
+
return {
|
|
295
|
+
ok: false,
|
|
296
|
+
reason: "signaling_reconnecting",
|
|
297
|
+
guidance: "The directory signaling stream is reconnecting. Wait for directory_signaling to show connected in cello status before retrying the close. The daemon reconnects automatically.",
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
if (!kp || !myPubkeyHex) {
|
|
301
|
+
logger.error("session.seal.initiate.failed", {
|
|
302
|
+
sessionId,
|
|
303
|
+
reason: "signing_key_unavailable",
|
|
304
|
+
errorMessage: "no key provider or pubkey for the agent that owns this session",
|
|
305
|
+
correlationId,
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
ok: false,
|
|
309
|
+
reason: "signing_key_unavailable",
|
|
310
|
+
guidance: "The signing key for the agent that owns this session could not be loaded. Confirm the agent's key file exists under ~/.cello/agents and restart the daemon.",
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
// SI-001: the root is the daemon's OWN tree root — computed from the leaves it
|
|
314
|
+
// appended itself. Any caller-supplied merkleRoot is never read here.
|
|
315
|
+
const ownRootHex = sessionNodeManager.getSessionTreeRootHex(record.agent_name, sessionId);
|
|
316
|
+
const leafCount = sessionNodeManager.getSessionTree(record.agent_name, sessionId).size();
|
|
317
|
+
const nonce = randomUUID();
|
|
318
|
+
// SI-003: K_local-sign our OWN SEAL leaf over our own root. We reuse the
|
|
319
|
+
// wired SEAL-INTERRUPTED leaf shape so the counterparty co-signs an identical
|
|
320
|
+
// canonical form (the active and interrupted bilateral exchanges share the
|
|
321
|
+
// directory pass-through routing — there is no separate `seal_request`
|
|
322
|
+
// transport, and inventing one silently drops the frame at the directory).
|
|
323
|
+
let ownLeaf;
|
|
324
|
+
try {
|
|
325
|
+
ownLeaf = await buildSignedSealInterruptedLeaf(kp, {
|
|
326
|
+
sessionId,
|
|
327
|
+
leafCount,
|
|
328
|
+
merkleRootAtInterruption: ownRootHex,
|
|
329
|
+
signerPubkeyHex: myPubkeyHex,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
logger.error("session.seal.initiate.failed", {
|
|
334
|
+
sessionId,
|
|
335
|
+
reason: "seal_leaf_signing_failed",
|
|
336
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
337
|
+
correlationId,
|
|
338
|
+
});
|
|
339
|
+
return {
|
|
340
|
+
ok: false,
|
|
341
|
+
reason: "seal_leaf_signing_failed",
|
|
342
|
+
guidance: "The SEAL leaf could not be signed. Check the daemon logs for the signing error and confirm the agent key is intact.",
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
// AC-003: session.seal.initiated — rootHex MUST equal the daemon's own root.
|
|
346
|
+
logger.info("session.seal.initiated", {
|
|
347
|
+
sessionId,
|
|
348
|
+
rootHex: ownRootHex,
|
|
349
|
+
role: "initiator",
|
|
350
|
+
correlationId,
|
|
351
|
+
});
|
|
352
|
+
// Submit the SEAL request over the directory signaling stream (the SAME wired
|
|
353
|
+
// pass-through the interrupted-seal flow uses) and AWAIT the counterparty's
|
|
354
|
+
// bilateral ack. We never report success on a fire-and-forget send.
|
|
355
|
+
const sendResult = await sendOver(record.agent_name, {
|
|
356
|
+
type: "seal_interrupted_request",
|
|
357
|
+
sessionId,
|
|
358
|
+
initiatorPubkey: myPubkeyHex,
|
|
359
|
+
counterpartyPubkey: record.counterparty_pubkey,
|
|
360
|
+
leafCountAtInterruption: leafCount,
|
|
361
|
+
merkleRootAtInterruption: ownRootHex,
|
|
362
|
+
nonce,
|
|
363
|
+
});
|
|
364
|
+
if (!sendResult.ok) {
|
|
365
|
+
logger.error("session.seal.initiate.failed", {
|
|
366
|
+
sessionId,
|
|
367
|
+
reason: sendResult.reason,
|
|
368
|
+
errorMessage: sendResult.reason,
|
|
369
|
+
correlationId,
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
ok: false,
|
|
373
|
+
reason: sendResult.reason ?? "directory_unreachable",
|
|
374
|
+
guidance: "guidance" in sendResult && typeof sendResult.guidance === "string"
|
|
375
|
+
? sendResult.guidance
|
|
376
|
+
: "The seal could not be submitted to the directory. Retry once cello status shows directory_signaling connected.",
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
// Wait for the counterparty's bilateral ack (or rejection / timeout).
|
|
380
|
+
const ackResult = await awaitSealAck(sessionId, signalingFor(record.agent_name));
|
|
381
|
+
if (ackResult.type === "timeout" || ackResult.type === "seal_interrupted_rejection") {
|
|
382
|
+
const reason = ackResult.type === "timeout" ? "seal_counterparty_unavailable" : "seal_rejected_by_counterparty";
|
|
383
|
+
logger.error("session.seal.initiate.failed", {
|
|
384
|
+
sessionId,
|
|
385
|
+
reason,
|
|
386
|
+
errorMessage: ackResult.type === "timeout" ? "seal_response_timeout" : ackResult.reason,
|
|
387
|
+
correlationId,
|
|
388
|
+
});
|
|
389
|
+
return {
|
|
390
|
+
ok: false,
|
|
391
|
+
reason,
|
|
392
|
+
guidance: ackResult.type === "timeout"
|
|
393
|
+
? "The counterparty did not acknowledge the seal in time. Retry when they are online — check cello_status. The session remains active and usable."
|
|
394
|
+
: "The counterparty rejected the seal request. Their session state may be inconsistent. Ask them to check cello status before retrying.",
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
// SI-002 / SI-003: verify the counterparty's own-signed ack leaf over our root.
|
|
398
|
+
const verified = verifyCounterpartySealLeaf({
|
|
399
|
+
leaf: ackResult.sealInterruptedLeaf,
|
|
400
|
+
sentNonce: nonce,
|
|
401
|
+
ackNonce: ackResult.nonce,
|
|
402
|
+
ownLeafCount: leafCount,
|
|
403
|
+
expectedCounterpartyPubkey: record.counterparty_pubkey,
|
|
404
|
+
});
|
|
405
|
+
if (!verified.ok) {
|
|
406
|
+
logger.error("session.seal.initiate.failed", {
|
|
407
|
+
sessionId,
|
|
408
|
+
reason: `seal_${verified.reason}`,
|
|
409
|
+
errorMessage: verified.error,
|
|
410
|
+
correlationId,
|
|
411
|
+
});
|
|
412
|
+
return {
|
|
413
|
+
ok: false,
|
|
414
|
+
reason: `seal_${verified.reason}`,
|
|
415
|
+
guidance: "The counterparty's seal acknowledgement failed verification (nonce, leaf count, or signature). The session remains active — retry cello_close_session once both sides agree on the transcript.",
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
// Verified bilateral commitment over the daemon's OWN root. Persist both
|
|
419
|
+
// signed leaves and advance the session out of 'active'. As in the
|
|
420
|
+
// interrupted flow, we stop at the bilateral commitment ('seal_interrupted_pending');
|
|
421
|
+
// the FROST threshold notarization that finalizes 'sealed' is the deferred
|
|
422
|
+
// directory step (AC-004, exercised under CELLO_E2E_LIVE).
|
|
423
|
+
const advanced = sessionNodeManager.persistSealInterruptedCommitment({
|
|
424
|
+
agentName: record.agent_name,
|
|
425
|
+
sessionId,
|
|
426
|
+
role: "initiator",
|
|
427
|
+
ownLeaf,
|
|
428
|
+
counterpartyLeaf: ackResult.sealInterruptedLeaf,
|
|
429
|
+
merkleRoot: ownRootHex,
|
|
430
|
+
nonce,
|
|
431
|
+
});
|
|
432
|
+
if (!advanced) {
|
|
433
|
+
logger.error("session.seal.initiate.failed", {
|
|
434
|
+
sessionId,
|
|
435
|
+
reason: "seal_persist_failed",
|
|
436
|
+
errorMessage: "session row was not in an active/interrupted state at commit time",
|
|
437
|
+
correlationId,
|
|
438
|
+
});
|
|
439
|
+
return {
|
|
440
|
+
ok: false,
|
|
441
|
+
reason: "seal_persist_failed",
|
|
442
|
+
guidance: "The bilateral seal commitment could not be persisted because the session changed state. Re-check cello status — it may already be pending or sealed.",
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
// round-2 finding #5: the session is now frozen at 'seal_interrupted_pending'.
|
|
446
|
+
// Retire its live libp2p node so no further inbound content can arrive (which
|
|
447
|
+
// ingestReceivedContent now also rejects) and so the node is not leaked per
|
|
448
|
+
// active close. retireSessionNode stops the node WITHOUT changing the DB status.
|
|
449
|
+
await sessionNodeManager.retireSessionNode(record.agent_name, sessionId);
|
|
450
|
+
return { ok: true, sessionId, status: "seal_interrupted_pending", rootHex: ownRootHex };
|
|
451
|
+
}
|
|
452
|
+
return { awaitSealAck, handleSealInterruptedFlow, handleActiveSealFlow };
|
|
453
|
+
}
|
|
454
|
+
//# sourceMappingURL=seal-flows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seal-flows.js","sourceRoot":"","sources":["../src/seal-flows.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Client-side content-frontier re-derivation.
|
|
3
3
|
*
|
|
4
4
|
* The directory builds + signs the seal legibility, including each party's
|
|
5
5
|
* `content_frontier_seq` ("the highest message the party provably received"). The client
|
|
@@ -65,12 +65,12 @@ export interface UnilateralFrontierCheck {
|
|
|
65
65
|
* - verified: leaves present, no CLIENT-VERIFIABLE ('live') frontier exceeded its leaves.
|
|
66
66
|
* - corrected: leaves present, one or more 'live' frontiers were inflated and overridden
|
|
67
67
|
* DOWN to the re-derived value (see `corrections`).
|
|
68
|
-
* - directory_attested: no frontier_leaves shipped (
|
|
69
|
-
* directory-attested
|
|
68
|
+
* - directory_attested: no frontier_leaves shipped (an older directory) — the cert stays
|
|
69
|
+
* directory-attested. No correction possible.
|
|
70
70
|
* - leaves_invalid: frontier_leaves are forged / cross-session (reDeriveFrontiers failed) — a
|
|
71
71
|
* tamper signal; persist the directory-attested frontiers, log loudly. NEVER
|
|
72
|
-
* rejected
|
|
73
|
-
* dead-end
|
|
72
|
+
* rejected: the unilateral dedup guard makes rejection an unrecoverable
|
|
73
|
+
* dead-end.
|
|
74
74
|
*/
|
|
75
75
|
status: "verified" | "corrected" | "directory_attested" | "leaves_invalid";
|
|
76
76
|
/** lowercased pubkey → corrected content_frontier_seq, for inflated 'live' parties. The caller
|
|
@@ -79,14 +79,14 @@ export interface UnilateralFrontierCheck {
|
|
|
79
79
|
reason?: string;
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
82
|
+
* The present party independently re-verifies (and CORRECTS) the UNILATERAL receipt's frontiers.
|
|
83
|
+
* OVERRIDE, never reject.
|
|
84
84
|
*
|
|
85
85
|
* The unilateral legibility is FROST-notarized by the directory but the frontier VALUES are NOT bound
|
|
86
86
|
* into the seal signature (unlike the bilateral seal, whose signer binds the legibility hash), so the
|
|
87
87
|
* client must not trust them blindly. Because the directory-side dedup guard makes a client REJECTION
|
|
88
|
-
* of a unilateral cert unrecoverable (a retry close is silently ignored — no receipt ever
|
|
89
|
-
*
|
|
88
|
+
* of a unilateral cert unrecoverable (a retry close is silently ignored — no receipt is ever
|
|
89
|
+
* produced), the client CORRECTS rather than rejects:
|
|
90
90
|
* - CLIENT-VERIFIABLE ('live') party: the present (submitting) party carries all its own signed
|
|
91
91
|
* leaves, so its content_frontier_seq is fully re-derivable. The directory cannot forge signed
|
|
92
92
|
* leaves, so the re-derived value is the provable truth → an inflated published value is OVERRIDDEN
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seal-frontier-verify.d.ts","sourceRoot":"","sources":["../src/seal-frontier-verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,UAAU,CAAC;IAC5B,aAAa,EAAE,UAAU,CAAC;IAC1B,gBAAgB,EAAE,UAAU,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,GAAG,uBAAuB,CAAA;CAAE,CAAC;AAQjG;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,iBAAiB,EAAE,UAAU,GAAG,cAAc,CA0B3G;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7E,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQ9E;AAID,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;OAUG;IACH,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,CAAC;IAC3E;kHAC8G;IAC9G,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,aAAa,CAAC,6BAA6B,CAAC,EAC1D,cAAc,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC9C,SAAS,EAAE,UAAU,GACpB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"seal-frontier-verify.d.ts","sourceRoot":"","sources":["../src/seal-frontier-verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,UAAU,CAAC;IAC5B,aAAa,EAAE,UAAU,CAAC;IAC1B,gBAAgB,EAAE,UAAU,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,GAAG,uBAAuB,CAAA;CAAE,CAAC;AAQjG;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,iBAAiB,EAAE,UAAU,GAAG,cAAc,CA0B3G;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7E,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQ9E;AAID,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;OAUG;IACH,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,oBAAoB,GAAG,gBAAgB,CAAC;IAC3E;kHAC8G;IAC9G,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,aAAa,CAAC,6BAA6B,CAAC,EAC1D,cAAc,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC9C,SAAS,EAAE,UAAU,GACpB,uBAAuB,CAwBzB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Client-side content-frontier re-derivation.
|
|
3
3
|
*
|
|
4
4
|
* The directory builds + signs the seal legibility, including each party's
|
|
5
5
|
* `content_frontier_seq` ("the highest message the party provably received"). The client
|
|
@@ -85,14 +85,14 @@ export function findInflatedFrontier(participants, derived) {
|
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
88
|
+
* The present party independently re-verifies (and CORRECTS) the UNILATERAL receipt's frontiers.
|
|
89
|
+
* OVERRIDE, never reject.
|
|
90
90
|
*
|
|
91
91
|
* The unilateral legibility is FROST-notarized by the directory but the frontier VALUES are NOT bound
|
|
92
92
|
* into the seal signature (unlike the bilateral seal, whose signer binds the legibility hash), so the
|
|
93
93
|
* client must not trust them blindly. Because the directory-side dedup guard makes a client REJECTION
|
|
94
|
-
* of a unilateral cert unrecoverable (a retry close is silently ignored — no receipt ever
|
|
95
|
-
*
|
|
94
|
+
* of a unilateral cert unrecoverable (a retry close is silently ignored — no receipt is ever
|
|
95
|
+
* produced), the client CORRECTS rather than rejects:
|
|
96
96
|
* - CLIENT-VERIFIABLE ('live') party: the present (submitting) party carries all its own signed
|
|
97
97
|
* leaves, so its content_frontier_seq is fully re-derivable. The directory cannot forge signed
|
|
98
98
|
* leaves, so the re-derived value is the provable truth → an inflated published value is OVERRIDDEN
|
|
@@ -108,17 +108,16 @@ export function findInflatedFrontier(participants, derived) {
|
|
|
108
108
|
export function checkUnilateralFrontier(participants, frontierLeaves, sessionId) {
|
|
109
109
|
const corrections = new Map();
|
|
110
110
|
const haveLeaves = Array.isArray(frontierLeaves) && frontierLeaves.length > 0;
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
// not-yet-upgraded directory during rollout.
|
|
111
|
+
// A directory that ships no leaves leaves the cert directory-attested. Never reject — rejecting
|
|
112
|
+
// would break unilateral seals against a not-yet-upgraded directory during rollout.
|
|
114
113
|
if (!haveLeaves)
|
|
115
114
|
return { status: "directory_attested", corrections };
|
|
116
115
|
const rederived = reDeriveFrontiers(frontierLeaves, sessionId);
|
|
117
116
|
// Forged / cross-session leaves are the STRONGEST tamper evidence, so they get the strongest
|
|
118
|
-
// correction
|
|
119
|
-
// 'live' frontier > 0 down to 0.
|
|
120
|
-
// an EASIER inflation bypass than shipping none
|
|
121
|
-
// (the directory dedup guard makes rejection an unrecoverable dead-end); the caller logs
|
|
117
|
+
// correction: treat them as ZERO trustworthy evidence (an empty derived map), which drives any
|
|
118
|
+
// 'live' frontier > 0 down to 0. Do NOT leave the published value untouched on invalid leaves —
|
|
119
|
+
// that would make malformed leaves an EASIER inflation bypass than shipping none. Still never
|
|
120
|
+
// REJECT (the directory dedup guard makes rejection an unrecoverable dead-end); the caller logs.
|
|
122
121
|
const derived = rederived.ok ? rederived.frontiers : new Map();
|
|
123
122
|
// Only CLIENT-VERIFIABLE ('live') parties are re-derivable; override any value above the provable
|
|
124
123
|
// one DOWN to it. The absent party is directory-attested (its remainder is not re-derivable here).
|