@volter/world-core 2.0.32 → 2.0.34
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/src/changeset.d.ts +21 -1
- package/dist/src/changeset.js +0 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
- package/src/changeset.ts +35 -4
- package/src/index.ts +1 -0
package/dist/src/changeset.d.ts
CHANGED
|
@@ -141,6 +141,15 @@ export type Changeset = {
|
|
|
141
141
|
/** The author's own words for the changeset (git's commit message) — what `volter changeset -m`
|
|
142
142
|
* records. Outside the hash, like the narration; a reviewer reads both. */
|
|
143
143
|
message?: string;
|
|
144
|
+
/** Who cut it, as the World names a caller (`key:<name>`, `key:<name> for:<person>`, `person:<who>`, `machine`, `person`,
|
|
145
|
+
* `token`); the command on this machine records its signed-in person, and is absent when no one is signed in there.
|
|
146
|
+
* Outside the hash, as approvals are (docs/contributing/architecture.md, "Who acted is recorded"). */
|
|
147
|
+
cutBy?: string;
|
|
148
|
+
/** The person accountable for it: the cutting grant's person, else the pusher's person when it lands in a shared World
|
|
149
|
+
* with none. Outside the hash. */
|
|
150
|
+
owner?: string;
|
|
151
|
+
/** Who pushed it into the World that keeps this copy, a caller as `cutBy` names one. Outside the hash. */
|
|
152
|
+
pushedBy?: string;
|
|
144
153
|
/** v3 — set by `rebaseChangeset`: the hash this object was rebased from, and when. Outside the hash. */
|
|
145
154
|
rebasedFrom?: {
|
|
146
155
|
contentHash: string;
|
|
@@ -212,6 +221,8 @@ export declare function buildChangeset(opts: {
|
|
|
212
221
|
createdAt?: string;
|
|
213
222
|
message?: string;
|
|
214
223
|
cut?: Record<string, HistoryReference>;
|
|
224
|
+
cutBy?: string;
|
|
225
|
+
owner?: string;
|
|
215
226
|
}): Changeset;
|
|
216
227
|
/** Fill the lifecycle fields a changeset authored before v1 lacks on disk, without touching
|
|
217
228
|
* its hash (absent and empty `verifiers` hash identically by construction). */
|
|
@@ -329,6 +340,9 @@ export type ChangesetReadiness = {
|
|
|
329
340
|
contentHash: string;
|
|
330
341
|
/** stored hash matches the body */
|
|
331
342
|
hashOk: boolean;
|
|
343
|
+
/** the different people whose approvals bind to the current hash, and how many this World requires */
|
|
344
|
+
approvers: number;
|
|
345
|
+
required: number;
|
|
332
346
|
/** a verification exists, binds to the current hash, and every verifier passed */
|
|
333
347
|
verified: boolean;
|
|
334
348
|
verification: ChangesetVerification | null;
|
|
@@ -340,7 +354,13 @@ export type ChangesetReadiness = {
|
|
|
340
354
|
/** empty exactly when ready */
|
|
341
355
|
reasons: string[];
|
|
342
356
|
};
|
|
343
|
-
|
|
357
|
+
/** Ready to apply: hashed as authored, verified against its current contents, and approved for them by `rules.approvals`
|
|
358
|
+
* different people (the World's changeset rules; one when it names none). */
|
|
359
|
+
/** Whom an approval counts for: the person a key acts for (`key:<name> for:<person>`), else the principal itself. */
|
|
360
|
+
export declare function approverOf(principal: string): string;
|
|
361
|
+
export declare function changesetReadiness(changeset: Changeset, rules?: {
|
|
362
|
+
approvals?: number;
|
|
363
|
+
}): ChangesetReadiness;
|
|
344
364
|
/** The single honest line `changeset status` prints. No push here — v2's job; this line only
|
|
345
365
|
* tells the truth about the object. */
|
|
346
366
|
export declare function formatChangesetStatus(readiness: ChangesetReadiness): string;
|
package/dist/src/changeset.js
CHANGED
|
Binary file
|
package/dist/src/index.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export { forkTwin, isFork, readForkMeta, } from './fork.js';
|
|
|
41
41
|
export type { ForkMeta } from './fork.js';
|
|
42
42
|
export { appendAction, appendTransactionCommit, checkPrecondition, confirmAction, listActions, listTransactionCommits, pendingActions, pushablePendingActions, isTwinBookkeeping, pendingTransactionCommits, projectResources, projectOwnerResources, OwnerStoreAmbiguousError, revertAction, TwinActionPreconditionError, subjectAliases, resolveSubjectId, runWithCorrelationId, currentCorrelationId } from './actions.js';
|
|
43
43
|
export type { ActionProjection, ProjectedDelivery, ProjectedResource, ProjectedResourcePatch, ProjectedResourceRef, TwinAction, TwinActionOp, TwinActionPrecondition, TwinActionPreconditionOp, TwinActionRevertSpec, TwinTransactionCommit, TwinTransactionCommitOp, TwinTransactionPrecondition, TwinTransactionRevertSpec, } from './actions.js';
|
|
44
|
-
export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from './changeset.js';
|
|
44
|
+
export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, approverOf, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from './changeset.js';
|
|
45
45
|
export type { ApplyReceipt, RebaseActionResult, RebaseReport, RebaseTarget, Changeset, ChangesetAction, ChangesetApplication, CompensationEntry, ChangesetApproval, ChangesetReadiness, ChangesetVerification, ChangesetVerifier, ChangesetVerifierResult, LedgerDelta, LedgerPosition, LedgerRef, ReplayActionResult, ReplayReport, ReplayTarget, VendorSummary, WorldMarker, } from './changeset.js';
|
|
46
46
|
export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets, type PackAssetStore } from './pack-assets.js';
|
|
47
47
|
export * as git from './git/index.js';
|
package/dist/src/index.js
CHANGED
|
@@ -66,7 +66,7 @@ export { appendAction, appendTransactionCommit, checkPrecondition, confirmAction
|
|
|
66
66
|
// the content-addressed, replayable changeset over that delta. State-level by construction
|
|
67
67
|
// (it reads the same per-service action ledgers `actions.ts` writes); `volter-world` supplies
|
|
68
68
|
// world discovery and thin verbs on top.
|
|
69
|
-
export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from "./changeset.js";
|
|
69
|
+
export { approveChangeset, assertMarkerBelongsTo, assertSafeChangesetName, assertValidVerifiers, buildChangeset, captureMarker, changesetContentHash, changesetHashMatches, changesetReadiness, approverOf, CHANGESET_KIND, diffLedgers, formatApplication, formatChangeset, formatRebaseReport, narrateActions, narrationDrift, rebaseChangeset, formatChangesetStatus, formatLedgerDelta, formatReplayReport, formatVerification, MARKER_KIND, normalizeChangeset, parseVerifierExpression, replayChangeset, runChangesetVerifiers, summarizeByVendor, twinWriteShape, withApplication, withVerification, worldBootMarker, WORLD_BOOT_MARKER_ID, } from "./changeset.js";
|
|
70
70
|
export { getActivePackAssets, setActivePackAssets, packAsset, assetContentType, confinedAssetPath, LocalPackAssets, BindingPackAssets } from "./pack-assets.js";
|
|
71
71
|
// The git plane (contract "The git plane is a kernel library"): objects, packs, refs, smart HTTP.
|
|
72
72
|
export * as git from "./git/index.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.34",
|
|
4
4
|
"description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|
package/src/changeset.ts
CHANGED
|
@@ -210,6 +210,15 @@ export type Changeset = {
|
|
|
210
210
|
/** The author's own words for the changeset (git's commit message) — what `volter changeset -m`
|
|
211
211
|
* records. Outside the hash, like the narration; a reviewer reads both. */
|
|
212
212
|
message?: string;
|
|
213
|
+
/** Who cut it, as the World names a caller (`key:<name>`, `key:<name> for:<person>`, `person:<who>`, `machine`, `person`,
|
|
214
|
+
* `token`); the command on this machine records its signed-in person, and is absent when no one is signed in there.
|
|
215
|
+
* Outside the hash, as approvals are (docs/contributing/architecture.md, "Who acted is recorded"). */
|
|
216
|
+
cutBy?: string;
|
|
217
|
+
/** The person accountable for it: the cutting grant's person, else the pusher's person when it lands in a shared World
|
|
218
|
+
* with none. Outside the hash. */
|
|
219
|
+
owner?: string;
|
|
220
|
+
/** Who pushed it into the World that keeps this copy, a caller as `cutBy` names one. Outside the hash. */
|
|
221
|
+
pushedBy?: string;
|
|
213
222
|
/** v3 — set by `rebaseChangeset`: the hash this object was rebased from, and when. Outside the hash. */
|
|
214
223
|
rebasedFrom?: { contentHash: string; at: string };
|
|
215
224
|
/** PROTOCOL 2 — where the parent log stood when this was cut, per state service (its entry count):
|
|
@@ -454,7 +463,7 @@ export function parseVerifierExpression(expression: string, id: string): Changes
|
|
|
454
463
|
}
|
|
455
464
|
|
|
456
465
|
/** Freeze a delta into a named, content-addressed changeset. */
|
|
457
|
-
export function buildChangeset(opts: { name: string; world: string; base: string; actions: ChangesetAction[]; verifiers?: ChangesetVerifier[]; createdAt?: string; message?: string; cut?: Record<string, HistoryReference
|
|
466
|
+
export function buildChangeset(opts: { name: string; world: string; base: string; actions: ChangesetAction[]; verifiers?: ChangesetVerifier[]; createdAt?: string; message?: string; cut?: Record<string, HistoryReference>; cutBy?: string; owner?: string }): Changeset {
|
|
458
467
|
assertSafeChangesetName(opts.name);
|
|
459
468
|
const verifiers = assertValidVerifiers(opts.verifiers ?? []);
|
|
460
469
|
const core = { id: `chg_${opts.name}`, world: opts.world, base: opts.base, actions: opts.actions, verifiers, ...(opts.cut === undefined ? {} : { cut: opts.cut }) };
|
|
@@ -468,6 +477,8 @@ export function buildChangeset(opts: { name: string; world: string; base: string
|
|
|
468
477
|
applied: null,
|
|
469
478
|
narration: narrateActions(opts.actions),
|
|
470
479
|
...(opts.message === undefined ? {} : { message: opts.message }),
|
|
480
|
+
...(opts.cutBy === undefined ? {} : { cutBy: opts.cutBy }),
|
|
481
|
+
...(opts.owner === undefined ? {} : { owner: opts.owner }),
|
|
471
482
|
contentHash: changesetContentHash(core),
|
|
472
483
|
};
|
|
473
484
|
}
|
|
@@ -509,6 +520,9 @@ function renderVerificationLines(changeset: Changeset): string[] {
|
|
|
509
520
|
lines.push(` FAIL ${result.id}: ${renderAssert(result)} — actual ${result.actual === undefined ? 'undefined' : JSON.stringify(result.actual)}`);
|
|
510
521
|
}
|
|
511
522
|
}
|
|
523
|
+
// who: cut by, owned by, pushed by (each only when recorded)
|
|
524
|
+
const who = [changeset.cutBy ? `cut by ${changeset.cutBy}` : null, changeset.owner ? `owned by ${changeset.owner}` : null, changeset.pushedBy ? `pushed by ${changeset.pushedBy}` : null].filter(Boolean);
|
|
525
|
+
if (who.length) lines.push(` ${who.join(' · ')}`);
|
|
512
526
|
if (changeset.approvals.length === 0) {
|
|
513
527
|
lines.push(' approvals: none');
|
|
514
528
|
} else {
|
|
@@ -790,6 +804,9 @@ export type ChangesetReadiness = {
|
|
|
790
804
|
contentHash: string;
|
|
791
805
|
/** stored hash matches the body */
|
|
792
806
|
hashOk: boolean;
|
|
807
|
+
/** the different people whose approvals bind to the current hash, and how many this World requires */
|
|
808
|
+
approvers: number;
|
|
809
|
+
required: number;
|
|
793
810
|
/** a verification exists, binds to the current hash, and every verifier passed */
|
|
794
811
|
verified: boolean;
|
|
795
812
|
verification: ChangesetVerification | null;
|
|
@@ -802,7 +819,14 @@ export type ChangesetReadiness = {
|
|
|
802
819
|
reasons: string[];
|
|
803
820
|
};
|
|
804
821
|
|
|
805
|
-
|
|
822
|
+
/** Ready to apply: hashed as authored, verified against its current contents, and approved for them by `rules.approvals`
|
|
823
|
+
* different people (the World's changeset rules; one when it names none). */
|
|
824
|
+
/** Whom an approval counts for: the person a key acts for (`key:<name> for:<person>`), else the principal itself. */
|
|
825
|
+
export function approverOf(principal: string): string {
|
|
826
|
+
const at = principal.indexOf(' for:');
|
|
827
|
+
return principal.startsWith('key:') && at > 0 ? principal.slice(at + ' for:'.length) : principal;
|
|
828
|
+
}
|
|
829
|
+
export function changesetReadiness(changeset: Changeset, rules: { approvals?: number } = {}): ChangesetReadiness {
|
|
806
830
|
const bodyHash = changesetContentHash(changeset);
|
|
807
831
|
const hashOk = changeset.contentHash === bodyHash;
|
|
808
832
|
const verification = changeset.verification;
|
|
@@ -820,8 +844,13 @@ export function changesetReadiness(changeset: Changeset): ChangesetReadiness {
|
|
|
820
844
|
const failed = verification.results.filter((result) => !result.passed);
|
|
821
845
|
reasons.push(`verification FAILED: ${failed.map((result) => result.id).join(', ')} (${failed.length} of ${verification.results.length})`);
|
|
822
846
|
}
|
|
823
|
-
|
|
824
|
-
|
|
847
|
+
const required = rules.approvals ?? 1;
|
|
848
|
+
// different people: a key's approval (`key:<name> for:<person>`) is its person's, so a person and their agent are one
|
|
849
|
+
const approvers = new Set(binding.map((approval) => approverOf(approval.principal))).size;
|
|
850
|
+
if (approvers < required) {
|
|
851
|
+
reasons.push(binding.length === 0
|
|
852
|
+
? (changeset.approvals.length ? 'no approval binds to the current body hash' : 'no approvals — run `changeset approve --as <principal>`')
|
|
853
|
+
: `${approvers} of the ${required} approvals this World requires`);
|
|
825
854
|
}
|
|
826
855
|
|
|
827
856
|
const verified = Boolean(hashOk && verification && verification.contentHash === changeset.contentHash && verification.passed);
|
|
@@ -830,6 +859,8 @@ export function changesetReadiness(changeset: Changeset): ChangesetReadiness {
|
|
|
830
859
|
world: changeset.world,
|
|
831
860
|
contentHash: changeset.contentHash,
|
|
832
861
|
hashOk,
|
|
862
|
+
approvers,
|
|
863
|
+
required,
|
|
833
864
|
verified,
|
|
834
865
|
verification,
|
|
835
866
|
approvals: changeset.approvals.length,
|