@lapxo/bound 0.1.8 → 0.1.9
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/README.md +56 -20
- package/TARGET.bound +25 -25
- package/dist/cli/accept.js +83 -59
- package/dist/cli/act-result.d.ts +9 -0
- package/dist/cli/act-result.js +68 -13
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.js +5 -2
- package/dist/cli/custodian.d.ts +1 -0
- package/dist/cli/custodian.js +29 -0
- package/dist/cli/native-descendant.d.ts +1 -0
- package/dist/cli/native-descendant.js +19 -0
- package/dist/cli/native.d.ts +1 -0
- package/dist/cli/native.js +60 -0
- package/dist/cli/observe.js +9 -2
- package/dist/cli/pass.js +6 -1
- package/dist/cli/standing-result.js +7 -26
- package/dist/cli/verb.js +24 -5
- package/dist/fold/admission-history.js +2 -2
- package/dist/fold/claims.d.ts +4 -0
- package/dist/fold/claims.js +23 -3
- package/dist/fold/closed.d.ts +1 -1
- package/dist/fold/closed.js +16 -4
- package/dist/fold/digests.d.ts +1 -1
- package/dist/fold/digests.js +3 -2
- package/dist/fold/evidence.d.ts +1 -1
- package/dist/fold/kept.js +2 -1
- package/dist/fold/observed.d.ts +1 -0
- package/dist/fold/observed.js +54 -9
- package/dist/fold/readers.d.ts +4 -3
- package/dist/fold/readers.js +18 -13
- package/dist/fold/resolved.js +11 -1
- package/dist/fold/signers.js +2 -2
- package/dist/host/adapters/modules/javascript.d.ts +2 -0
- package/dist/host/adapters/modules/javascript.js +8 -6
- package/dist/host/admitted-place.d.ts +5 -0
- package/dist/host/admitted-place.js +54 -0
- package/dist/host/capsule-process.d.ts +1 -1
- package/dist/host/capsule-process.js +4 -1
- package/dist/host/capsule.d.ts +4 -0
- package/dist/host/capsule.js +16 -2
- package/dist/host/contextual-place.d.ts +59 -0
- package/dist/host/contextual-place.js +77 -0
- package/dist/host/hash.d.ts +7 -0
- package/dist/host/hash.js +6 -0
- package/dist/host/io.d.ts +2 -0
- package/dist/host/io.js +2 -0
- package/dist/host/lifetime.js +61 -22
- package/dist/host/native/bounded-file.d.ts +8 -0
- package/dist/host/native/bounded-file.js +32 -0
- package/dist/host/native/command.d.ts +36 -0
- package/dist/host/native/command.js +91 -0
- package/dist/host/native/control-bridge-worker.d.ts +1 -0
- package/dist/host/native/control-bridge-worker.js +88 -0
- package/dist/host/native/control-bridge.d.ts +30 -0
- package/dist/host/native/control-bridge.js +110 -0
- package/dist/host/native/control-selection.d.ts +29 -0
- package/dist/host/native/control-selection.js +32 -0
- package/dist/host/native/custody.d.ts +5 -0
- package/dist/host/native/custody.js +91 -0
- package/dist/host/native/deadline.d.ts +12 -0
- package/dist/host/native/deadline.js +28 -0
- package/dist/host/native/descendants.d.ts +1 -0
- package/dist/host/native/descendants.js +528 -0
- package/dist/host/native/generated-custodian.d.ts +122 -0
- package/dist/host/native/generated-custodian.js +267 -0
- package/dist/host/native/generated.d.ts +217 -0
- package/dist/host/native/generated.js +379 -0
- package/dist/host/native/image.d.ts +36 -0
- package/dist/host/native/image.js +45 -0
- package/dist/host/native/jobs.d.ts +75 -0
- package/dist/host/native/jobs.js +148 -0
- package/dist/host/native/loader.d.ts +80 -0
- package/dist/host/native/loader.js +269 -0
- package/dist/host/native/materialize.d.ts +22 -0
- package/dist/host/native/materialize.js +175 -0
- package/dist/host/native/module-closure.d.ts +27 -0
- package/dist/host/native/module-closure.js +99 -0
- package/dist/host/native/module-syntax.d.ts +8 -0
- package/dist/host/native/module-syntax.js +63 -0
- package/dist/host/native/native-binary.d.ts +54 -0
- package/dist/host/native/native-binary.js +115 -0
- package/dist/host/native/native-program.d.ts +56 -0
- package/dist/host/native/native-program.js +72 -0
- package/dist/host/native/node-jobs.d.ts +84 -0
- package/dist/host/native/node-jobs.js +187 -0
- package/dist/host/native/node-launch.d.ts +72 -0
- package/dist/host/native/node-launch.js +159 -0
- package/dist/host/native/preload.d.ts +1 -0
- package/dist/host/native/preload.js +45 -0
- package/dist/host/native/reading.d.ts +91 -0
- package/dist/host/native/reading.js +249 -0
- package/dist/host/native/receipt-environment.d.ts +3 -0
- package/dist/host/native/receipt-environment.js +41 -0
- package/dist/host/native/references.d.ts +5 -0
- package/dist/host/native/references.js +30 -0
- package/dist/host/native/root.d.ts +17 -0
- package/dist/host/native/root.js +37 -0
- package/dist/host/native/route.d.ts +66 -0
- package/dist/host/native/route.js +216 -0
- package/dist/host/native/runtime.d.ts +4 -0
- package/dist/host/native/runtime.js +9 -0
- package/dist/host/native-reader-context.d.ts +3 -0
- package/dist/host/native-reader-context.js +8 -0
- package/dist/host/place-clock-selection.d.ts +55 -0
- package/dist/host/place-clock-selection.js +124 -0
- package/dist/host/ports/local-act.d.ts +10 -0
- package/dist/host/ports/local-act.js +78 -6
- package/dist/host/ports/place-act.d.ts +46 -0
- package/dist/host/ports/place-act.js +169 -0
- package/dist/host/process-lifetime.js +8 -3
- package/dist/host/provide.d.ts +25 -0
- package/dist/host/provide.js +115 -13
- package/dist/host/reading-closures.d.ts +15 -1
- package/dist/host/reading-closures.js +88 -6
- package/dist/host/reading-context.d.ts +29 -0
- package/dist/host/reading-context.js +53 -0
- package/dist/host/root-clock-source.d.ts +85 -0
- package/dist/host/root-clock-source.js +305 -0
- package/dist/host/selected-capsules.js +3 -2
- package/dist/land/act.d.ts +26 -0
- package/dist/land/act.js +96 -3
- package/dist/land/ledger.d.ts +4 -0
- package/dist/land/ledger.js +20 -2
- package/dist/observe/runner.d.ts +4 -0
- package/dist/observe/runner.js +9 -2
- package/docs/contracts/cli.md +13 -0
- package/package.json +2 -2
- package/receipts.bound +296 -256
package/dist/cli/accept.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { assertProspectiveRootClockSelection } from "../host/root-clock-source.js";
|
|
2
|
+
import { hasContextualPlace, landContextualPlace } from "../host/contextual-place.js";
|
|
1
3
|
import { commitLocalAct, intactLocalAct, committedLocalActs } from "../host/ports/local-act.js";
|
|
2
4
|
import { withoutEffects } from "../host/read-only.js";
|
|
3
5
|
import { admittedLine } from "../host/selected-topos.js";
|
|
@@ -26,7 +28,7 @@ import { retractedTogether, withdrawal } from "../land/withdraw.js";
|
|
|
26
28
|
import { isCeiling } from "../fold/configures.js";
|
|
27
29
|
import { inertIn } from "../land/inert.js";
|
|
28
30
|
import { landSaid } from "./pass.js";
|
|
29
|
-
import { underTheLock, underTheRegions } from "../land/act.js";
|
|
31
|
+
import { underTheLock, underTheRegions, underAuthorityRegions, underRootProjection } from "../land/act.js";
|
|
30
32
|
import { openedBy } from "../fold/opened.js";
|
|
31
33
|
import { touchedBy } from "../fold/reach.js";
|
|
32
34
|
import { landOwned, ownedOf } from "../land/owned.js";
|
|
@@ -46,6 +48,7 @@ import { judgeDemand, landTake } from "./takes.js";
|
|
|
46
48
|
function admissionEvidence(root, signed, standing) {
|
|
47
49
|
return withoutEffects(() => {
|
|
48
50
|
const store = storeOf(root);
|
|
51
|
+
assertProspectiveRootClockSelection(root, signed);
|
|
49
52
|
const reads = !signed.some(isReaderLock) && signed.some(isCeiling);
|
|
50
53
|
const fold = reads ? coneOf(root, entryOf(root), signed.filter(isCeiling)) : { standing, observed: [], own: {}, kept: true };
|
|
51
54
|
const inert = inertIn(signed, { standing: fold.standing, ceiling: isCeiling, signsReader: !reads, observed: fold.observed, own: fold.own, epoch: epochOf([...lockLines(store), ...signed]) });
|
|
@@ -277,6 +280,14 @@ export async function signedBatch(root, args, files) {
|
|
|
277
280
|
*/
|
|
278
281
|
export async function accept(root, args) {
|
|
279
282
|
const started = Date.now();
|
|
283
|
+
const contextFiles = positionalsOf(args);
|
|
284
|
+
if (contextFiles.length === 1 && hasContextualPlace(root) && !claimLinesIn(contextFiles[0]).length) {
|
|
285
|
+
if (namedPlaces(args).length || valueOf(args, FLAGS.key) || valueOf(args, FLAGS.keyFile) || valueOf(args, FLAGS.signer))
|
|
286
|
+
throw Error('REFUSE·contextual place accepts one already signed context envelope');
|
|
287
|
+
const result = await landContextualPlace(root, contextFiles[0]);
|
|
288
|
+
process.stdout.write(JSON.stringify({ profile: 'place-act-context@1', identity: result.identity, status: result.kind, context: result.context, receipts: result.receipts }) + '\n');
|
|
289
|
+
return 0;
|
|
290
|
+
}
|
|
280
291
|
const named = namedPlaces(args);
|
|
281
292
|
const placed = positionalsOf(args).reduce((all, file) => ((places) => (places.length ? claimLinesIn(file).reduce((got, line) => got.set(sayingOf(line), [...new Set([...(got.get(sayingOf(line)) ?? []), ...places])]), all) : all))(placesOfFile(file)), new Map());
|
|
282
293
|
const batch = await signedBatch(root, args, positionalsOf(args));
|
|
@@ -301,7 +312,11 @@ export async function accept(root, args) {
|
|
|
301
312
|
const where = every ? 'every place · then the root, where the places join' : regions.length ? regions.map((one) => `${one}/`).join(' · ') : 'the root alone, where the places join';
|
|
302
313
|
process.stdout.write(`ACTS ${where} · ${owned.ledger.length} lines to the ledger${[...owned.own].map(([place, lines]) => ` · ${lines.length} to ${place}'s own lock`).join('')} · before the lock\n`);
|
|
303
314
|
const asked = Date.now();
|
|
304
|
-
|
|
315
|
+
// Root-ledger writes may change grants or inherited policies. Child-only
|
|
316
|
+
// lots read that authority through publication, without excluding siblings.
|
|
317
|
+
const rootWrite = owned.ledger.length > 0 || every || regions.length === 0;
|
|
318
|
+
const enter = rootWrite ? underTheRegions : underAuthorityRegions;
|
|
319
|
+
return enter(store, rootWrite ? [...regions, ''] : regions, 'land', () => acceptNow(root, { ...batch, signed: owned.ledger, records: batch.signed }, started, owned, asked, regions));
|
|
305
320
|
}
|
|
306
321
|
async function acceptNow(root, batch, started, owned, asked = started, descent = []) {
|
|
307
322
|
const waited = Date.now() - asked;
|
|
@@ -318,6 +333,13 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
318
333
|
process.stderr.write(`${selfName()}: REFUSE·base moved ${batch.base.digest} → ${currentBase} · nothing landed\n`);
|
|
319
334
|
return 1;
|
|
320
335
|
}
|
|
336
|
+
try {
|
|
337
|
+
assertProspectiveRootClockSelection(root, signed);
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
process.stderr.write(`${selfName()}: ${error instanceof Error ? error.message : String(error)} · nothing landed\n`);
|
|
341
|
+
return 1;
|
|
342
|
+
}
|
|
321
343
|
if (signed.some(line => !isConfig(line))) {
|
|
322
344
|
try {
|
|
323
345
|
await admittedObjects(root, [...signedOwnerLines(store), ...signed]);
|
|
@@ -396,67 +418,69 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
396
418
|
landed = took('land', () => [...new Set(signed.map(line => fieldOf(line, 'by')))].map(by => land(store, by, signed.filter(line => fieldOf(line, 'by') === by))));
|
|
397
419
|
for (const [place, lines] of owned.own)
|
|
398
420
|
landOwned(root, place, lines, resultProfile !== undefined);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
for (const need of locationsOf(fieldOf(line, 'needs')).locations) {
|
|
405
|
-
const at = join(root, need);
|
|
406
|
-
const bytes = observeFile(at);
|
|
407
|
-
if (bytes === undefined)
|
|
421
|
+
return underRootProjection(store, 'projection', async () => {
|
|
422
|
+
landSaid(store, writerFor(told.standing, 'fold'), []);
|
|
423
|
+
for (const line of signed) {
|
|
424
|
+
const value = fieldOf(line, 'value');
|
|
425
|
+
if (!/^[a-z0-9-]+:[0-9a-f]{32,}$/.test(value))
|
|
408
426
|
continue;
|
|
409
|
-
|
|
410
|
-
|
|
427
|
+
for (const need of locationsOf(fieldOf(line, 'needs')).locations) {
|
|
428
|
+
const at = join(root, need);
|
|
429
|
+
const bytes = observeFile(at);
|
|
430
|
+
if (bytes === undefined)
|
|
431
|
+
continue;
|
|
432
|
+
if (bytesDigest(store, bytes) === value)
|
|
433
|
+
landBlob(store, value, bytes);
|
|
434
|
+
}
|
|
411
435
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
436
|
+
if (coordinates.taken.length) {
|
|
437
|
+
for (const path of coordinates.taken) {
|
|
438
|
+
if (existsSync(join(root, path)))
|
|
439
|
+
rmSync(join(root, path), { recursive: true });
|
|
440
|
+
for (let dir = dirname(path); dir !== '.' && existsSync(join(root, dir)) && !entriesIn(join(root, dir)).length; dir = dirname(dir))
|
|
441
|
+
rmdirSync(join(root, dir));
|
|
442
|
+
}
|
|
443
|
+
landCoordinates(store, new Map(), coordinates.taken, `withdraw:epoch-${epoch}`);
|
|
444
|
+
for (const path of coordinates.taken)
|
|
445
|
+
process.stdout.write(`GONE ${path} · withdrawn by its line\n`);
|
|
419
446
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
land(store, 'judge', late);
|
|
431
|
-
for (const line of late)
|
|
432
|
-
if (fieldOf(line, 'measure') !== 'cone')
|
|
433
|
-
process.stdout.write(`LATE ${fieldOf(line, 'scope')} · answered from the landed cone\n`);
|
|
434
|
-
}
|
|
435
|
-
if (signed.some((line) => fieldOf(line, 'scope').startsWith(`${basename(ownRoot())}/`) && !fieldOf(line, 'scope').split('/').slice(1, -1).includes('uses'))) {
|
|
436
|
-
const code = instrumentOf(store, entryOf(root), told.standing, root, ownLock());
|
|
437
|
-
if (instrumentKept(store) !== code) {
|
|
438
|
-
const open = await closeReceipts(root, store);
|
|
439
|
-
instrumentKeep(store, code);
|
|
440
|
-
process.stderr.write(`open by instrument · ${open.length}\n`);
|
|
447
|
+
for (const one of judged)
|
|
448
|
+
landTake(root, one, []);
|
|
449
|
+
const standingAsked = [...signed, ...fold.standing].filter((line) => fieldOf(line, 'role') === 'demands' && fieldOf(line, 'value') !== 'withdraw');
|
|
450
|
+
const paidScopes = new Set(paidOf(store, standingAsked, fold.observed, view).paid.map((line) => fieldOf(line, 'scope')));
|
|
451
|
+
const late = lateFacts(store, [...signed, ...fold.standing], paidScopes);
|
|
452
|
+
if (late.length) {
|
|
453
|
+
land(store, 'judge', late);
|
|
454
|
+
for (const line of late)
|
|
455
|
+
if (fieldOf(line, 'measure') !== 'cone')
|
|
456
|
+
process.stdout.write(`LATE ${fieldOf(line, 'scope')} · answered from the landed cone\n`);
|
|
441
457
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
458
|
+
if (signed.some((line) => fieldOf(line, 'scope').startsWith(`${basename(ownRoot())}/`) && !fieldOf(line, 'scope').split('/').slice(1, -1).includes('uses'))) {
|
|
459
|
+
const code = instrumentOf(store, entryOf(root), told.standing, root, ownLock());
|
|
460
|
+
if (instrumentKept(store) !== code) {
|
|
461
|
+
const open = await closeReceipts(root, store);
|
|
462
|
+
instrumentKeep(store, code);
|
|
463
|
+
process.stderr.write(`open by instrument · ${open.length}\n`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const rendered = took('render', () => renderInto(root, store));
|
|
467
|
+
process.stdout.write(`RENDER 0\n`);
|
|
468
|
+
const own = new Set([...owned.own.values()].flat()).size;
|
|
469
|
+
const perLine = Math.round((Date.now() - started) / Math.max(1, signed.length + own));
|
|
470
|
+
const folder = writerFor(fold.standing, 'fold');
|
|
471
|
+
const beat = (ms, at) => canonical({ scope: 'beat/accept', role: 'writes', form: 'interval', measure: 'ms', value: `${ms}..${ms}`, by: folder ?? '', at: `place:${at}` });
|
|
472
|
+
if (folder !== undefined)
|
|
473
|
+
land(store, folder, [beat(perLine, 'line'), beat(1, fold.kept ? 'kept' : 'folded'), beat(Date.now() - started, 'total')]);
|
|
474
|
+
process.stdout.write(`FACT signed ${signed.length + own} · landed ${landed.length ? landed.map((one) => `${one.appended} in ${one.at}`).join(' · ') : '0'}${[...owned.own].map(([place, lines]) => ` · ${lines.length} in ${place}/${LOCK}`).join('')} · epoch ${epoch}\n`
|
|
475
|
+
+ `TARGET ${rendered.standing} claims · ${rendered.forks.length} forks · ${rendered.vacuous.length} vacuous · ${rendered.grey.length} grey · ${rendered.refused.length} refused · readings · no encounters computed · ${Date.now() - started} ms\n`
|
|
476
|
+
+ `SPENT ${spent.join(' ms · ')} ms · ${signed.length} lines\n`);
|
|
477
|
+
if (withdrawn) {
|
|
478
|
+
process.stdout.write(`WITHDRAW ${withdrawn.taken.length} taken · ${withdrawn.exact.length} exact on distributive scales · ${withdrawn.open.length} on open scales, not computed\n`);
|
|
479
|
+
for (const line of withdrawn.inexact)
|
|
480
|
+
process.stdout.write(`INEXACT ${fieldOf(line, 'scope')} · its scale is not distributive: what the others hold is not what they held without it\n`);
|
|
481
|
+
}
|
|
482
|
+
return 0;
|
|
483
|
+
});
|
|
460
484
|
}
|
|
461
485
|
/**
|
|
462
486
|
* A batch landed twice is one: nothing of it lands again. What it left unpaid is judged again, the way it would be now:
|
package/dist/cli/act-result.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { type ActResult } from '@lapxo/topos/wire';
|
|
2
|
+
import { type LocalActBundle } from '../host/ports/local-act.ts';
|
|
1
3
|
/** Public query of a committed identity, using the same admission authority.
|
|
2
4
|
* Native fold evidence has store provenance; it never grants coverage. */
|
|
5
|
+
export declare function verifiedLegacyActResult(root: string, identity: string): {
|
|
6
|
+
result: ActResult;
|
|
7
|
+
bundle: LocalActBundle;
|
|
8
|
+
records: readonly string[];
|
|
9
|
+
epoch: number;
|
|
10
|
+
history: readonly string[];
|
|
11
|
+
};
|
|
3
12
|
export declare function printActResult(root: string, identity: string | undefined): void;
|
package/dist/cli/act-result.js
CHANGED
|
@@ -1,31 +1,68 @@
|
|
|
1
|
+
import { hashText } from "../host/hash.js";
|
|
2
|
+
import { hasContextualPlace, contextualAct } from "../host/contextual-place.js";
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
1
4
|
import { actResultOf, actResultProfile } from '@lapxo/topos/wire';
|
|
2
5
|
import { actLines, intactLocalAct, localActResult } from "../host/ports/local-act.js";
|
|
3
6
|
import { storeOf } from "../land/ledger.js";
|
|
4
7
|
import { lockStanding } from "../fold/keys.js";
|
|
5
8
|
import { authorityFor, writerFor } from "../fold/signers.js";
|
|
6
9
|
import { eraOf } from "../fold/digests.js";
|
|
7
|
-
import { fieldOf, isConfig, foldClaims } from "../fold/claims.js";
|
|
10
|
+
import { fieldOf, isConfig, foldClaims, parsedLine } from "../fold/claims.js";
|
|
8
11
|
import { ownRecordAdmitted } from "../fold/signed.js";
|
|
9
12
|
import { admissionAnchor, admissionHistoryAt } from "../fold/admission-history.js";
|
|
10
13
|
import { fullDigest } from "../host/digest.js";
|
|
11
14
|
import { wordOf, wireLine } from "../fold/wire.js";
|
|
12
15
|
import { viewsOf } from "../fold/views.js";
|
|
16
|
+
/** Historical proof only. Exact current bodies, admission history and bootstrap
|
|
17
|
+
* anchor are reread before lookup; this never retains a current command grant. */
|
|
18
|
+
const historicalProofs = new WeakMap();
|
|
19
|
+
function proofFingerprint(identity, bundle, history, anchor, algorithms) {
|
|
20
|
+
const hash = createHash('sha256'), text = hashText.bind(undefined, hash);
|
|
21
|
+
text('legacy-act-historical-proof/1');
|
|
22
|
+
text(identity);
|
|
23
|
+
text(bundle.records);
|
|
24
|
+
text(bundle.receipt);
|
|
25
|
+
text(bundle.placements === undefined ? 'absent' : 'present');
|
|
26
|
+
text(String(bundle.placements?.length ?? 0));
|
|
27
|
+
for (const placement of bundle.placements ?? []) {
|
|
28
|
+
text(placement.place);
|
|
29
|
+
text(placement.records);
|
|
30
|
+
}
|
|
31
|
+
text(String(history.length));
|
|
32
|
+
for (const line of history)
|
|
33
|
+
text(line);
|
|
34
|
+
text(JSON.stringify(anchor));
|
|
35
|
+
text(String(algorithms.length));
|
|
36
|
+
for (const algorithm of algorithms)
|
|
37
|
+
text(algorithm);
|
|
38
|
+
return hash.digest('hex');
|
|
39
|
+
}
|
|
40
|
+
const freshResult = (result) => ({ ...result, records: [...result.records] });
|
|
13
41
|
/** Public query of a committed identity, using the same admission authority.
|
|
14
42
|
* Native fold evidence has store provenance; it never grants coverage. */
|
|
15
|
-
export function
|
|
16
|
-
const store = storeOf(root)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
export function verifiedLegacyActResult(root, identity) {
|
|
44
|
+
const store = storeOf(root);
|
|
45
|
+
let observation;
|
|
46
|
+
const bundle = localActResult(store, identity, (id, current) => {
|
|
47
|
+
const receipt = parsedLine(current.receipt.trim());
|
|
48
|
+
if (receipt.kind !== 'fact')
|
|
49
|
+
return intactLocalAct(id, current);
|
|
50
|
+
const epoch = Number(fieldOf(current.receipt.trim(), 'epoch'));
|
|
51
|
+
const history = admissionHistoryAt(root, epoch), before = history.filter(line => !isConfig(line) || Number(fieldOf(line, 'epoch')) < epoch);
|
|
52
|
+
const algorithms = eraOf(foldClaims(before).standing).admitted, anchor = admissionAnchor(root);
|
|
53
|
+
const fingerprint = proofFingerprint(id, current, history, anchor, algorithms), cached = historicalProofs.get(receipt.value);
|
|
54
|
+
const retained = cached?.fingerprint === fingerprint ? cached.result : undefined;
|
|
55
|
+
observation = { epoch, history, before, algorithms, anchor, key: receipt.value, fingerprint, ...(retained ? { retained } : {}) };
|
|
56
|
+
return retained !== undefined || intactLocalAct(id, current);
|
|
57
|
+
});
|
|
23
58
|
if (!bundle)
|
|
24
59
|
throw Error('REFUSE·act no committed result ' + identity);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
60
|
+
if (!observation)
|
|
61
|
+
throw Error('REFUSE·act historical proof observation absent');
|
|
62
|
+
const records = actLines(bundle.records), { epoch, history, before, algorithms, anchor, retained } = observation;
|
|
63
|
+
if (retained)
|
|
64
|
+
return { result: freshResult(retained), bundle, records, epoch, history };
|
|
65
|
+
const authority = authorityFor(history, anchor, algorithms);
|
|
29
66
|
const admittedBefore = foldClaims(before.filter(line => authority.of(line).kind === 'admitted')).standing;
|
|
30
67
|
const profile = actResultProfile(admittedBefore);
|
|
31
68
|
if (!profile)
|
|
@@ -44,5 +81,23 @@ export function printActResult(root, identity) {
|
|
|
44
81
|
return bundle.placements.some(p => actLines(p.records).includes(line) && (p.place === '.' ? authority.of(line).kind === 'admitted' : ownRecordAdmitted(line, p.place.slice(0, p.place.lastIndexOf('/')), family, authority.admitted, algorithms)));
|
|
45
82
|
},
|
|
46
83
|
verifiesReceipt: line => fieldOf(line, 'by') === writerFor(admittedBefore, 'fold') && intactLocalAct(identity, bundle), });
|
|
84
|
+
const kept = Object.freeze({ ...result, records: Object.freeze([...result.records]) });
|
|
85
|
+
historicalProofs.set(observation.key, { fingerprint: observation.fingerprint, result: kept });
|
|
86
|
+
return { result: freshResult(kept), bundle, records, epoch, history };
|
|
87
|
+
}
|
|
88
|
+
export function printActResult(root, identity) {
|
|
89
|
+
const store = storeOf(root), standing = lockStanding(store), view = viewsOf(standing).get('act');
|
|
90
|
+
if (!view || view.shape || !view.regions.some(region => region.name === 'act'))
|
|
91
|
+
throw Error('REFUSE·view act requires an admitted result profile and act view');
|
|
92
|
+
if (!identity)
|
|
93
|
+
throw Error('REFUSE·act name one committed identity');
|
|
94
|
+
if (hasContextualPlace(root)) {
|
|
95
|
+
const contextual = contextualAct(root, identity);
|
|
96
|
+
if (contextual) {
|
|
97
|
+
process.stdout.write(JSON.stringify(contextual) + '\n');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const { result, bundle } = verifiedLegacyActResult(root, identity);
|
|
47
102
|
process.stdout.write(`ACT ${result.identity} · epoch ${result.epoch} · admitted · conformance not asserted\n` + bundle.records + bundle.receipt);
|
|
48
103
|
}
|
package/dist/cli/args.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export declare function entryOf(root: string): string;
|
|
|
5
5
|
export declare function valueOf(args: readonly string[], flag: string): string | undefined;
|
|
6
6
|
export declare const valuesOf: (args: readonly string[], flag: string) => readonly string[];
|
|
7
7
|
export declare const namedPlaces: (args: readonly string[]) => readonly string[];
|
|
8
|
+
export declare function positionalIndexes(args: readonly string[]): number[];
|
|
8
9
|
export declare function positionalsOf(args: readonly string[]): string[];
|
|
9
10
|
export declare const placesOfFile: (file: string) => readonly string[];
|
|
10
11
|
export declare function claimLinesIn(file: string): string[];
|
package/dist/cli/args.js
CHANGED
|
@@ -14,7 +14,7 @@ export function valueOf(args, flag) {
|
|
|
14
14
|
}
|
|
15
15
|
export const valuesOf = (args, flag) => args.flatMap((arg, i) => (arg === flag && args[i + 1] !== undefined ? [args[i + 1]] : []));
|
|
16
16
|
export const namedPlaces = (args) => valuesOf(args, FLAGS.place).map((one) => one.replace(/\/$/, ''));
|
|
17
|
-
export function
|
|
17
|
+
export function positionalIndexes(args) {
|
|
18
18
|
const out = [];
|
|
19
19
|
for (let i = 0; i < args.length; i += 1) {
|
|
20
20
|
const arg = args[i] ?? '';
|
|
@@ -23,10 +23,13 @@ export function positionalsOf(args) {
|
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
25
|
if (!arg.startsWith('--'))
|
|
26
|
-
out.push(
|
|
26
|
+
out.push(i);
|
|
27
27
|
}
|
|
28
28
|
return out;
|
|
29
29
|
}
|
|
30
|
+
export function positionalsOf(args) {
|
|
31
|
+
return positionalIndexes(args).map(index => args[index]);
|
|
32
|
+
}
|
|
30
33
|
export const placesOfFile = (file) => (observeText(file) ?? '').split('\n').map((line) => line.trim())
|
|
31
34
|
.filter((line) => line.startsWith('# place ')).map((line) => line.slice('# place '.length).trim().replace(/\/$/, '')).filter(Boolean);
|
|
32
35
|
export function claimLinesIn(file) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Fixed sync-to-async transport executable. It never resets producer counters
|
|
2
|
+
* or grants. Its stdin budget comes from the fixed host argv before reading.
|
|
3
|
+
*/
|
|
4
|
+
import { createConnection } from 'node:net';
|
|
5
|
+
import { scheduleDeadline } from "../host/native/deadline.js";
|
|
6
|
+
const cap = Number(process.argv[2]);
|
|
7
|
+
if (!Number.isSafeInteger(cap) || cap < 1)
|
|
8
|
+
throw Error('REFUSE·producer sync client input resources');
|
|
9
|
+
const chunks = [];
|
|
10
|
+
let size = 0;
|
|
11
|
+
for await (const chunk of process.stdin) {
|
|
12
|
+
const raw = Buffer.from(chunk);
|
|
13
|
+
size += raw.length;
|
|
14
|
+
if (size > cap)
|
|
15
|
+
throw Error('REFUSE·producer sync client input bytes');
|
|
16
|
+
chunks.push(raw);
|
|
17
|
+
}
|
|
18
|
+
const { endpoint, frame } = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
19
|
+
if (!endpoint || typeof endpoint.socket !== 'string' || !Number.isSafeInteger(endpoint.timeoutMs) || endpoint.timeoutMs < 1 || !Number.isSafeInteger(endpoint.responseBytes) || endpoint.responseBytes < 1 || typeof frame !== 'string' || Buffer.byteLength(frame) > endpoint.responseBytes)
|
|
20
|
+
throw Error('REFUSE·producer sync client binding');
|
|
21
|
+
const socket = createConnection(endpoint.socket), remaining = Math.max(1, Math.min(endpoint.timeoutMs, endpoint.deadlineMs - Date.now())), cancel = scheduleDeadline(process.hrtime.bigint() + BigInt(remaining) * 1000000n, () => socket.destroy(Error('REFUSE·producer IPC timeout')));
|
|
22
|
+
let bytes = 0;
|
|
23
|
+
socket.once('connect', () => socket.write(frame + '\n'));
|
|
24
|
+
socket.on('data', chunk => { bytes += chunk.length; if (bytes > endpoint.responseBytes)
|
|
25
|
+
socket.destroy(Error('REFUSE·producer IPC response bytes'));
|
|
26
|
+
else
|
|
27
|
+
process.stdout.write(chunk); });
|
|
28
|
+
socket.once('error', error => { process.stderr.write(error.message); process.exitCode = 1; });
|
|
29
|
+
socket.once('close', cancel);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Fixed descendant entry. The caller supplies only a sealed operational envelope;
|
|
2
|
+
* actual grants/counters live in the retained Root producer service.
|
|
3
|
+
*/
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { readBoundedFile } from "../host/native/bounded-file.js";
|
|
6
|
+
import { installDescendantBoundary } from "../host/native/descendants.js";
|
|
7
|
+
import { protectNativeLoaderRegistration } from "../host/native/loader.js";
|
|
8
|
+
import { assertNativeRuntime } from "../host/native/runtime.js";
|
|
9
|
+
const url = new URL(import.meta.url), path = url.searchParams.get('config'), cap = Number(url.searchParams.get('bytes')), expected = url.searchParams.get('digest');
|
|
10
|
+
if (!path || !expected || !Number.isSafeInteger(cap) || cap < 1)
|
|
11
|
+
throw Error('REFUSE·native descendant inherited envelope absent');
|
|
12
|
+
assertNativeRuntime(process.env, []);
|
|
13
|
+
const raw = readBoundedFile(path, cap, 'descendant host envelope');
|
|
14
|
+
if ('sha256:' + createHash('sha256').update(raw).digest('hex') !== expected)
|
|
15
|
+
throw Error('REFUSE·native descendant envelope changed');
|
|
16
|
+
const config = JSON.parse(raw.toString('utf8'));
|
|
17
|
+
config.custodian.preload = url.href;
|
|
18
|
+
installDescendantBoundary(config);
|
|
19
|
+
protectNativeLoaderRegistration();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { sha256 as hash } from "../host/hash.js";
|
|
2
|
+
/** Fixed instrument child. Root authority and reading identity arrive through the
|
|
3
|
+
* inherited supervisor argv; request JSON supplies neither verifier nor grant.
|
|
4
|
+
*/
|
|
5
|
+
import { realpathSync } from 'node:fs';
|
|
6
|
+
import { readingIdentityBytes } from '@lapxo/topos/contract';
|
|
7
|
+
import { readBoundedBatch } from "../host/native/bounded-file.js";
|
|
8
|
+
import { inheritedNativeGuard, inheritedNativeRoot } from "../host/native/root.js";
|
|
9
|
+
import { authenticateNativeProfile, loadSignedNativeReading, answerNativeReading } from "../host/native/reading.js";
|
|
10
|
+
import { readingEnvironment } from "../host/reading-context.js";
|
|
11
|
+
import { assertNativeRuntime } from "../host/native/runtime.js";
|
|
12
|
+
import { nativeReferenceInputs } from "../host/native/references.js";
|
|
13
|
+
const fail = (why) => { throw Error('REFUSE·native dispatcher ' + why); };
|
|
14
|
+
const ordered = (value) => [...value].sort(([a], [b]) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
15
|
+
async function run() {
|
|
16
|
+
const inherited = { store: process.argv[2], parent: Number(process.argv[8]), expected: JSON.parse(process.argv[4]) }, coordinate = process.argv[3], inputLimit = Number(process.argv[6]), phase = process.argv[7], execution = JSON.parse(process.argv[9]);
|
|
17
|
+
if (phase !== 'act')
|
|
18
|
+
fail('effects forbidden during ' + phase);
|
|
19
|
+
if (!Number.isSafeInteger(inputLimit) || inputLimit < 1)
|
|
20
|
+
fail('missing inherited input limit');
|
|
21
|
+
if (!execution?.context || !execution.env || !Array.isArray(execution.flags) || !execution.cwd)
|
|
22
|
+
fail('missing complete inherited reading identity');
|
|
23
|
+
assertNativeRuntime(process.env, process.execArgv);
|
|
24
|
+
const identity = hash(readingIdentityBytes(execution.context));
|
|
25
|
+
if (JSON.stringify(ordered(readingEnvironment(hash, execution.env, execution.cwd, execution.flags))) !== JSON.stringify(ordered(execution.context.environment)))
|
|
26
|
+
fail('inherited execution differs from context');
|
|
27
|
+
if (JSON.stringify(ordered(readingEnvironment(hash))) !== JSON.stringify(ordered(execution.context.environment)))
|
|
28
|
+
fail('actual child environment differs from inherited identity');
|
|
29
|
+
const chunks = [];
|
|
30
|
+
let bytes = 0;
|
|
31
|
+
for await (const chunk of process.stdin) {
|
|
32
|
+
const got = Buffer.from(chunk);
|
|
33
|
+
bytes += got.length;
|
|
34
|
+
if (bytes > inputLimit)
|
|
35
|
+
fail('input bytes exceeded');
|
|
36
|
+
chunks.push(got);
|
|
37
|
+
}
|
|
38
|
+
const frame = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
39
|
+
const current = inheritedNativeRoot(inherited, frame.proof), guard = inheritedNativeGuard(inherited, frame.proof), authenticated = authenticateNativeProfile(current, coordinate), profile = authenticated.profile;
|
|
40
|
+
const selected = authenticated.selection;
|
|
41
|
+
if (execution.context.implementation !== profile.selection.archive)
|
|
42
|
+
fail('reading implementation differs from selected archive');
|
|
43
|
+
if (!Array.isArray(frame.locations) || frame.locations.length !== profile.selection.members.length || frame.locations.length > profile.selection.budget.members)
|
|
44
|
+
fail('image member budget/count');
|
|
45
|
+
const runtime = frame.locations.find((location) => location.member === profile.selection.runtime);
|
|
46
|
+
if (!runtime || realpathSync(runtime.path) !== realpathSync(process.execPath))
|
|
47
|
+
fail('runtime differs from executing interpreter');
|
|
48
|
+
nativeReferenceInputs(execution.context.inputs, profile.selection.members.map(member => ['native/' + member.coordinate, member.digest]));
|
|
49
|
+
const imagePaths = profile.selection.members.map(member => { const rows = frame.locations.filter((location) => location.member === member.coordinate); if (rows.length !== 1)
|
|
50
|
+
return fail('missing/ambiguous actual member ' + member.coordinate); return { path: rows[0].path, coordinate: member.coordinate }; });
|
|
51
|
+
const raw = readBoundedBatch([...imagePaths, { path: frame.archive, coordinate: 'implementation archive' }], profile.selection.budget.bytes), archive = raw.at(-1), members = profile.selection.members.map((member, index) => ({ ...member, bytes: new Uint8Array(raw[index]) }));
|
|
52
|
+
if (hash(archive) !== profile.selection.archive)
|
|
53
|
+
fail('implementation archive differs');
|
|
54
|
+
const handoff = { place: inherited.expected.namespace, instrument: execution.context.instrument, policy: execution.context.policy, authoritySnapshot: identity, budget: profile.selection.budget, members, bindings: profile.selection.bindings, loads: profile.selection.loads };
|
|
55
|
+
const image = { cwd: execution.cwd, locations: frame.locations, runtime: profile.selection.runtime, preload: profile.selection.preload ?? undefined, nativePreloadMembers: profile.selection.nativePreloadMembers, condition: profile.selection.condition, commandPort: profile.port };
|
|
56
|
+
const handle = await loadSignedNativeReading(selected, { profile, handoff, image, archive }, guard);
|
|
57
|
+
const results = await answerNativeReading(handle, frame.requests, profile.selection.reader, { phase: 'act', guard });
|
|
58
|
+
process.stdout.write(JSON.stringify(results) + '\n');
|
|
59
|
+
}
|
|
60
|
+
run().catch(error => { process.stderr.write((error instanceof Error ? error.message : String(error)) + '\n'); process.exitCode = 1; });
|
package/dist/cli/observe.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { observedClaims } from "../fold/observed.js";
|
|
3
3
|
import { storeOf } from "../land/ledger.js";
|
|
4
|
+
import { withContentStore } from "../host/content-store.js";
|
|
5
|
+
import { lockStanding } from "../fold/keys.js";
|
|
6
|
+
import { underRootAuthority } from "../land/act.js";
|
|
4
7
|
/** One reader, run to the end behind a fold that did not wait for it: what it lands, the next fold reads. */
|
|
5
|
-
const
|
|
6
|
-
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
if (args.length > 3 || (args[2] !== undefined && (args[1] === undefined || !/^sha256:[a-f0-9]{64}$/.test(args[2]))))
|
|
10
|
+
throw Error('REFUSE·reader invalid internal background arguments');
|
|
11
|
+
const [root = '.', only, selected] = args;
|
|
12
|
+
const place = resolve(root), store = storeOf(place);
|
|
13
|
+
await underRootAuthority(store, 'reader authority', () => withContentStore(store, () => observedClaims(place, store, { wait: true, ...(only === undefined ? {} : { only }), ...(selected === undefined ? {} : { selected }) }), () => lockStanding(store)));
|
package/dist/cli/pass.js
CHANGED
|
@@ -25,6 +25,7 @@ import { carriedFrom } from "../fold/resolved.js";
|
|
|
25
25
|
import { wireLine } from "../fold/wire.js";
|
|
26
26
|
import { isWire, RECEIPTS } from "../fold/claims.js";
|
|
27
27
|
import { withoutEffects } from "../host/read-only.js";
|
|
28
|
+
import { assertNativeReaderGrantsCurrent } from "../host/native/route.js";
|
|
28
29
|
/**
|
|
29
30
|
* The pass of a place, in one process: the releases its instrument names are laid out first, its readers observe
|
|
30
31
|
* once, each place a view writes in is folded once, the places before the root whose door reads them, and every coordinate a
|
|
@@ -43,7 +44,7 @@ import { withoutEffects } from "../host/read-only.js";
|
|
|
43
44
|
async function checked(root, entry, under) {
|
|
44
45
|
const started = Date.now();
|
|
45
46
|
const store = storeOf(root);
|
|
46
|
-
if (!meets(root, store, under ?? '')) {
|
|
47
|
+
if (!meets(root, store, under ?? '', false)) {
|
|
47
48
|
process.stderr.write(`${selfName()}: REFUSE·check receipts are open; a fold must close them\n`);
|
|
48
49
|
return 1;
|
|
49
50
|
}
|
|
@@ -132,6 +133,10 @@ async function sweep(root, entry, under, check, told, journal, given, keep, reac
|
|
|
132
133
|
};
|
|
133
134
|
const settled = met && sameInstrument && !missingView();
|
|
134
135
|
if (settled) {
|
|
136
|
+
// File and receipt seals authenticate retained evidence. A normal quiet
|
|
137
|
+
// fold also needs today's acting Root grant; --check uses checked() above
|
|
138
|
+
// and intentionally performs historical inspection without fresh effects.
|
|
139
|
+
assertNativeReaderGrantsCurrent(store);
|
|
135
140
|
const ms = Date.now() - digestAt;
|
|
136
141
|
const read = receiptsSeen();
|
|
137
142
|
const lock = algorithmCost();
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
+
import { hasContextualPlace, contextualStanding } from "../host/contextual-place.js";
|
|
2
|
+
import { authenticatedStanding } from "../host/admitted-place.js";
|
|
1
3
|
import { viewsOf } from "../fold/views.js";
|
|
2
4
|
import { lockStanding } from "../fold/keys.js";
|
|
3
|
-
import { admissionAnchor, admissionHistoryAt } from "../fold/admission-history.js";
|
|
4
|
-
import { authorityFor } from "../fold/signers.js";
|
|
5
|
-
import { eraOf } from "../fold/digests.js";
|
|
6
|
-
import { fieldOf, foldClaims } from "../fold/claims.js";
|
|
7
5
|
import { storeOf } from "../land/ledger.js";
|
|
8
|
-
import { foldedEvidence } from '@lapxo/topos/contract';
|
|
9
6
|
/** An evidence projection, never a new authority lock. Authentication uses
|
|
10
7
|
* the admission snapshot at each local epoch; the existing fold applies
|
|
11
8
|
* supersessions and withdrawals across all declared classes. Storage layout
|
|
@@ -14,26 +11,10 @@ export function printStandingResult(root) {
|
|
|
14
11
|
const store = storeOf(root), view = viewsOf(lockStanding(store)).get('standing');
|
|
15
12
|
if (!view || view.shape || !view.regions.some(region => region.name === 'standing'))
|
|
16
13
|
throw Error('REFUSE·view standing requires a declared standing view');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (!authority) {
|
|
23
|
-
const snapshot = admissionHistoryAt(root, epoch);
|
|
24
|
-
// The signature vocabulary is configuration, not the as-yet
|
|
25
|
-
// unauthenticated evidence whose values are about to be folded.
|
|
26
|
-
const wire = snapshot.filter(record => fieldOf(record, 'scope').startsWith('wire/'));
|
|
27
|
-
authority = authorityFor(snapshot, anchor, eraOf(foldClaims(wire).standing).admitted);
|
|
28
|
-
snapshots.set(epoch, authority);
|
|
29
|
-
}
|
|
30
|
-
return authority.of(line).kind === 'admitted';
|
|
31
|
-
});
|
|
32
|
-
// The host authenticates against historical authority; Topos projects the
|
|
33
|
-
// authenticated history using the instrument's existing fold.
|
|
34
|
-
const { standing } = foldedEvidence(admitted, {
|
|
35
|
-
classification: () => 'local',
|
|
36
|
-
fold: lines => foldClaims(lines).standing,
|
|
37
|
-
});
|
|
14
|
+
if (hasContextualPlace(root)) {
|
|
15
|
+
process.stdout.write(JSON.stringify(contextualStanding(root)) + '\n');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const standing = authenticatedStanding(root);
|
|
38
19
|
process.stdout.write(standing.length ? standing.join('\n') + '\n' : '');
|
|
39
20
|
}
|