@cello-protocol/protocol-types 0.0.53 → 0.0.55
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/document-amendment.d.ts +133 -0
- package/dist/document-amendment.d.ts.map +1 -0
- package/dist/document-amendment.js +229 -0
- package/dist/document-amendment.js.map +1 -0
- package/dist/document-derive.d.ts +96 -0
- package/dist/document-derive.d.ts.map +1 -0
- package/dist/document-derive.js +605 -0
- package/dist/document-derive.js.map +1 -0
- package/dist/document-envelope.d.ts +18 -8
- package/dist/document-envelope.d.ts.map +1 -1
- package/dist/document-envelope.js +35 -19
- package/dist/document-envelope.js.map +1 -1
- package/dist/document-governance.d.ts +40 -0
- package/dist/document-governance.d.ts.map +1 -0
- package/dist/document-governance.js +145 -0
- package/dist/document-governance.js.map +1 -0
- package/dist/document-multisig.d.ts +81 -0
- package/dist/document-multisig.d.ts.map +1 -0
- package/dist/document-multisig.js +185 -0
- package/dist/document-multisig.js.map +1 -0
- package/dist/document-proposal.d.ts +29 -14
- package/dist/document-proposal.d.ts.map +1 -1
- package/dist/document-proposal.js +101 -7
- package/dist/document-proposal.js.map +1 -1
- package/dist/document-reconcile.d.ts +100 -0
- package/dist/document-reconcile.d.ts.map +1 -0
- package/dist/document-reconcile.js +197 -0
- package/dist/document-reconcile.js.map +1 -0
- package/dist/index.d.ts +14 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/document-ack.d.ts +0 -111
- package/dist/document-ack.d.ts.map +0 -1
- package/dist/document-ack.js +0 -228
- package/dist/document-ack.js.map +0 -1
- package/dist/document-control.d.ts +0 -74
- package/dist/document-control.d.ts.map +0 -1
- package/dist/document-control.js +0 -174
- package/dist/document-control.js.map +0 -1
|
@@ -27,26 +27,29 @@
|
|
|
27
27
|
* the binding is LEARNABLE, and this envelope is where it is learned. Outside
|
|
28
28
|
* the signature, "learnable" would mean "assertable by anyone on the wire".
|
|
29
29
|
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* `doc_prev_hash` is not optional and is not defaulted (§14): the chain link is what lets the
|
|
31
|
+
* document log be extracted and verified across sealed sessions, and a decoder that read absence
|
|
32
|
+
* as null would turn every gap into a valid-looking genesis. `governance_parents` is likewise
|
|
33
|
+
* mandatory — it is content's only causal link to the governance that makes it admissible.
|
|
33
34
|
*/
|
|
34
35
|
/** Domain tag in slot 0 of the to-be-signed array. */
|
|
35
|
-
|
|
36
|
+
/**
|
|
37
|
+
* v2 (SYNC-G1, journal Entry 58): the envelope gains `governance_parents` — the author's
|
|
38
|
+
* governance frontier at authoring — inside the signed preimage. It is the content's causal
|
|
39
|
+
* link to the governance that made it admissible; the per-envelope epoch stamp it replaces is
|
|
40
|
+
* deleted by the same phase. No compatibility owed: nothing was published between bumps.
|
|
41
|
+
*/
|
|
42
|
+
export declare const DOCUMENT_UPDATE_DOMAIN = "CELLO-DOCUMENT-UPDATE-v3";
|
|
36
43
|
/**
|
|
37
44
|
* The pinned Yjs update encoding (§16.7-8). Pinned in the protocol types precisely so that two
|
|
38
45
|
* supporting clients can never disagree silently — the failure mode of disagreement is an empty
|
|
39
46
|
* document, not an error.
|
|
40
47
|
*/
|
|
41
48
|
export declare const DOCUMENT_UPDATE_ENCODING_V1 = "yjs-v1";
|
|
42
|
-
/** V1 has exactly one epoch. Compaction (which mints new epochs) is V2. */
|
|
43
|
-
export declare const DOCUMENT_EPOCH_V1 = 0;
|
|
44
49
|
export interface DocumentUpdateEnvelope {
|
|
45
50
|
type: "document_update";
|
|
46
51
|
/** Hash of the handshake proposal envelope that minted this document. */
|
|
47
52
|
document_id: string;
|
|
48
|
-
/** Constant `DOCUMENT_EPOCH_V1` in V1 — carried explicitly, never omitted. */
|
|
49
|
-
epoch_id: number;
|
|
50
53
|
/**
|
|
51
54
|
* The per-sender chain link: the `documentEnvelopeHash` of this sender's previous envelope for
|
|
52
55
|
* this document, or `null` for this sender's FIRST envelope. `null` and absent are different
|
|
@@ -62,6 +65,13 @@ export interface DocumentUpdateEnvelope {
|
|
|
62
65
|
state_vector: Uint8Array;
|
|
63
66
|
/** The Yjs update payload. */
|
|
64
67
|
update: Uint8Array;
|
|
68
|
+
/**
|
|
69
|
+
* SYNC-G1 — the author's GOVERNANCE frontier when authoring: governance entry hashes,
|
|
70
|
+
* canonical (strictly ascending, capped). This is what R20/R30 rule on for content: was the
|
|
71
|
+
* author a participant at THESE ancestors, and is no ending among them. Empty = authored at
|
|
72
|
+
* genesis, before any governance entry existed.
|
|
73
|
+
*/
|
|
74
|
+
governance_parents: string[];
|
|
65
75
|
/** Ed25519 (RFC 8032) over `buildDocumentUpdateTbs`. */
|
|
66
76
|
signature: Uint8Array;
|
|
67
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-envelope.d.ts","sourceRoot":"","sources":["../src/document-envelope.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"document-envelope.d.ts","sourceRoot":"","sources":["../src/document-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAKH,sDAAsD;AACtD;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AAEjE;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,WAAW,CAAC;AAOpD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,iBAAiB,CAAC;IACxB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,gBAAgB,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,eAAe,EAAE,MAAM,CAAC;IACxB,yFAAyF;IACzF,YAAY,EAAE,UAAU,CAAC;IACzB,8BAA8B;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,wDAAwD;IACxD,SAAS,EAAE,UAAU,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,sBAAsB,EAC3B,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/B,UAAU,CAcZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM,CAIxE;AAED,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,sBAAsB,GAAG,UAAU,CAapF;AAmCD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,sBAAsB,CAkFtF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,sBAAsB,EAC3B,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GAC1D;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAiCxB"}
|
|
@@ -27,14 +27,21 @@
|
|
|
27
27
|
* the binding is LEARNABLE, and this envelope is where it is learned. Outside
|
|
28
28
|
* the signature, "learnable" would mean "assertable by anyone on the wire".
|
|
29
29
|
*
|
|
30
|
-
* `
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* `doc_prev_hash` is not optional and is not defaulted (§14): the chain link is what lets the
|
|
31
|
+
* document log be extracted and verified across sealed sessions, and a decoder that read absence
|
|
32
|
+
* as null would turn every gap into a valid-looking genesis. `governance_parents` is likewise
|
|
33
|
+
* mandatory — it is content's only causal link to the governance that makes it admissible.
|
|
33
34
|
*/
|
|
34
35
|
import { createHash } from "node:crypto";
|
|
35
36
|
import { encodeCbor, decodeCbor } from "./cbor.js";
|
|
36
37
|
/** Domain tag in slot 0 of the to-be-signed array. */
|
|
37
|
-
|
|
38
|
+
/**
|
|
39
|
+
* v2 (SYNC-G1, journal Entry 58): the envelope gains `governance_parents` — the author's
|
|
40
|
+
* governance frontier at authoring — inside the signed preimage. It is the content's causal
|
|
41
|
+
* link to the governance that made it admissible; the per-envelope epoch stamp it replaces is
|
|
42
|
+
* deleted by the same phase. No compatibility owed: nothing was published between bumps.
|
|
43
|
+
*/
|
|
44
|
+
export const DOCUMENT_UPDATE_DOMAIN = "CELLO-DOCUMENT-UPDATE-v3";
|
|
38
45
|
/**
|
|
39
46
|
* The pinned Yjs update encoding (§16.7-8). Pinned in the protocol types precisely so that two
|
|
40
47
|
* supporting clients can never disagree silently — the failure mode of disagreement is an empty
|
|
@@ -42,7 +49,6 @@ export const DOCUMENT_UPDATE_DOMAIN = "CELLO-DOCUMENT-UPDATE-v1";
|
|
|
42
49
|
*/
|
|
43
50
|
export const DOCUMENT_UPDATE_ENCODING_V1 = "yjs-v1";
|
|
44
51
|
/** V1 has exactly one epoch. Compaction (which mints new epochs) is V2. */
|
|
45
|
-
export const DOCUMENT_EPOCH_V1 = 0;
|
|
46
52
|
/** A 32-byte hex digest — the shape of `document_id` and of every chain link. */
|
|
47
53
|
const HEX32 = /^[0-9a-f]{64}$/;
|
|
48
54
|
/**
|
|
@@ -63,13 +69,13 @@ export function buildDocumentUpdateTbs(env, opts = {}) {
|
|
|
63
69
|
const preimage = encodeCbor([
|
|
64
70
|
DOCUMENT_UPDATE_DOMAIN,
|
|
65
71
|
env.document_id,
|
|
66
|
-
env.epoch_id,
|
|
67
72
|
env.doc_prev_hash, // null encodes distinctly from any string — genesis is unambiguous
|
|
68
73
|
env.sender_agent_id,
|
|
69
74
|
env.sender_client_id,
|
|
70
75
|
env.update_encoding,
|
|
71
76
|
env.state_vector,
|
|
72
77
|
env.update,
|
|
78
|
+
[...env.governance_parents],
|
|
73
79
|
]);
|
|
74
80
|
if (opts.preHash === false)
|
|
75
81
|
return preimage;
|
|
@@ -94,20 +100,20 @@ export function encodeDocumentUpdateEnvelope(env) {
|
|
|
94
100
|
return encodeCbor({
|
|
95
101
|
type: env.type,
|
|
96
102
|
document_id: env.document_id,
|
|
97
|
-
epoch_id: env.epoch_id,
|
|
98
103
|
doc_prev_hash: env.doc_prev_hash,
|
|
99
104
|
sender_agent_id: env.sender_agent_id,
|
|
100
105
|
sender_client_id: env.sender_client_id,
|
|
101
106
|
update_encoding: env.update_encoding,
|
|
102
107
|
state_vector: env.state_vector,
|
|
103
108
|
update: env.update,
|
|
109
|
+
governance_parents: [...env.governance_parents],
|
|
104
110
|
signature: env.signature,
|
|
105
111
|
});
|
|
106
112
|
}
|
|
107
113
|
function requirePresent(map, field) {
|
|
108
114
|
// `in`, not a truthiness or nullish check. ABSENT and `null` are different facts: absent
|
|
109
|
-
// doc_prev_hash read as null would turn every gap in a chain into a fresh valid-looking genesis
|
|
110
|
-
//
|
|
115
|
+
// doc_prev_hash read as null would turn every gap in a chain into a fresh valid-looking genesis.
|
|
116
|
+
// A decoder that
|
|
111
117
|
// supplies a default for a field the spec calls mandatory is manufacturing the sender's claim.
|
|
112
118
|
if (!(field in map)) {
|
|
113
119
|
throw new Error(`document_envelope_missing_field: ${field} is mandatory and was not present`);
|
|
@@ -152,15 +158,6 @@ export function decodeDocumentUpdateEnvelope(bytes) {
|
|
|
152
158
|
if (!HEX32.test(documentId)) {
|
|
153
159
|
throw new Error(`document_envelope_document_id: must be a 32-byte lowercase hex digest, got "${documentId}"`);
|
|
154
160
|
}
|
|
155
|
-
const epochId = requirePresent(map, "epoch_id");
|
|
156
|
-
if (typeof epochId !== "number" || !Number.isInteger(epochId)) {
|
|
157
|
-
throw new Error(`document_envelope_epoch: must be an integer, got ${String(epochId)}`);
|
|
158
|
-
}
|
|
159
|
-
if (epochId !== DOCUMENT_EPOCH_V1) {
|
|
160
|
-
// V2 introduces compaction and non-zero epochs. Accepting one now would mean applying an
|
|
161
|
-
// update whose base state this build cannot reconstruct.
|
|
162
|
-
throw new Error(`document_envelope_epoch: this build speaks epoch ${DOCUMENT_EPOCH_V1} only, got ${epochId}`);
|
|
163
|
-
}
|
|
164
161
|
const prev = requirePresent(map, "doc_prev_hash");
|
|
165
162
|
if (prev !== null && (typeof prev !== "string" || !HEX32.test(prev))) {
|
|
166
163
|
throw new Error(`document_envelope_prev_hash: must be a 32-byte hex digest or explicit null, got "${String(prev)}"`);
|
|
@@ -178,16 +175,35 @@ export function decodeDocumentUpdateEnvelope(bytes) {
|
|
|
178
175
|
// The one refusal that cannot be replaced by a heuristic. See the header.
|
|
179
176
|
throw new Error(`document_envelope_encoding: this build speaks ${DOCUMENT_UPDATE_ENCODING_V1} only, got "${encoding}"`);
|
|
180
177
|
}
|
|
178
|
+
const rawParents = requirePresent(map, "governance_parents");
|
|
179
|
+
if (!Array.isArray(rawParents)) {
|
|
180
|
+
throw new Error("document_envelope_governance_parents: must be an array of entry hashes");
|
|
181
|
+
}
|
|
182
|
+
if (rawParents.length > 64) {
|
|
183
|
+
throw new Error(`document_envelope_governance_parents_cap: ${rawParents.length} exceeds the ceiling of 64`);
|
|
184
|
+
}
|
|
185
|
+
const governanceParents = rawParents.map((h) => {
|
|
186
|
+
if (typeof h !== "string" || !HEX32.test(h)) {
|
|
187
|
+
throw new Error("document_envelope_governance_parents: must hold 64-hex entry hashes");
|
|
188
|
+
}
|
|
189
|
+
return h;
|
|
190
|
+
});
|
|
191
|
+
for (let i = 1; i < governanceParents.length; i++) {
|
|
192
|
+
if (governanceParents[i] <= governanceParents[i - 1]) {
|
|
193
|
+
throw new Error("document_envelope_governance_parents_canonical: strictly ascending, no duplicates — " +
|
|
194
|
+
"one envelope, one identity");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
181
197
|
return {
|
|
182
198
|
type: "document_update",
|
|
183
199
|
document_id: documentId,
|
|
184
|
-
epoch_id: epochId,
|
|
185
200
|
doc_prev_hash: prev,
|
|
186
201
|
sender_agent_id: senderAgentId,
|
|
187
202
|
sender_client_id: clientId,
|
|
188
203
|
update_encoding: encoding,
|
|
189
204
|
state_vector: requireBytes(map, "state_vector"),
|
|
190
205
|
update: requireBytes(map, "update"),
|
|
206
|
+
governance_parents: governanceParents,
|
|
191
207
|
signature: requireBytes(map, "signature"),
|
|
192
208
|
};
|
|
193
209
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-envelope.js","sourceRoot":"","sources":["../src/document-envelope.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"document-envelope.js","sourceRoot":"","sources":["../src/document-envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-MP-GOVERN-1 — the signature-requirement policy. Rulings D2/D3 (2026-08-11), as code.
|
|
3
|
+
*
|
|
4
|
+
* The policy VALIDATES the collection's claimed required set; it does not mint one. "Any single
|
|
5
|
+
* admin may act" has no single answer to mint — {a} and {b} are both acceptable claims — so the
|
|
6
|
+
* seam is a verdict on what the collection claims, and the multisig layer then demands every
|
|
7
|
+
* claimed signature actually verify.
|
|
8
|
+
*
|
|
9
|
+
* The rules:
|
|
10
|
+
* - **Single-admin kinds** — `add_holder`, `promote_admin`, `remove_holder` (of a non-admin),
|
|
11
|
+
* `change_property`: the claim is EXACTLY ONE current admin. A wider claim is refused, not
|
|
12
|
+
* welcomed as extra-safe: every claimed signer must sign for the collection to complete, so an
|
|
13
|
+
* inflated claim lets one absent co-signer veto an action the rule gives to any single admin —
|
|
14
|
+
* a governance change smuggled through the claim.
|
|
15
|
+
* - **Voluntary leave** — `remove_holder` claimed by exactly the subject themselves is always
|
|
16
|
+
* acceptable, admin or not. Leaving is theirs (D3).
|
|
17
|
+
* - **`remove_admin`** — the claim is exactly ALL OTHER admins; the subject neither required nor
|
|
18
|
+
* counted. With exactly two admins NEITHER CAN REMOVE THE OTHER — by design, and the refusal
|
|
19
|
+
* names the recourse (D3: stop working in it, duplicate it, start fresh without them).
|
|
20
|
+
* - **The holder door is not a bypass** — `remove_holder` of a CURRENT ADMIN (other than
|
|
21
|
+
* voluntary leave) is refused: holder removal drops admin status too, so allowing it under the
|
|
22
|
+
* single-admin rule would expel an admin on one signature, evading `remove_admin` and the
|
|
23
|
+
* deadlock in one move. Demote first, under remove_admin's rule.
|
|
24
|
+
*
|
|
25
|
+
* Kind/subject semantics (does the subject hold? is it already an admin? last-admin protection)
|
|
26
|
+
* are the causal fold's job (`deriveDocumentState`) and run BEFORE this policy is consulted — it may assume a
|
|
27
|
+
* semantically coherent amendment.
|
|
28
|
+
*/
|
|
29
|
+
import type { AmendmentKind } from "./document-amendment.js";
|
|
30
|
+
export type GovernanceVerdict = {
|
|
31
|
+
ok: true;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
reason: string;
|
|
35
|
+
};
|
|
36
|
+
export declare function documentGovernancePolicy(kind: AmendmentKind, subjectAgentId: string | null, state: {
|
|
37
|
+
participants: ReadonlySet<string>;
|
|
38
|
+
admins: ReadonlySet<string>;
|
|
39
|
+
}, claimedRequiredSet: readonly string[]): GovernanceVerdict;
|
|
40
|
+
//# sourceMappingURL=document-governance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-governance.d.ts","sourceRoot":"","sources":["../src/document-governance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAiB7E,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,aAAa,EACnB,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,KAAK,EAAE;IAAE,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,EACzE,kBAAkB,EAAE,SAAS,MAAM,EAAE,GACpC,iBAAiB,CAyHnB"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-MP-GOVERN-1 — the signature-requirement policy. Rulings D2/D3 (2026-08-11), as code.
|
|
3
|
+
*
|
|
4
|
+
* The policy VALIDATES the collection's claimed required set; it does not mint one. "Any single
|
|
5
|
+
* admin may act" has no single answer to mint — {a} and {b} are both acceptable claims — so the
|
|
6
|
+
* seam is a verdict on what the collection claims, and the multisig layer then demands every
|
|
7
|
+
* claimed signature actually verify.
|
|
8
|
+
*
|
|
9
|
+
* The rules:
|
|
10
|
+
* - **Single-admin kinds** — `add_holder`, `promote_admin`, `remove_holder` (of a non-admin),
|
|
11
|
+
* `change_property`: the claim is EXACTLY ONE current admin. A wider claim is refused, not
|
|
12
|
+
* welcomed as extra-safe: every claimed signer must sign for the collection to complete, so an
|
|
13
|
+
* inflated claim lets one absent co-signer veto an action the rule gives to any single admin —
|
|
14
|
+
* a governance change smuggled through the claim.
|
|
15
|
+
* - **Voluntary leave** — `remove_holder` claimed by exactly the subject themselves is always
|
|
16
|
+
* acceptable, admin or not. Leaving is theirs (D3).
|
|
17
|
+
* - **`remove_admin`** — the claim is exactly ALL OTHER admins; the subject neither required nor
|
|
18
|
+
* counted. With exactly two admins NEITHER CAN REMOVE THE OTHER — by design, and the refusal
|
|
19
|
+
* names the recourse (D3: stop working in it, duplicate it, start fresh without them).
|
|
20
|
+
* - **The holder door is not a bypass** — `remove_holder` of a CURRENT ADMIN (other than
|
|
21
|
+
* voluntary leave) is refused: holder removal drops admin status too, so allowing it under the
|
|
22
|
+
* single-admin rule would expel an admin on one signature, evading `remove_admin` and the
|
|
23
|
+
* deadlock in one move. Demote first, under remove_admin's rule.
|
|
24
|
+
*
|
|
25
|
+
* Kind/subject semantics (does the subject hold? is it already an admin? last-admin protection)
|
|
26
|
+
* are the causal fold's job (`deriveDocumentState`) and run BEFORE this policy is consulted — it may assume a
|
|
27
|
+
* semantically coherent amendment.
|
|
28
|
+
*/
|
|
29
|
+
function canonical(ids) {
|
|
30
|
+
return [...new Set(ids)].sort();
|
|
31
|
+
}
|
|
32
|
+
/** A duplicated claim is a builder bug, refused — deduping here would hand the multisig layer a
|
|
33
|
+
* collection it THROWS on (`multisig_duplicate_signer`), escaping the derivation's never-throw
|
|
34
|
+
* contract. The two layers agree: duplicates refuse, loudly, at the first gate they reach. */
|
|
35
|
+
function hasDuplicates(ids) {
|
|
36
|
+
return new Set(ids).size !== ids.length;
|
|
37
|
+
}
|
|
38
|
+
function sameSet(a, b) {
|
|
39
|
+
return a.length === b.length && a.every((id, i) => id === b[i]);
|
|
40
|
+
}
|
|
41
|
+
export function documentGovernancePolicy(kind, subjectAgentId, state, claimedRequiredSet) {
|
|
42
|
+
if (hasDuplicates(claimedRequiredSet)) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
reason: "governance_claim_shape: the claimed required set names a signer more than once",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const claimed = canonical(claimedRequiredSet);
|
|
49
|
+
if (claimed.length === 0) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
reason: "governance_claim_shape: a collection nobody is required to sign authorizes nothing",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// SYNC-P2 — the subject's own acts: consent answers an admission, refuse_join declines one.
|
|
56
|
+
// The claim is EXACTLY the subject; no admin can consent on anyone's behalf (R22).
|
|
57
|
+
if (kind === "consent" || kind === "refuse_join" || kind === "close") {
|
|
58
|
+
if (subjectAgentId !== null && claimed.length === 1 && claimed[0] === subjectAgentId) {
|
|
59
|
+
return { ok: true };
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
reason: `governance_consent_self: ${kind} is the subject's own act — the claim must be exactly ` +
|
|
64
|
+
`[${subjectAgentId ?? "the subject"}] and the collection claims [${claimed.join(", ")}]`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// SYNC-P4 (R28): a kill is one admin's own act — self-claimed AND admin-held.
|
|
68
|
+
if (kind === "kill") {
|
|
69
|
+
if (subjectAgentId !== null &&
|
|
70
|
+
claimed.length === 1 &&
|
|
71
|
+
claimed[0] === subjectAgentId &&
|
|
72
|
+
state.admins.has(subjectAgentId)) {
|
|
73
|
+
return { ok: true };
|
|
74
|
+
}
|
|
75
|
+
if (subjectAgentId !== null && !state.admins.has(subjectAgentId)) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
reason: `governance_not_admin: ${subjectAgentId} holds no admin power over this document — ` +
|
|
79
|
+
`ending everyone's document takes a current admin's own signature`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
reason: `governance_consent_self: kill is the admin's own act — the claim must be exactly ` +
|
|
85
|
+
`[${subjectAgentId ?? "the admin"}] and the collection claims [${claimed.join(", ")}]`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (kind === "remove_admin") {
|
|
89
|
+
// The fold already refused a non-admin subject and the last-admin case.
|
|
90
|
+
if (state.admins.size === 2) {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
reason: "governance_two_admin_deadlock: with exactly two admins neither can remove the other " +
|
|
94
|
+
"(D3, by design) — the recourse is to stop working in this document, duplicate it, and " +
|
|
95
|
+
"start fresh without them",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const others = canonical([...state.admins].filter((id) => id !== subjectAgentId));
|
|
99
|
+
if (!sameSet(claimed, others)) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
reason: `governance_remove_admin_set: removing an admin takes the signatures of ALL other ` +
|
|
103
|
+
`admins [${others.join(", ")}] exactly — the subject neither required nor counted — ` +
|
|
104
|
+
`and the collection claims [${claimed.join(", ")}]`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { ok: true };
|
|
108
|
+
}
|
|
109
|
+
// Voluntary leave: the subject signing their own removal, admin or not. Checked before the
|
|
110
|
+
// admin-door rule below so a leaving admin is not told to demote themselves first.
|
|
111
|
+
if (kind === "remove_holder" &&
|
|
112
|
+
subjectAgentId !== null &&
|
|
113
|
+
claimed.length === 1 &&
|
|
114
|
+
claimed[0] === subjectAgentId) {
|
|
115
|
+
return { ok: true };
|
|
116
|
+
}
|
|
117
|
+
if (kind === "remove_holder" && subjectAgentId !== null && state.admins.has(subjectAgentId)) {
|
|
118
|
+
return {
|
|
119
|
+
ok: false,
|
|
120
|
+
reason: "governance_remove_admin_first: a fellow admin cannot be expelled through the holder " +
|
|
121
|
+
"door — holder removal would drop their admin status with it. Demotion takes every " +
|
|
122
|
+
"other admin's signature, and NO VERB FOR THAT EXISTS YET: today the only way an admin " +
|
|
123
|
+
"leaves is to remove themselves (pass their own agent id). Do not wait for a demote " +
|
|
124
|
+
"command; there isn't one.",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// The single-admin kinds: add_holder, promote_admin, remove_holder (non-admin), change_property.
|
|
128
|
+
if (claimed.length !== 1) {
|
|
129
|
+
return {
|
|
130
|
+
ok: false,
|
|
131
|
+
reason: `governance_claim_shape: ${kind} is a single-admin action and the collection claims ` +
|
|
132
|
+
`${claimed.length} required signers — a wider claim lets an absent co-signer veto what ` +
|
|
133
|
+
`the rule gives to any one admin`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (!state.admins.has(claimed[0])) {
|
|
137
|
+
return {
|
|
138
|
+
ok: false,
|
|
139
|
+
reason: `governance_not_admin: ${claimed[0]} holds no admin power over this document — ` +
|
|
140
|
+
`${kind} takes a current admin's signature`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return { ok: true };
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=document-governance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-governance.js","sourceRoot":"","sources":["../src/document-governance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-MP-SIG-1 — the multi-signature primitive: N Ed25519 signatures over ONE preimage.
|
|
3
|
+
*
|
|
4
|
+
* A collection is COMPLETE only when every signer in the required set has a verifying signature —
|
|
5
|
+
* no more, no fewer, no substitutes. Anything short of that is a partial collection: storable
|
|
6
|
+
* while signatures are being gathered, never valid. Completeness is computed independently by any
|
|
7
|
+
* holder from the collection alone plus a verifier; there is no coordinator whose word settles it.
|
|
8
|
+
*
|
|
9
|
+
* ── GENERIC BY CONSTRUCTION ───────────────────────────────────────────────────────────────────
|
|
10
|
+
*
|
|
11
|
+
* Nothing in this module knows what an amendment is. The subject is carried as
|
|
12
|
+
* `(subject_kind, subject_hash)` — the hash of the subject's OWN to-be-signed structure — so the
|
|
13
|
+
* amendment record (its first consumer) and Tier 2's N-way quiescence agreement (its named second)
|
|
14
|
+
* use the same preimage builder and the same completeness rule. Anything subject-specific growing
|
|
15
|
+
* in here is the drift the M14B Tier-2-readiness lens blocks.
|
|
16
|
+
*
|
|
17
|
+
* ── THE PREIMAGE COMMITS TO WHO MUST SIGN ─────────────────────────────────────────────────────
|
|
18
|
+
*
|
|
19
|
+
* `required_signers` is inside the signed bytes, sorted so the set — not the order it was typed
|
|
20
|
+
* in — is what is committed. Each signer therefore signs knowing exactly which co-signatures the
|
|
21
|
+
* collection needs: a signature given as "the sole required signer" cannot be replayed into a
|
|
22
|
+
* collection claiming a different signer set, because the preimage differs and the signature
|
|
23
|
+
* stops verifying. Replay across chain positions is the SUBJECT's job to prevent (its TBS chains
|
|
24
|
+
* to its predecessor), not this layer's.
|
|
25
|
+
*
|
|
26
|
+
* Signatures are Ed25519 (RFC 8032) over the SHA-256 of the preimage array, matching the sibling
|
|
27
|
+
* envelope builders. Verification is injected — the same seam the proposal path uses — so this
|
|
28
|
+
* module stays pure types + bytes.
|
|
29
|
+
*/
|
|
30
|
+
/** Domain tag in slot 0 of the to-be-signed array. Distinct from every sibling envelope domain. */
|
|
31
|
+
export declare const DOCUMENT_MULTISIG_DOMAIN = "CELLO-DOCUMENT-MULTISIG-v1";
|
|
32
|
+
/** The fields the preimage commits to. `signatures` is deliberately NOT part of the TBS. */
|
|
33
|
+
export interface MultisigSubject {
|
|
34
|
+
document_id: string;
|
|
35
|
+
/** What kind of thing is being co-signed, e.g. "document_amendment". Open set on purpose. */
|
|
36
|
+
subject_kind: string;
|
|
37
|
+
/** SHA-256 of the subject's own to-be-signed structure. */
|
|
38
|
+
subject_hash: Uint8Array;
|
|
39
|
+
/** Pubkey-hex identities that must ALL sign. Committed as a sorted set. */
|
|
40
|
+
required_signers: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
export interface MultisigSignature {
|
|
43
|
+
signer_agent_id: string;
|
|
44
|
+
/** Ed25519 (RFC 8032) over `buildDocumentMultisigTbs` of the subject fields. */
|
|
45
|
+
signature: Uint8Array;
|
|
46
|
+
}
|
|
47
|
+
export interface MultisigCollection extends MultisigSubject {
|
|
48
|
+
required_signers: string[];
|
|
49
|
+
signatures: MultisigSignature[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The canonical to-be-signed preimage: a fixed-order CBOR ARRAY with the domain in slot 0.
|
|
53
|
+
* SHA-256 pre-hashed by default, matching the sibling builders.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildDocumentMultisigTbs(subject: MultisigSubject, opts?: {
|
|
56
|
+
preHash?: boolean;
|
|
57
|
+
}): Uint8Array;
|
|
58
|
+
export interface MultisigStatus {
|
|
59
|
+
/** True only when every required signer has exactly one verifying signature and nobody else signed. */
|
|
60
|
+
complete: boolean;
|
|
61
|
+
/** Required signers with no signature present. */
|
|
62
|
+
missing: string[];
|
|
63
|
+
/** Signers present whose signature does not verify against the preimage. */
|
|
64
|
+
invalidSigners: string[];
|
|
65
|
+
/** Signatures from identities OUTSIDE the required set — never counted, always named. */
|
|
66
|
+
unknown: string[];
|
|
67
|
+
/** Signers with more than one signature row — settle once. */
|
|
68
|
+
duplicates: string[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Completeness, computed from the collection alone plus an injected verifier.
|
|
72
|
+
*
|
|
73
|
+
* Every defect class is NAMED rather than folded into a boolean, because the operator-facing
|
|
74
|
+
* question differs: "waiting on C" (missing), "B's signature is bad" (invalid), "someone outside
|
|
75
|
+
* the arrangement signed" (unknown — refused because extra names must not make a collection look
|
|
76
|
+
* more agreed than the rule it commits to), and "B signed twice" (duplicate).
|
|
77
|
+
*/
|
|
78
|
+
export declare function collectionStatus(collection: MultisigCollection, verify: (agentId: string, tbs: Uint8Array, signature: Uint8Array) => boolean): MultisigStatus;
|
|
79
|
+
export declare function encodeMultisigCollection(collection: MultisigCollection): Uint8Array;
|
|
80
|
+
export declare function decodeMultisigCollection(input: Uint8Array): MultisigCollection;
|
|
81
|
+
//# sourceMappingURL=document-multisig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-multisig.d.ts","sourceRoot":"","sources":["../src/document-multisig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,mGAAmG;AACnG,eAAO,MAAM,wBAAwB,+BAA+B,CAAC;AAErE,4FAA4F;AAC5F,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,YAAY,EAAE,UAAU,CAAC;IACzB,2EAA2E;IAC3E,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,SAAS,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAgCD;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,eAAe,EACxB,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/B,UAAU,CAUZ;AAED,MAAM,WAAW,cAAc;IAC7B,uGAAuG;IACvG,QAAQ,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,4EAA4E;IAC5E,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,yFAAyF;IACzF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,GAC3E,cAAc,CAuChB;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,kBAAkB,GAAG,UAAU,CAWnF;AA0BD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,GAAG,kBAAkB,CAoC9E"}
|