@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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-MP-AMEND-1 — the amendment record: an epoch event in its FINAL frame shape, and the replay
|
|
3
|
+
* that derives a document's arrangement from genesis + the chain.
|
|
4
|
+
*
|
|
5
|
+
* The genesis proposal stays the anchor — never edited, still hashing to `document_id`. What may
|
|
6
|
+
* change after it — who holds the document, who administers it, its amendable properties — is
|
|
7
|
+
* derived ONLY from this chain of signed amendments, replayed independently by every holder. An
|
|
8
|
+
* amendment whose signature collection does not meet its kind's requirement is INVALID everywhere,
|
|
9
|
+
* computed rather than detected; that is the invariant that replaced immutability (multiplayer log
|
|
10
|
+
* §6, rulings §13).
|
|
11
|
+
*
|
|
12
|
+
* ── THE FRAME IS FINAL (TIER2-READY constraint 1) ─────────────────────────────────────────────
|
|
13
|
+
*
|
|
14
|
+
* Signed, chained to its predecessor, epoch-incrementing, and carrying `state_hash` — the
|
|
15
|
+
* canonical-hash-at-boundary slot — as DEFINED-ABSENT (`null`) while the tier is `authenticated`.
|
|
16
|
+
* Tier 2 fills the slot; it does not migrate the frame. Dropping the slot "because Tier 1 doesn't
|
|
17
|
+
* use it" is the exact seam violation M14 forbade.
|
|
18
|
+
*
|
|
19
|
+
* ── WHO MUST SIGN IS INJECTED ─────────────────────────────────────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* The replay owns MECHANICS: chaining, completeness, application order, and the arrangement
|
|
22
|
+
* invariants (admins ⊆ participants, admins never empty, the holder cap). WHICH signatures each
|
|
23
|
+
* kind requires is GOVERN-1's policy, consulted against the state BEFORE the amendment — so a
|
|
24
|
+
* newly-promoted admin is required on the NEXT amendment, not retroactively on their own
|
|
25
|
+
* promotion.
|
|
26
|
+
*/
|
|
27
|
+
import { type MultisigCollection } from "./document-multisig.js";
|
|
28
|
+
/**
|
|
29
|
+
* Domain tag in slot 0 of the to-be-signed array. Sibling of the other CELLO-DOCUMENT-* tags.
|
|
30
|
+
* v2 (SYNC-P1): the preimage gained the causal fields — author, sequence, parents. A v1 frame is
|
|
31
|
+
* refused by the mandatory-field discipline below; no compatibility is owed (all holders upgrade
|
|
32
|
+
* together).
|
|
33
|
+
*/
|
|
34
|
+
export declare const DOCUMENT_AMENDMENT_DOMAIN = "CELLO-DOCUMENT-AMENDMENT-v3";
|
|
35
|
+
/**
|
|
36
|
+
* Ceiling on an entry's parent list. The honest frontier is bounded by the holder cap (D5: 20);
|
|
37
|
+
* the ceiling exists so a hostile daemon cannot make every ancestry walk unbounded.
|
|
38
|
+
*/
|
|
39
|
+
export declare const MAX_ENTRY_PARENTS = 64;
|
|
40
|
+
/** The `subject_kind` an amendment's multisig collection must carry. */
|
|
41
|
+
export declare const AMENDMENT_SUBJECT_KIND = "document_amendment";
|
|
42
|
+
/** D5 (ruled 2026-08-11): documents inherit the group-room cap. Enforced at amendment validation. */
|
|
43
|
+
export declare const MAX_DOCUMENT_HOLDERS = 20;
|
|
44
|
+
export declare const AMENDMENT_KINDS: readonly ["add_holder", "remove_holder", "promote_admin", "remove_admin", "change_property", "consent", "refuse_join", "close", "kill"];
|
|
45
|
+
export type AmendmentKind = (typeof AMENDMENT_KINDS)[number];
|
|
46
|
+
/**
|
|
47
|
+
* Properties an amendment may change. Deliberately NARROW to start: the seam properties are owned
|
|
48
|
+
* elsewhere (`assurance_tier` changes are the Tier 2 tier-upgrade epoch event; `schema_enforcement`
|
|
49
|
+
* is Tier 2's schema work; `topology` and `content_profile` are identity-shaped — changing them
|
|
50
|
+
* under a live document is a new agreement, not an amendment). Widening this set is a one-line,
|
|
51
|
+
* journaled decision; shrinking it after documents exist is a migration.
|
|
52
|
+
*/
|
|
53
|
+
export declare const AMENDABLE_PROPERTIES: Set<string>;
|
|
54
|
+
export interface DocumentAmendmentBody {
|
|
55
|
+
document_id: string;
|
|
56
|
+
kind: AmendmentKind;
|
|
57
|
+
/** The holder the amendment is about (pubkey hex). Null exactly for `change_property`. */
|
|
58
|
+
subject_agent_id: string | null;
|
|
59
|
+
/** Non-null exactly for `change_property`. */
|
|
60
|
+
property_change: {
|
|
61
|
+
key: string;
|
|
62
|
+
value: string | number | boolean;
|
|
63
|
+
} | null;
|
|
64
|
+
/**
|
|
65
|
+
* Tier 2's canonical-hash-at-boundary slot. DEFINED-ABSENT (`null`) while the document's tier
|
|
66
|
+
* is `authenticated`; refused non-null at replay until the attested tier exists.
|
|
67
|
+
*/
|
|
68
|
+
state_hash: Uint8Array | null;
|
|
69
|
+
authored_at_ms: number;
|
|
70
|
+
/**
|
|
71
|
+
* SYNC-P1 — the causal fields. The accountable initiator (MUST appear in the collection's
|
|
72
|
+
* required set), their own-chain counter, and the frontier heads applied when authoring. For
|
|
73
|
+
* `author_seq > 1` the author's previous entry MUST be among the ancestors the parents reach —
|
|
74
|
+
* a direct parent is the common case, not the requirement. Signed: a forwarder cannot
|
|
75
|
+
* re-attribute, re-sequence, or re-parent without every signature failing (SYNC-R2).
|
|
76
|
+
*/
|
|
77
|
+
author_agent_id: string;
|
|
78
|
+
author_seq: number;
|
|
79
|
+
/** Entry hashes (64-hex), CANONICAL: strictly ascending, no duplicates. Empty anchors to genesis. */
|
|
80
|
+
parents: readonly string[];
|
|
81
|
+
}
|
|
82
|
+
export interface DocumentAmendmentEnvelope {
|
|
83
|
+
body: DocumentAmendmentBody;
|
|
84
|
+
/** SIG-1 collection over `documentAmendmentHash(body)` with `subject_kind: "document_amendment"`. */
|
|
85
|
+
collection: MultisigCollection;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The canonical to-be-signed preimage: a fixed-order CBOR ARRAY with the domain in slot 0.
|
|
89
|
+
* `property_change` is FLATTENED into two slots — `encodeCbor` maps follow insertion order, and a
|
|
90
|
+
* nested map would make the hash depend on how the builder happened to assemble it.
|
|
91
|
+
*/
|
|
92
|
+
export declare function buildDocumentAmendmentTbs(body: DocumentAmendmentBody, opts?: {
|
|
93
|
+
preHash?: boolean;
|
|
94
|
+
}): Uint8Array;
|
|
95
|
+
/** The amendment's identity: SHA-256 over the TBS preimage — signature-independent, like `document_id`. */
|
|
96
|
+
export declare function documentAmendmentHash(body: DocumentAmendmentBody): Uint8Array;
|
|
97
|
+
export declare function encodeDocumentAmendment(env: DocumentAmendmentEnvelope): Uint8Array;
|
|
98
|
+
export declare function decodeDocumentAmendment(input: Uint8Array): DocumentAmendmentEnvelope;
|
|
99
|
+
/** The genesis facts replay starts from — all of them signed into the proposal (or its admin slot). */
|
|
100
|
+
export interface ArrangementGenesis {
|
|
101
|
+
documentId: string;
|
|
102
|
+
proposerAgentId: string;
|
|
103
|
+
peerAgentId: string;
|
|
104
|
+
/** Pubkey-hex identities holding admin power at creation. Must be ⊆ {proposer, peer}, non-empty. */
|
|
105
|
+
adminSet: readonly string[];
|
|
106
|
+
properties: Record<string, string | number | boolean | undefined>;
|
|
107
|
+
}
|
|
108
|
+
export interface Arrangement {
|
|
109
|
+
epoch: number;
|
|
110
|
+
participants: ReadonlySet<string>;
|
|
111
|
+
/** SYNC-P2: admitted-not-yet-answered (R22). Optional while the interim join surface lives. */
|
|
112
|
+
invited?: ReadonlySet<string>;
|
|
113
|
+
admins: ReadonlySet<string>;
|
|
114
|
+
/** The DERIVED view — genesis properties + applied change_property amendments. */
|
|
115
|
+
properties: Record<string, string | number | boolean | undefined>;
|
|
116
|
+
lastAmendmentHash: string | null;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* GOVERN-1's seam: is the collection's CLAIMED required-signer set acceptable for this amendment,
|
|
120
|
+
* given the arrangement as it stands BEFORE the amendment applies. A verdict rather than a
|
|
121
|
+
* minted set, because "any single admin" has no single answer — {a} and {b} are both acceptable
|
|
122
|
+
* claims — and the multisig layer then demands every claimed signature verify.
|
|
123
|
+
*/
|
|
124
|
+
export type SignerPolicy = (kind: AmendmentKind, subjectAgentId: string | null, state: {
|
|
125
|
+
participants: ReadonlySet<string>;
|
|
126
|
+
admins: ReadonlySet<string>;
|
|
127
|
+
}, claimedRequiredSet: readonly string[]) => {
|
|
128
|
+
ok: true;
|
|
129
|
+
} | {
|
|
130
|
+
ok: false;
|
|
131
|
+
reason: string;
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=document-amendment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-amendment.d.ts","sourceRoot":"","sources":["../src/document-amendment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOD-MP-AMEND-1 — the amendment record: an epoch event in its FINAL frame shape, and the replay
|
|
3
|
+
* that derives a document's arrangement from genesis + the chain.
|
|
4
|
+
*
|
|
5
|
+
* The genesis proposal stays the anchor — never edited, still hashing to `document_id`. What may
|
|
6
|
+
* change after it — who holds the document, who administers it, its amendable properties — is
|
|
7
|
+
* derived ONLY from this chain of signed amendments, replayed independently by every holder. An
|
|
8
|
+
* amendment whose signature collection does not meet its kind's requirement is INVALID everywhere,
|
|
9
|
+
* computed rather than detected; that is the invariant that replaced immutability (multiplayer log
|
|
10
|
+
* §6, rulings §13).
|
|
11
|
+
*
|
|
12
|
+
* ── THE FRAME IS FINAL (TIER2-READY constraint 1) ─────────────────────────────────────────────
|
|
13
|
+
*
|
|
14
|
+
* Signed, chained to its predecessor, epoch-incrementing, and carrying `state_hash` — the
|
|
15
|
+
* canonical-hash-at-boundary slot — as DEFINED-ABSENT (`null`) while the tier is `authenticated`.
|
|
16
|
+
* Tier 2 fills the slot; it does not migrate the frame. Dropping the slot "because Tier 1 doesn't
|
|
17
|
+
* use it" is the exact seam violation M14 forbade.
|
|
18
|
+
*
|
|
19
|
+
* ── WHO MUST SIGN IS INJECTED ─────────────────────────────────────────────────────────────────
|
|
20
|
+
*
|
|
21
|
+
* The replay owns MECHANICS: chaining, completeness, application order, and the arrangement
|
|
22
|
+
* invariants (admins ⊆ participants, admins never empty, the holder cap). WHICH signatures each
|
|
23
|
+
* kind requires is GOVERN-1's policy, consulted against the state BEFORE the amendment — so a
|
|
24
|
+
* newly-promoted admin is required on the NEXT amendment, not retroactively on their own
|
|
25
|
+
* promotion.
|
|
26
|
+
*/
|
|
27
|
+
import { createHash } from "node:crypto";
|
|
28
|
+
import { encodeCbor, decodeCbor } from "./cbor.js";
|
|
29
|
+
import { encodeMultisigCollection, decodeMultisigCollection, } from "./document-multisig.js";
|
|
30
|
+
/**
|
|
31
|
+
* Domain tag in slot 0 of the to-be-signed array. Sibling of the other CELLO-DOCUMENT-* tags.
|
|
32
|
+
* v2 (SYNC-P1): the preimage gained the causal fields — author, sequence, parents. A v1 frame is
|
|
33
|
+
* refused by the mandatory-field discipline below; no compatibility is owed (all holders upgrade
|
|
34
|
+
* together).
|
|
35
|
+
*/
|
|
36
|
+
export const DOCUMENT_AMENDMENT_DOMAIN = "CELLO-DOCUMENT-AMENDMENT-v3";
|
|
37
|
+
/**
|
|
38
|
+
* Ceiling on an entry's parent list. The honest frontier is bounded by the holder cap (D5: 20);
|
|
39
|
+
* the ceiling exists so a hostile daemon cannot make every ancestry walk unbounded.
|
|
40
|
+
*/
|
|
41
|
+
export const MAX_ENTRY_PARENTS = 64;
|
|
42
|
+
/** The `subject_kind` an amendment's multisig collection must carry. */
|
|
43
|
+
export const AMENDMENT_SUBJECT_KIND = "document_amendment";
|
|
44
|
+
/** D5 (ruled 2026-08-11): documents inherit the group-room cap. Enforced at amendment validation. */
|
|
45
|
+
export const MAX_DOCUMENT_HOLDERS = 20;
|
|
46
|
+
export const AMENDMENT_KINDS = [
|
|
47
|
+
"add_holder",
|
|
48
|
+
"remove_holder",
|
|
49
|
+
"promote_admin",
|
|
50
|
+
"remove_admin",
|
|
51
|
+
"change_property",
|
|
52
|
+
// SYNC-P2 (R21/R24): the subject's own acts. A `consent` answers an admission and names what
|
|
53
|
+
// it agrees to in the signed property slots ({ key: "consents_to", value: "<tier>/<version>" });
|
|
54
|
+
// a `refuse_join` ends the invitation. Both are authored, subject-ed, and signed by the same
|
|
55
|
+
// party — nobody consents for you.
|
|
56
|
+
"consent",
|
|
57
|
+
"refuse_join",
|
|
58
|
+
// SYNC-P4 (R26-R28): endings are governance entries like everything else. A `close` is the
|
|
59
|
+
// closer's own signed agreement to end; the document is CLOSED when every current participant
|
|
60
|
+
// holds one (derived, never tracked). A `kill` is any single admin's immediate one-sided end.
|
|
61
|
+
"close",
|
|
62
|
+
"kill",
|
|
63
|
+
];
|
|
64
|
+
/**
|
|
65
|
+
* Properties an amendment may change. Deliberately NARROW to start: the seam properties are owned
|
|
66
|
+
* elsewhere (`assurance_tier` changes are the Tier 2 tier-upgrade epoch event; `schema_enforcement`
|
|
67
|
+
* is Tier 2's schema work; `topology` and `content_profile` are identity-shaped — changing them
|
|
68
|
+
* under a live document is a new agreement, not an amendment). Widening this set is a one-line,
|
|
69
|
+
* journaled decision; shrinking it after documents exist is a migration.
|
|
70
|
+
*/
|
|
71
|
+
export const AMENDABLE_PROPERTIES = new Set(["append_only"]);
|
|
72
|
+
/**
|
|
73
|
+
* The canonical to-be-signed preimage: a fixed-order CBOR ARRAY with the domain in slot 0.
|
|
74
|
+
* `property_change` is FLATTENED into two slots — `encodeCbor` maps follow insertion order, and a
|
|
75
|
+
* nested map would make the hash depend on how the builder happened to assemble it.
|
|
76
|
+
*/
|
|
77
|
+
export function buildDocumentAmendmentTbs(body, opts = {}) {
|
|
78
|
+
const preimage = encodeCbor([
|
|
79
|
+
DOCUMENT_AMENDMENT_DOMAIN,
|
|
80
|
+
body.document_id,
|
|
81
|
+
body.kind,
|
|
82
|
+
body.subject_agent_id,
|
|
83
|
+
body.property_change?.key ?? null,
|
|
84
|
+
body.property_change?.value ?? null,
|
|
85
|
+
body.state_hash,
|
|
86
|
+
// BIGINT past 0xffffffff — the same float64-vs-uint64 coercion every sibling builder carries.
|
|
87
|
+
typeof body.authored_at_ms === "number" && body.authored_at_ms > 0xffffffff
|
|
88
|
+
? BigInt(body.authored_at_ms)
|
|
89
|
+
: body.authored_at_ms,
|
|
90
|
+
body.author_agent_id,
|
|
91
|
+
body.author_seq,
|
|
92
|
+
[...body.parents],
|
|
93
|
+
]);
|
|
94
|
+
if (opts.preHash === false)
|
|
95
|
+
return preimage;
|
|
96
|
+
return new Uint8Array(createHash("sha256").update(preimage).digest());
|
|
97
|
+
}
|
|
98
|
+
/** The amendment's identity: SHA-256 over the TBS preimage — signature-independent, like `document_id`. */
|
|
99
|
+
export function documentAmendmentHash(body) {
|
|
100
|
+
return new Uint8Array(createHash("sha256").update(buildDocumentAmendmentTbs(body, { preHash: false })).digest());
|
|
101
|
+
}
|
|
102
|
+
export function encodeDocumentAmendment(env) {
|
|
103
|
+
return encodeCbor({
|
|
104
|
+
// The FRAME discriminator — how the session router tells an amendment from conversation.
|
|
105
|
+
// Not part of the TBS (the hash and every signature are over the body's preimage), so its
|
|
106
|
+
// absence in early builds cost classification, never integrity.
|
|
107
|
+
type: "document_amendment",
|
|
108
|
+
body: {
|
|
109
|
+
document_id: env.body.document_id,
|
|
110
|
+
kind: env.body.kind,
|
|
111
|
+
subject_agent_id: env.body.subject_agent_id,
|
|
112
|
+
property_change: env.body.property_change,
|
|
113
|
+
state_hash: env.body.state_hash,
|
|
114
|
+
authored_at_ms: env.body.authored_at_ms,
|
|
115
|
+
author_agent_id: env.body.author_agent_id,
|
|
116
|
+
author_seq: env.body.author_seq,
|
|
117
|
+
parents: [...env.body.parents],
|
|
118
|
+
},
|
|
119
|
+
collection: encodeMultisigCollection(env.collection),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function present(map, field) {
|
|
123
|
+
if (!(field in map)) {
|
|
124
|
+
throw new Error(`document_amendment_missing_field: ${field} is mandatory and was not present`);
|
|
125
|
+
}
|
|
126
|
+
return map[field];
|
|
127
|
+
}
|
|
128
|
+
function str(map, field) {
|
|
129
|
+
const v = present(map, field);
|
|
130
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
131
|
+
throw new Error(`document_amendment_field_type: ${field} must be a non-empty text string`);
|
|
132
|
+
}
|
|
133
|
+
return v;
|
|
134
|
+
}
|
|
135
|
+
export function decodeDocumentAmendment(input) {
|
|
136
|
+
const decoded = decodeCbor(input);
|
|
137
|
+
if (typeof decoded !== "object" || decoded === null || Array.isArray(decoded)) {
|
|
138
|
+
throw new Error("document_amendment_malformed: not a CBOR map");
|
|
139
|
+
}
|
|
140
|
+
const map = decoded;
|
|
141
|
+
const frameType = present(map, "type");
|
|
142
|
+
if (frameType !== "document_amendment") {
|
|
143
|
+
throw new Error(`document_amendment_type: expected document_amendment, got ${String(frameType)}`);
|
|
144
|
+
}
|
|
145
|
+
const rawBody = present(map, "body");
|
|
146
|
+
if (typeof rawBody !== "object" || rawBody === null || Array.isArray(rawBody)) {
|
|
147
|
+
throw new Error("document_amendment_field_type: body must be a CBOR map");
|
|
148
|
+
}
|
|
149
|
+
const b = rawBody;
|
|
150
|
+
const kind = str(b, "kind");
|
|
151
|
+
if (!AMENDMENT_KINDS.includes(kind)) {
|
|
152
|
+
throw new Error(`document_amendment_kind: "${kind}" is not an amendment kind this build knows ` +
|
|
153
|
+
`(${AMENDMENT_KINDS.join(", ")})`);
|
|
154
|
+
}
|
|
155
|
+
const subject = present(b, "subject_agent_id");
|
|
156
|
+
if (subject !== null && (typeof subject !== "string" || subject.length === 0)) {
|
|
157
|
+
throw new Error("document_amendment_field_type: subject_agent_id must be a non-empty string or explicit null");
|
|
158
|
+
}
|
|
159
|
+
const rawChange = present(b, "property_change");
|
|
160
|
+
let propertyChange = null;
|
|
161
|
+
if (rawChange !== null) {
|
|
162
|
+
if (typeof rawChange !== "object" || Array.isArray(rawChange)) {
|
|
163
|
+
throw new Error("document_amendment_field_type: property_change must be a CBOR map or null");
|
|
164
|
+
}
|
|
165
|
+
const c = rawChange;
|
|
166
|
+
const key = str(c, "key");
|
|
167
|
+
const value = present(c, "value");
|
|
168
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
169
|
+
throw new Error("document_amendment_field_type: property_change.value must be a string, number, or boolean");
|
|
170
|
+
}
|
|
171
|
+
propertyChange = { key, value };
|
|
172
|
+
}
|
|
173
|
+
const stateHash = present(b, "state_hash");
|
|
174
|
+
if (stateHash !== null && !(stateHash instanceof Uint8Array)) {
|
|
175
|
+
throw new Error("document_amendment_field_type: state_hash must be a CBOR byte string or explicit null");
|
|
176
|
+
}
|
|
177
|
+
const authoredAt = present(b, "authored_at_ms");
|
|
178
|
+
if (typeof authoredAt !== "number" || !Number.isInteger(authoredAt)) {
|
|
179
|
+
throw new Error("document_amendment_field_type: authored_at_ms must be an integer");
|
|
180
|
+
}
|
|
181
|
+
const author = present(b, "author_agent_id");
|
|
182
|
+
if (typeof author !== "string" || !/^[0-9a-f]{64}$/.test(author)) {
|
|
183
|
+
throw new Error("document_amendment_field_type: author_agent_id must be a 64-hex agent pubkey");
|
|
184
|
+
}
|
|
185
|
+
const authorSeq = present(b, "author_seq");
|
|
186
|
+
if (typeof authorSeq !== "number" || !Number.isInteger(authorSeq) || authorSeq < 1) {
|
|
187
|
+
throw new Error(`document_amendment_author_seq: must be a positive integer (an author's own chain starts ` +
|
|
188
|
+
`at 1), got ${String(authorSeq)}`);
|
|
189
|
+
}
|
|
190
|
+
const rawParents = present(b, "parents");
|
|
191
|
+
if (!Array.isArray(rawParents)) {
|
|
192
|
+
throw new Error("document_amendment_field_type: parents must be an array of entry hashes");
|
|
193
|
+
}
|
|
194
|
+
if (rawParents.length > MAX_ENTRY_PARENTS) {
|
|
195
|
+
throw new Error(`document_amendment_parents_cap: ${rawParents.length} parents exceeds the ceiling of ` +
|
|
196
|
+
`${MAX_ENTRY_PARENTS} — an honest frontier is bounded by the holder cap`);
|
|
197
|
+
}
|
|
198
|
+
for (const p of rawParents) {
|
|
199
|
+
if (typeof p !== "string" || !/^[0-9a-f]{64}$/.test(p)) {
|
|
200
|
+
throw new Error("document_amendment_field_type: parents must be 64-hex entry hashes");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const parents = rawParents;
|
|
204
|
+
for (let i = 1; i < parents.length; i++) {
|
|
205
|
+
if (parents[i] <= parents[i - 1]) {
|
|
206
|
+
throw new Error("document_amendment_parents_canonical: parents must be strictly ascending with no " +
|
|
207
|
+
"duplicates — one entry, one identity");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const rawCollection = present(map, "collection");
|
|
211
|
+
if (!(rawCollection instanceof Uint8Array)) {
|
|
212
|
+
throw new Error("document_amendment_field_type: collection must be a CBOR byte string");
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
body: {
|
|
216
|
+
document_id: str(b, "document_id"),
|
|
217
|
+
kind: kind,
|
|
218
|
+
subject_agent_id: subject,
|
|
219
|
+
property_change: propertyChange,
|
|
220
|
+
state_hash: stateHash === null ? null : new Uint8Array(stateHash),
|
|
221
|
+
authored_at_ms: authoredAt,
|
|
222
|
+
author_agent_id: author,
|
|
223
|
+
author_seq: authorSeq,
|
|
224
|
+
parents,
|
|
225
|
+
},
|
|
226
|
+
collection: decodeMultisigCollection(new Uint8Array(rawCollection)),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=document-amendment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-amendment.js","sourceRoot":"","sources":["../src/document-amendment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SYNC-P1 — the causal derivation. ONE derivation of a document's state for every holder: the
|
|
3
|
+
* fold over the entry DAG in a deterministic total order. Same entry set → same state, everywhere,
|
|
4
|
+
* always. This file replaces the linear epoch replay; the fold rules are M14B Build Journal
|
|
5
|
+
* Entries 48–49 (SYNC-G2's finding plus its admin-floor addendum).
|
|
6
|
+
*
|
|
7
|
+
* The total order is Kahn's topological sort refined by ascending entry hash — a pure function of
|
|
8
|
+
* the entry SET. The hash tie-break resolves only what is semantically arbitrary (which property
|
|
9
|
+
* value wins). It never resolves authority: causal concurrency is author-claimable (a modified
|
|
10
|
+
* daemon backdates its parents at will), so any rule where a concurrent act could beat a removal
|
|
11
|
+
* would make removal defeatable. Hence the fold rules:
|
|
12
|
+
*
|
|
13
|
+
* F1. A non-removal entry takes effect iff it validates against the folded state at its position
|
|
14
|
+
* AND it is not concurrent with an ancestor-valid removal of its author.
|
|
15
|
+
* F2. A removal is judged at its OWN ancestors (the state derived from its ancestor closure) and
|
|
16
|
+
* is exempt from F1's concurrency void — the exemption is what keeps mutual removals from
|
|
17
|
+
* being circular. At fold position it is void only by the admin floor: a removal that would
|
|
18
|
+
* leave zero admins does not take effect.
|
|
19
|
+
* F3. Content admissibility is R20's (ancestor-based) and is NOT this module's concern.
|
|
20
|
+
* F4. A void entry stays in the linearization — history, not refusal — and contributes nothing.
|
|
21
|
+
*/
|
|
22
|
+
import { type DocumentAmendmentEnvelope, type ArrangementGenesis, type SignerPolicy } from "./document-amendment.js";
|
|
23
|
+
export interface DocumentStateView {
|
|
24
|
+
participants: ReadonlySet<string>;
|
|
25
|
+
/** Admitted, not yet answered (R22) — a seat at the table, not a voice. Counts toward the cap. */
|
|
26
|
+
invited: ReadonlySet<string>;
|
|
27
|
+
admins: ReadonlySet<string>;
|
|
28
|
+
/** R27/R28 — DERIVED, never tracked: "closed" when every current participant has closed;
|
|
29
|
+
* "killed" on any admin's kill; null while live. */
|
|
30
|
+
ended: "closed" | "killed" | null;
|
|
31
|
+
/** Who has agreed to close — the surface's "waiting on" list is its complement. */
|
|
32
|
+
closedBy: ReadonlySet<string>;
|
|
33
|
+
properties: Record<string, string | number | boolean | undefined>;
|
|
34
|
+
/** The total order actually folded (applied AND void entries — F4 keeps voids in history). */
|
|
35
|
+
order: readonly string[];
|
|
36
|
+
/** Heads: included entries no other included entry names as a parent. Ascending. */
|
|
37
|
+
frontier: readonly string[];
|
|
38
|
+
/** Fold-void entries, each with the reason it contributed nothing. */
|
|
39
|
+
voids: readonly {
|
|
40
|
+
hash: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
}[];
|
|
43
|
+
/** Entries whose ancestry is not fully present — held out entirely, never guessed at (R14). */
|
|
44
|
+
excluded: readonly {
|
|
45
|
+
hash: string;
|
|
46
|
+
reason: string;
|
|
47
|
+
}[];
|
|
48
|
+
/** Highest seq per author among included entries — the watermark seed. */
|
|
49
|
+
authorSeqs: ReadonlyMap<string, number>;
|
|
50
|
+
/** Interim carrier fields until P4 deletes the epoch spine (D7, gated on SYNC-G1). */
|
|
51
|
+
interimLastHash: string | null;
|
|
52
|
+
}
|
|
53
|
+
export type DeriveDocumentStateResult = {
|
|
54
|
+
ok: true;
|
|
55
|
+
state: DocumentStateView;
|
|
56
|
+
} | {
|
|
57
|
+
ok: false;
|
|
58
|
+
reason: string;
|
|
59
|
+
};
|
|
60
|
+
type VerifyFn = (agentId: string, tbs: Uint8Array, signature: Uint8Array) => boolean;
|
|
61
|
+
/**
|
|
62
|
+
* SYNC-G1 — the derivation AT a named governance frontier: the fold restricted to the ancestor
|
|
63
|
+
* closure of `frontierHashes`. This is what content admissibility rules on (R20/R30): was the
|
|
64
|
+
* envelope's author a participant in the world its signed `governance_parents` name? Judged
|
|
65
|
+
* from the named ancestors alone — the same bounded backdating concession Entry 48 accepted
|
|
66
|
+
* for governance: a lying daemon admits exactly what an honest holder AT THAT POSITION could
|
|
67
|
+
* have authored, and the fold's removal dominance keeps it out of governance regardless.
|
|
68
|
+
*
|
|
69
|
+
* A frontier hash not present in `entries` is the caller's signal to reconcile first — this
|
|
70
|
+
* function reports it rather than guessing (`missing`).
|
|
71
|
+
*/
|
|
72
|
+
export declare function deriveDocumentStateAt(genesis: ArrangementGenesis, entries: readonly DocumentAmendmentEnvelope[], frontierHashes: readonly string[], policy: SignerPolicy, verify: VerifyFn): {
|
|
73
|
+
ok: true;
|
|
74
|
+
state: DocumentStateView;
|
|
75
|
+
} | {
|
|
76
|
+
ok: false;
|
|
77
|
+
reason: string;
|
|
78
|
+
missing?: string[];
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The STATE-INDEPENDENT admission check — what an inbound path may refuse outright, because no
|
|
82
|
+
* future entry can ever make it good: the collection must bind to this entry, the claimed author
|
|
83
|
+
* must be in the required set, and every claimed signature must verify. Everything else — subject
|
|
84
|
+
* semantics, policy, concurrency — is the fold's ruling, and a fold-void entry is still HISTORY
|
|
85
|
+
* (F4): it must be stored and shared, never bounced at the door, or two holders end up holding
|
|
86
|
+
* different sets.
|
|
87
|
+
*/
|
|
88
|
+
export declare function checkEntryAdmissible(env: DocumentAmendmentEnvelope, verify: VerifyFn): {
|
|
89
|
+
ok: true;
|
|
90
|
+
} | {
|
|
91
|
+
ok: false;
|
|
92
|
+
reason: string;
|
|
93
|
+
};
|
|
94
|
+
export declare function deriveDocumentState(genesis: ArrangementGenesis, entries: readonly DocumentAmendmentEnvelope[], policy: SignerPolicy, verify: VerifyFn): DeriveDocumentStateResult;
|
|
95
|
+
export {};
|
|
96
|
+
//# sourceMappingURL=document-derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-derive.d.ts","sourceRoot":"","sources":["../src/document-derive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAKL,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,YAAY,EAClB,MAAM,yBAAyB,CAAC;AAIjC,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,kGAAkG;IAClG,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5B;yDACqD;IACrD,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IAClC,mFAAmF;IACnF,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IAClE,8FAA8F;IAC9F,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,oFAAoF;IACpF,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,sEAAsE;IACtE,KAAK,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACnD,+FAA+F;IAC/F,QAAQ,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtD,0EAA0E;IAC1E,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,sFAAsF;IACtF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC;AAErF;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,SAAS,yBAAyB,EAAE,EAC7C,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,QAAQ,GACf;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CA8B5F;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,yBAAyB,EAC9B,MAAM,EAAE,QAAQ,GACf;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA0C9C;AAqBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,SAAS,yBAAyB,EAAE,EAC7C,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,QAAQ,GACf,yBAAyB,CAkhB3B"}
|