@lapxo/bound 0.1.8 → 0.2.0
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 +70 -27
- package/assets/wasm/guest.js +4 -0
- package/assets/wasm/manifest.json +27 -0
- package/assets/wasm/runtime.js +6 -0
- package/assets/wasm/runtime.wasm +0 -0
- 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 +9 -4
- package/dist/cli/place.d.ts +2 -0
- package/dist/cli/place.js +7 -4
- package/dist/cli/standing-result.js +7 -26
- package/dist/cli/verb.js +65 -9
- package/dist/engine/index.d.ts +11 -0
- package/dist/engine/index.js +9 -0
- package/dist/engine/object.d.ts +17 -0
- package/dist/engine/object.js +38 -0
- 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 +36 -7
- package/dist/fold/digests.d.ts +1 -1
- package/dist/fold/digests.js +6 -4
- package/dist/fold/evidence.d.ts +1 -1
- package/dist/fold/kept.js +2 -1
- package/dist/fold/object.d.ts +3 -17
- package/dist/fold/object.js +2 -38
- 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 +12 -2
- 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 +57 -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/cell-receipts.js +1 -1
- 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/objects.d.ts +2 -1
- package/dist/host/objects.js +24 -4
- 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 +17 -1
- package/dist/host/reading-closures.js +98 -18
- package/dist/host/reading-context.d.ts +29 -0
- package/dist/host/reading-context.js +53 -0
- package/dist/host/reference-authenticated.d.ts +28 -0
- package/dist/host/reference-authenticated.js +84 -0
- package/dist/host/reference-native.d.ts +10 -0
- package/dist/host/reference-native.js +50 -0
- package/dist/host/reference-profile.d.ts +23 -0
- package/dist/host/reference-profile.js +62 -0
- package/dist/host/reference.d.ts +6 -0
- package/dist/host/reference.js +24 -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/host/selected-topos.d.ts +1 -1
- package/dist/host/selected-topos.js +9 -1
- 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/regions.d.ts +4 -0
- package/dist/observe/regions.js +109 -1
- package/dist/observe/runner.d.ts +4 -0
- package/dist/observe/runner.js +9 -2
- package/dist/wasm/adapter.d.ts +51 -0
- package/dist/wasm/adapter.js +180 -0
- package/dist/wasm/node-worker.d.ts +1 -0
- package/dist/wasm/node-worker.js +13 -0
- package/dist/wasm/object.d.ts +8 -0
- package/dist/wasm/object.js +76 -0
- package/dist/wasm/worker.d.ts +1 -0
- package/dist/wasm/worker.js +7 -0
- package/docs/contracts/authenticated-reference.publication.json +25 -0
- package/docs/contracts/cli.md +13 -0
- package/docs/contracts/engine-object-projection.publication.json +25 -0
- package/docs/contracts/engine.md +39 -0
- package/docs/contracts/native-publication.inventory.json +8 -0
- package/docs/contracts/optional-wasm-adapter.publication.json +25 -0
- package/docs/contracts/publication-additions.inventory.json +8 -0
- package/docs/contracts/reference-port.md +33 -0
- package/docs/contracts/reference-port.publication.json +25 -0
- package/licenses/wasm/bound.txt +21 -0
- package/licenses/wasm/fast-text-encoding.txt +201 -0
- package/licenses/wasm/jitl-quickjs-ffi-types.txt +21 -0
- package/licenses/wasm/jitl-quickjs-wasmfile-release-sync.txt +47 -0
- package/licenses/wasm/obligations.txt +21 -0
- package/licenses/wasm/quickjs-emscripten-core.txt +21 -0
- package/licenses/wasm/topos.txt +21 -0
- package/package.json +94 -4
- package/receipts.bound +7672 -573
- package/samples/authenticated-reference/no.json +31 -0
- package/samples/authenticated-reference/yes/editorial-state/TARGET.bound +57 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/arrival.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/coverage.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/era.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/order.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/signature.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.arrival.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.coverage.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.era.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.order.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.signature.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/transport.yes.json +1 -0
- package/samples/authenticated-reference/yes/editorial-state/inputs/yes.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/TARGET.bound +57 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/arrival.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/coverage.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/era.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/order.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/signature.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.arrival.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.coverage.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.era.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.order.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.signature.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/transport.yes.json +1 -0
- package/samples/authenticated-reference/yes/weather-reading/inputs/yes.json +1 -0
- package/samples/authenticated-reference/yes.json +19 -0
- package/samples/engine-alphabet/TARGET.bound +29 -0
- package/samples/engine-alphabet/inputs/sample.json +323 -0
- package/samples/engine-alphabet/package.json +1 -0
- package/samples/engine-alphabet/reader.js +1457 -0
- package/samples/engine-alphabet/receipts.bound +12 -0
- package/samples/engine-interval/TARGET.bound +29 -0
- package/samples/engine-interval/inputs/sample.json +277 -0
- package/samples/engine-interval/package.json +1 -0
- package/samples/engine-interval/reader.js +1457 -0
- package/samples/engine-interval/receipts.bound +12 -0
- package/samples/no/engine-order/TARGET.bound +29 -0
- package/samples/no/engine-order/inputs/sample.json +277 -0
- package/samples/no/engine-order/package.json +1 -0
- package/samples/no/engine-order/reader.js +1457 -0
- package/samples/reference-port/no/catalog/standing.json +1 -0
- package/samples/reference-port/no/catalog/transport.json +1 -0
- package/samples/reference-port/no/route-notes/standing.json +1 -0
- package/samples/reference-port/no/route-notes/transport.json +1 -0
- package/samples/reference-port/yes/catalog/TARGET.bound +33 -0
- package/samples/reference-port/yes/catalog/standing.json +1 -0
- package/samples/reference-port/yes/catalog/transport.json +1 -0
- package/samples/reference-port/yes/route-notes/TARGET.bound +33 -0
- package/samples/reference-port/yes/route-notes/standing.json +1 -0
- package/samples/reference-port/yes/route-notes/transport.json +1 -0
- package/samples/wasm/editorial-notes/TARGET.bound +65 -0
- package/samples/wasm/editorial-notes/esm.bound +59 -0
- package/samples/wasm/editorial-notes/no-deadline.bound +65 -0
- package/samples/wasm/editorial-notes/no-memory.bound +65 -0
- package/samples/wasm/editorial-notes/no-missing-limit.bound +64 -0
- package/samples/wasm/editorial-notes/receipts.bound +1 -0
- package/samples/wasm/water-level/TARGET.bound +65 -0
- package/samples/wasm/water-level/esm.bound +59 -0
- package/samples/wasm/water-level/no-deadline.bound +65 -0
- package/samples/wasm/water-level/no-memory.bound +65 -0
- package/samples/wasm/water-level/no-missing-limit.bound +64 -0
- package/samples/wasm/water-level/receipts.bound +1 -0
- package/vectors/engine-object.cli.json +548 -0
- package/vectors/native/authenticated-reference-formation.vector.json +53 -0
- package/vectors/native/authenticated-reference.cli.json +157 -0
- package/vectors/native/authenticated-reference.vector.json +440 -0
- package/vectors/reference-port.cli.json +688 -0
- package/vectors/wasm-object.cli.json +452 -0
|
@@ -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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdirSync, rmSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { Worker } from 'node:worker_threads';
|
|
4
4
|
import { ENVELOPE, canonical, parse } from '@lapxo/topos/wire';
|
|
5
5
|
import { foldPlace, standingOf } from "./place.js";
|
|
@@ -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
|
}
|
|
@@ -56,7 +57,7 @@ async function checked(root, entry, under) {
|
|
|
56
57
|
return 1;
|
|
57
58
|
}
|
|
58
59
|
const standing = emptyLedger(store) ? ownLockOf(root, under?.replace(/\/$/, '') ?? '') : standingOf(root).standing;
|
|
59
|
-
const instrument = sealed === undefined ? instrumentOf(store, entry, standing, root, ownLock()) : instrumentDigest(store, entry, [], ownRoot(), ownLock());
|
|
60
|
+
const instrument = sealed === undefined ? instrumentOf(store, entry, standing, root, ownLock()) : instrumentDigest(store, resolve(root, entry), [], ownRoot(), ownLock());
|
|
60
61
|
if (expectedInstrument !== instrument) {
|
|
61
62
|
process.stderr.write(`${selfName()}: REFUSE·check receipt instrument differs; a fold must close it\n`);
|
|
62
63
|
return 1;
|
|
@@ -89,10 +90,10 @@ export async function pass(root, entry, under, check) {
|
|
|
89
90
|
// Byte seals describe the completed render pass, not its intermediate outputs.
|
|
90
91
|
if (!swept.written.length)
|
|
91
92
|
await closeReceipts(root, storeOf(root));
|
|
92
|
-
const closed = meets(root, storeOf(root), under ?? '') && !swept.written.length;
|
|
93
93
|
// Sealed files do not imply an empty reading. If a retained fold is stale,
|
|
94
94
|
// foldPlace must reload its evidence; a valid retained fold still costs no read.
|
|
95
95
|
const fold = foldPlace(root, entry, under, false, { standing: swept.standingAt.get(under ?? '') ?? standingOf(root, under), ...(swept.settled ? {} : { observed: swept.observed.length ? swept.observed : observedClaims(root, storeOf(root), { wait: false }) }), free: !swept.settled });
|
|
96
|
+
const closed = meets(root, storeOf(root), under ?? '', true, fold.observed) && !swept.written.length;
|
|
96
97
|
for (const line of releasePolicyLines(fold.release))
|
|
97
98
|
process.stdout.write(`${line}\n`);
|
|
98
99
|
if (closed) {
|
|
@@ -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();
|
package/dist/cli/place.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface PlaceFold {
|
|
|
28
28
|
readonly missing: readonly string[];
|
|
29
29
|
readonly history: readonly string[];
|
|
30
30
|
readonly observed: readonly string[];
|
|
31
|
+
readonly receiptHistory?: readonly string[];
|
|
31
32
|
readonly ceilings: {
|
|
32
33
|
readonly read: number;
|
|
33
34
|
readonly total: number;
|
|
@@ -63,6 +64,7 @@ export declare function standingOf(root: string, under?: string, told?: readonly
|
|
|
63
64
|
export declare function coneOf(root: string, entry: string, ceilings: readonly string[], descent?: readonly string[]): {
|
|
64
65
|
readonly standing: readonly string[];
|
|
65
66
|
readonly observed: readonly string[];
|
|
67
|
+
readonly receiptHistory?: readonly string[];
|
|
66
68
|
readonly own: Readonly<Record<string, number>>;
|
|
67
69
|
readonly kept: boolean;
|
|
68
70
|
};
|
package/dist/cli/place.js
CHANGED
|
@@ -20,7 +20,7 @@ import { canonical, LOCK, parse } from '@lapxo/topos/wire';
|
|
|
20
20
|
import { classDefaults, kindsOf, placesIn, spoken } from "../fold/places.js";
|
|
21
21
|
import { isCeiling } from "../fold/configures.js";
|
|
22
22
|
import { observedClaims, placedReadings } from "../fold/observed.js";
|
|
23
|
-
import { capsuleReadingsOver } from "../observe/regions.js";
|
|
23
|
+
import { capsuleReadingsOver, currentReceiptObservations, retiredReceiptHistory } from "../observe/regions.js";
|
|
24
24
|
import { costReadings, ownReadings } from "../fold/own.js";
|
|
25
25
|
import { paidOf } from "../fold/paid.js";
|
|
26
26
|
import { rolesOf } from "../fold/roles.js";
|
|
@@ -175,7 +175,8 @@ export function coneOf(root, entry, ceilings, descent) {
|
|
|
175
175
|
const named = regionsNamed(standing);
|
|
176
176
|
const reach = descent !== undefined && descent.length ? [...descent] : [...new Set(ceilings.map((line) => boundOf(named, line).region))];
|
|
177
177
|
const read = observedClaims(root, store, { wait: false, ...(reach.includes('') ? {} : { reach }) });
|
|
178
|
-
const
|
|
178
|
+
const current = currentReceiptObservations({ root, store, standing, observed: read });
|
|
179
|
+
const observed = [...current, ...capsuleReadingsOver({ root, store, standing, observed: read })];
|
|
179
180
|
const own = {
|
|
180
181
|
...ownReadings({ root, store, entry, roleOf: rolesOf(store), standing, observed, unadmitted: rendered.grey.length + rendered.refused.length, orphans: 0 }),
|
|
181
182
|
...costReadings(store, standing),
|
|
@@ -213,7 +214,8 @@ export function foldPlace(root, entry, under, look = true, given) {
|
|
|
213
214
|
const spent = [];
|
|
214
215
|
const took = timing(spent);
|
|
215
216
|
const read = given?.observed ?? (under ? took('observe', () => observedClaims(root, store, { wait: look })) : reached);
|
|
216
|
-
const
|
|
217
|
+
const current = currentReceiptObservations({ root, store, ...(under ? { under } : {}), standing, observed: read });
|
|
218
|
+
const everywhere = [...current, ...took('capsules', () => capsuleReadingsOver({ root, store, ...(under ? { under } : {}), standing, observed: read }))];
|
|
217
219
|
const points = foldPoints(store, standing, under, folder, self, reached, root, answered, reads);
|
|
218
220
|
const taken = bytesDigest(store, new TextEncoder().encode(points.join('\n'))).replace(/^sha256:/, '');
|
|
219
221
|
const observed = everywhere.filter((line) => !/ measure=observed /.test(line) || inside(fieldOf(line, 'scope')));
|
|
@@ -241,6 +243,7 @@ export function foldPlace(root, entry, under, look = true, given) {
|
|
|
241
243
|
demands, paid, missing,
|
|
242
244
|
history: live.history.filter((line) => fieldOf(line, 'needs').split('|').filter(Boolean).some(inside)),
|
|
243
245
|
observed,
|
|
246
|
+
receiptHistory: retiredReceiptHistory({ root, store, ...(under ? { under } : {}), standing, observed: read }),
|
|
244
247
|
ceilings: {
|
|
245
248
|
read: folded.read.length,
|
|
246
249
|
total: ceilings.length,
|
|
@@ -290,7 +293,7 @@ export function foldPlace(root, entry, under, look = true, given) {
|
|
|
290
293
|
over: listed(again.over.filter((o) => o.side === 'over')),
|
|
291
294
|
},
|
|
292
295
|
};
|
|
293
|
-
if (folder !== undefined &&
|
|
296
|
+
if (folder !== undefined && meets(root, store, under ?? '', true, whole.observed))
|
|
294
297
|
took('keep', () => keepFold(store, taken, whole, points, self));
|
|
295
298
|
process.stderr.write(`SPENT fold ${spent.join(' ms · ')} ms\n`);
|
|
296
299
|
return whole;
|
|
@@ -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
|
}
|
package/dist/cli/verb.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { printReleaseApproval } from "./release-result.js";
|
|
3
|
+
import { inspectReference } from "../host/reference.js";
|
|
4
|
+
import { authenticatedReferenceSelected, openAuthenticatedReference } from "../host/reference-native.js";
|
|
3
5
|
import { printActResult } from "./act-result.js";
|
|
4
6
|
import { printStandingResult } from "./standing-result.js";
|
|
5
7
|
import { withContentStore } from "../host/content-store.js";
|
|
@@ -10,7 +12,8 @@ import { cellsWithReceipts } from "../host/cell-receipts.js";
|
|
|
10
12
|
import { renderCells } from '@lapxo/topos/cells-view';
|
|
11
13
|
import { releasePolicyLines } from "../fold/release-policy.js";
|
|
12
14
|
import { admittedObjects } from "../host/objects.js";
|
|
13
|
-
import { objectFold } from "../
|
|
15
|
+
import { objectFold } from "../engine/index.js";
|
|
16
|
+
import { foldObjectsWithWasm, usesWasmObject } from "../wasm/object.js";
|
|
14
17
|
import { OBJECT_VIEW } from '@lapxo/topos/wire';
|
|
15
18
|
import { toposStanding } from '@lapxo/topos/standing';
|
|
16
19
|
import { wireAt, parse as parseWire } from '@lapxo/topos/wire';
|
|
@@ -42,9 +45,9 @@ import { placesIn } from "../fold/places.js";
|
|
|
42
45
|
import { isCeiling } from "../fold/configures.js";
|
|
43
46
|
import { readingsIn } from "../land/inert.js";
|
|
44
47
|
import { pass } from "./pass.js";
|
|
45
|
-
import { underTheLock, underTheRegions } from "../land/act.js";
|
|
48
|
+
import { underTheLock, underTheRegions, underRootAuthority } from "../land/act.js";
|
|
46
49
|
import { ownerOf, renderInto, signedDemands, targetFile } from "./owner.js";
|
|
47
|
-
import { claimLinesIn, entryOf, namedPlaces, positionalsOf, valueOf } from "./args.js";
|
|
50
|
+
import { claimLinesIn, entryOf, namedPlaces, positionalIndexes, positionalsOf, valueOf } from "./args.js";
|
|
48
51
|
import { EXIT, FLAGS, NAMED_VIEWS, helpLines } from "./names.js";
|
|
49
52
|
import { accept, signedBatch } from "./accept.js";
|
|
50
53
|
import { renderWalk, landWalk, foreignWalkLines } from "../host/walk.js";
|
|
@@ -182,12 +185,18 @@ function beat(root, fold, ms) {
|
|
|
182
185
|
* as if the batch had landed: the batch is signed and folded, never landed, and nothing is written — `--as rank <batch>`
|
|
183
186
|
* is what a batch would move, read before land.
|
|
184
187
|
*/
|
|
185
|
-
async function view(root, under, asked, told = [], coord, key, includePolicy = true) {
|
|
188
|
+
async function view(root, under, asked, told = [], coord, key, includePolicy = true, authorityHeld = false) {
|
|
186
189
|
const [name = asked, depth] = asked.split('@');
|
|
187
190
|
if (name === NAMED_VIEWS.help) {
|
|
188
191
|
process.stdout.write(`${helpLines().join('\n')}\n`);
|
|
189
192
|
return EXIT.closed;
|
|
190
193
|
}
|
|
194
|
+
// A declared executable reader holds the acting Root's authority throughout
|
|
195
|
+
// observation and publication. This predicate acquires exclusion only; the
|
|
196
|
+
// native route authenticates the actual declaration before use.
|
|
197
|
+
if (!authorityHeld && !told.length && !readOnly() && lockStanding(storeOf(root)).some(line => /^reader\/.+\/port$/.test(fieldOf(line, 'scope')) && fieldOf(line, 'role') === 'writes' && fieldOf(line, 'value') !== 'withdraw')) {
|
|
198
|
+
return underRootAuthority(storeOf(root), 'view reader authority', () => view(root, under, asked, told, coord, key, includePolicy, true));
|
|
199
|
+
}
|
|
191
200
|
if (!lockLines(storeOf(root)).length) {
|
|
192
201
|
process.stderr.write(`${selfName()}: the owner ledger is empty; land it before rendering a view\n`);
|
|
193
202
|
return EXIT.refuse;
|
|
@@ -440,6 +449,28 @@ function foldFile(at) {
|
|
|
440
449
|
return EXIT.closed;
|
|
441
450
|
}
|
|
442
451
|
function foldVerb(root, rest) {
|
|
452
|
+
const references = positionalsOf(rest).filter(one => /^#bound(?::|$)/.test(one));
|
|
453
|
+
if (references.length) {
|
|
454
|
+
if (references.length !== 1 || positionalsOf(rest).length !== 1 || rest.some(one => one.startsWith('--')))
|
|
455
|
+
throw Error('REFUSE·reference name one reference without view, check or signing options');
|
|
456
|
+
if (authenticatedReferenceSelected(standingOf(root).standing))
|
|
457
|
+
return openAuthenticatedReference(root, references[0]).then(result => {
|
|
458
|
+
process.stdout.write(`SOURCE ${result.reference.source}\n`);
|
|
459
|
+
for (const line of result.semanticStanding.split('\n').filter(Boolean))
|
|
460
|
+
process.stdout.write(`TOPOS ${line}\n`);
|
|
461
|
+
for (const cell of result.readings)
|
|
462
|
+
process.stdout.write('CELL ' + JSON.stringify(cell) + '\n');
|
|
463
|
+
process.stdout.write(`AUTHENTICATED standing ${result.semanticIdentity} · authority ${result.authorityContextIdentity} · no effects committed\n`);
|
|
464
|
+
return EXIT.closed;
|
|
465
|
+
});
|
|
466
|
+
return inspectReference(references[0], standingOf(root).standing).then(result => {
|
|
467
|
+
process.stdout.write(`SOURCE ${result.reference.source}\n`);
|
|
468
|
+
for (const line of result.lines)
|
|
469
|
+
process.stdout.write(`TOPOS ${line}\n`);
|
|
470
|
+
process.stdout.write(`INSPECT standing sha256:${result.reference.digest} · blob ${result.reference.blob} · no encounters computed · unauthenticated\n`);
|
|
471
|
+
return EXIT.closed;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
443
474
|
const files = positionalsOf(rest).filter((one) => existsSync(resolve(one)) && !lstatSync(resolve(one)).isDirectory() && one.endsWith(EXTENSION));
|
|
444
475
|
const places = positionalsOf(rest).filter((one) => existsSync(resolve(one)) && lstatSync(resolve(one)).isDirectory());
|
|
445
476
|
if (files.length === 1 && !places.length && valueOf(rest, FLAGS.as) === undefined) {
|
|
@@ -495,9 +526,21 @@ async function foldResolved(root, under, argv) {
|
|
|
495
526
|
throw Error('REFUSE·object one history snapshot per fold');
|
|
496
527
|
const history = inputs.length ? claimLinesIn(inputs[0]) : signedOwnerLines(storeOf(root));
|
|
497
528
|
const held = await admittedObjects(root, history, text => process.stdout.write(text + '\n'));
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
529
|
+
let cells;
|
|
530
|
+
if (usesWasmObject(held.configuration)) {
|
|
531
|
+
const cancellation = new AbortController(), interrupt = () => cancellation.abort();
|
|
532
|
+
process.once('SIGINT', interrupt);
|
|
533
|
+
try {
|
|
534
|
+
cells = await foldObjectsWithWasm(root, held.records, held.context, held.configuration, cancellation.signal);
|
|
535
|
+
}
|
|
536
|
+
finally {
|
|
537
|
+
process.removeListener('SIGINT', interrupt);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else
|
|
541
|
+
cells = objectFold(held.records, held.context);
|
|
542
|
+
for (const cell of cells)
|
|
543
|
+
process.stdout.write('CELL ' + JSON.stringify(cell) + '\n');
|
|
501
544
|
process.stdout.write(`FACT object fold ${cells.length} cells\n`);
|
|
502
545
|
return EXIT.closed;
|
|
503
546
|
}
|
|
@@ -565,8 +608,21 @@ function main(argv) {
|
|
|
565
608
|
const run = verb in VERBS ? VERBS[verb] : undefined;
|
|
566
609
|
const places = positionalsOf(run === undefined ? argv : argv.slice(1)).filter((one) => existsSync(resolve(one)) && lstatSync(resolve(one)).isDirectory());
|
|
567
610
|
if (run !== undefined) {
|
|
568
|
-
const
|
|
569
|
-
|
|
611
|
+
const rest = argv.slice(1);
|
|
612
|
+
const roots = positionalIndexes(rest).filter(index => {
|
|
613
|
+
const path = resolve(rest[index]);
|
|
614
|
+
return existsSync(path) && lstatSync(path).isDirectory();
|
|
615
|
+
});
|
|
616
|
+
if (roots.length > 1) {
|
|
617
|
+
process.stderr.write(`${selfName()}: REFUSE·root name one acting directory\n`);
|
|
618
|
+
return EXIT.usage;
|
|
619
|
+
}
|
|
620
|
+
const selected = roots[0];
|
|
621
|
+
const root = resolve(selected === undefined ? '.' : rest[selected]);
|
|
622
|
+
const normalized = selected === undefined ? rest : rest.filter((_, index) => index !== selected);
|
|
623
|
+
return withContentStore(storeOf(root), () => verb === 'fold' && selected !== undefined && !positionalsOf(normalized).some(one => /^#bound(?::|$)/.test(one))
|
|
624
|
+
? foldAt(root, undefined, normalized)
|
|
625
|
+
: run(root, normalized, [verb, ...normalized]), () => standingOf(root).standing);
|
|
570
626
|
}
|
|
571
627
|
const under = argv[0] ?? '';
|
|
572
628
|
if (under && !under.startsWith('-') && places.includes(under)) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure projection of already admitted typed-object records.
|
|
3
|
+
* Input is the effective history already admitted by the host, preserving cell
|
|
4
|
+
* declarations before uses within each epoch and a deterministic selected context.
|
|
5
|
+
* This API performs no admission,
|
|
6
|
+
* signature verification, storage, transport, clock selection or execution.
|
|
7
|
+
* Object operations delegate to the existing Obligations implementation.
|
|
8
|
+
*/
|
|
9
|
+
export { objectFold } from './object.ts';
|
|
10
|
+
export type { ObjectReading } from './object.ts';
|
|
11
|
+
export type { ObjectRecord, ObjectContext } from '@lapxo/topos/wire';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure projection of already admitted typed-object records.
|
|
3
|
+
* Input is the effective history already admitted by the host, preserving cell
|
|
4
|
+
* declarations before uses within each epoch and a deterministic selected context.
|
|
5
|
+
* This API performs no admission,
|
|
6
|
+
* signature verification, storage, transport, clock selection or execution.
|
|
7
|
+
* Object operations delegate to the existing Obligations implementation.
|
|
8
|
+
*/
|
|
9
|
+
export { objectFold } from "./object.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Mark, Cell } from '@lapxo/obligations/views/field';
|
|
2
|
+
import type { ObjectRecord, ObjectContext } from '@lapxo/topos/wire';
|
|
3
|
+
/** Projection dispatches admitted acts into Obligatory; it defines no meet or propagation. */
|
|
4
|
+
export interface ObjectReading {
|
|
5
|
+
cell: string;
|
|
6
|
+
state: string;
|
|
7
|
+
parts: Cell<unknown>;
|
|
8
|
+
rest: readonly string[];
|
|
9
|
+
ownMarks: readonly (string | undefined)[];
|
|
10
|
+
ownClaims: readonly {
|
|
11
|
+
id: string | undefined;
|
|
12
|
+
origin: string;
|
|
13
|
+
}[];
|
|
14
|
+
marks: readonly Mark<unknown>[];
|
|
15
|
+
claims: readonly unknown[];
|
|
16
|
+
}
|
|
17
|
+
export declare function objectFold(records: readonly ObjectRecord[], context: ObjectContext): readonly ObjectReading[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { cell, sign, join, require as requireFloor, observe, mark, parts, state, live, restOf } from '@lapxo/obligations/views/field';
|
|
2
|
+
import { restCoordinates } from '@lapxo/topos/wire';
|
|
3
|
+
export function objectFold(records, context) {
|
|
4
|
+
let world = new Map();
|
|
5
|
+
const definitions = new Map(records.filter(r => r.record === 'cell').map(r => [r.fields.scope, r]));
|
|
6
|
+
const codecs = new Map([...definitions].map(([name, c]) => [name, context.resolve(c)]));
|
|
7
|
+
const ids = new Map(records.map(r => [r.fields.id, r]));
|
|
8
|
+
for (const record of [...records].sort((a, b) => Number(a.fields.epoch) - Number(b.fields.epoch))) {
|
|
9
|
+
const f = record.fields, name = f.scope, at = Number(f.epoch);
|
|
10
|
+
if (record.record === 'cell') {
|
|
11
|
+
world = new Map([...world, [name, cell(name, at, [], restCoordinates(f.restsOn))]]);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const codec = codecs.get(name), L = codec.form.lattice(codec.params), held = world.get(name);
|
|
15
|
+
if (record.record === 'claim') {
|
|
16
|
+
const target = f.sign === '-1' ? ids.get(f.takes).fields : f;
|
|
17
|
+
const changed = observe(held, { id: f.id, at, origin: target.origin, span: codec.form.parse(codec.params, target.value), ...(f.takes ? { takes: f.takes } : {}) }, f.sign === '-1' ? -1 : 1);
|
|
18
|
+
const seen = [...changed.seen];
|
|
19
|
+
seen[seen.length - 1] = { ...seen.at(-1), id: f.id };
|
|
20
|
+
world = new Map([...world, [name, { ...changed, seen }]]);
|
|
21
|
+
}
|
|
22
|
+
else if (f.sign === '-1') {
|
|
23
|
+
const target = ids.get(f.takes).fields;
|
|
24
|
+
world = new Map([...world, [name, { ...held, marks: [...(held.marks ?? []), mark({ id: f.id, at, takes: f.takes, pole: target.pole, reach: 'local', span: codec.form.parse(codec.params, target.value) })] }]]);
|
|
25
|
+
}
|
|
26
|
+
else if (f.widens !== undefined) {
|
|
27
|
+
const changed = join(L, held, codec.form.parse(codec.params, f.value), f.widens, at);
|
|
28
|
+
const marks = [...(changed.marks ?? [])];
|
|
29
|
+
marks[marks.length - 1] = { ...marks.at(-1), id: f.id };
|
|
30
|
+
world = new Map([...world, [name, { ...changed, marks }]]);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const span = codec.form.parse(codec.params, f.value);
|
|
34
|
+
world = f.pole === 'floor' ? requireFloor(L, world, name, span, { id: f.id, at }) : sign(L, world, name, span, { id: f.id, at });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return [...world].map(([name, c]) => { const codec = codecs.get(name), L = codec.form.lattice(codec.params); return { cell: name, state: state(L, c, world), parts: parts(L, c, world), rest: restOf(c, world), ownMarks: live(c.marks ?? []).map(m => m.id), ownClaims: live(c.seen).map(s => ({ id: s.id, origin: s.origin })), marks: live(c.marks ?? []), claims: live(c.seen) }; });
|
|
38
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { rootLedgerLines, storeOf } from "../land/ledger.js";
|
|
4
4
|
import { fieldOf, isConfig, selfName } from "./claims.js";
|
|
5
5
|
/** Local admission history only. Foreign ingress is evidence, never coverage.
|
|
6
6
|
* The clock cutoff is meaningful for configuration; object clocks stay intact. */
|
|
7
7
|
export function admissionHistoryAt(root, epoch) {
|
|
8
8
|
const store = storeOf(root);
|
|
9
|
-
return [...new Set(
|
|
9
|
+
return [...new Set(rootLedgerLines(store))]
|
|
10
10
|
.filter(line => fieldOf(line, 'sig') !== '' && (!isConfig(line) || Number(fieldOf(line, 'epoch')) <= epoch));
|
|
11
11
|
}
|
|
12
12
|
/** The existing bootstrap's public root of trust, not today's key selection. */
|
package/dist/fold/claims.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { parse } from '@lapxo/topos/wire';
|
|
1
2
|
export { CAPSULE, EXTENSION, LOCK, RECEIPTS } from '@lapxo/topos/wire';
|
|
3
|
+
/** Pure syntax is retained by the exact record bytes, never by a path, epoch or
|
|
4
|
+
* claimed digest. This does not retain admission, coverage or current grants. */
|
|
5
|
+
export declare function parsedLine(line: string): ReturnType<typeof parse>;
|
|
2
6
|
export declare const fieldOf: (line: string, name: string) => string;
|
|
3
7
|
export declare const fieldsOf: (line: string) => Record<string, string>;
|
|
4
8
|
export declare function selfName(): string;
|
package/dist/fold/claims.js
CHANGED
|
@@ -4,12 +4,31 @@ import { ENVELOPE, PROTOCOL, recordKind, signedBytes, parse } from '@lapxo/topos
|
|
|
4
4
|
export { CAPSULE, EXTENSION, LOCK, RECEIPTS } from '@lapxo/topos/wire';
|
|
5
5
|
import { ownRoot } from "../observe/runner.js";
|
|
6
6
|
const decoded = new Map();
|
|
7
|
+
const parsed = new Map();
|
|
8
|
+
const kinds = new Map();
|
|
9
|
+
/** Pure syntax is retained by the exact record bytes, never by a path, epoch or
|
|
10
|
+
* claimed digest. This does not retain admission, coverage or current grants. */
|
|
11
|
+
export function parsedLine(line) {
|
|
12
|
+
const held = parsed.get(line);
|
|
13
|
+
if (held !== undefined)
|
|
14
|
+
return held;
|
|
15
|
+
const got = parse(line);
|
|
16
|
+
if (got.kind === 'fact') {
|
|
17
|
+
Object.freeze(got.value.fields);
|
|
18
|
+
if (got.value.keys)
|
|
19
|
+
Object.freeze(got.value.keys);
|
|
20
|
+
Object.freeze(got.value);
|
|
21
|
+
}
|
|
22
|
+
Object.freeze(got);
|
|
23
|
+
parsed.set(line, got);
|
|
24
|
+
return got;
|
|
25
|
+
}
|
|
7
26
|
/** Field access uses the Topos wire parser; decoding is shared for this CLI process. */
|
|
8
27
|
function wireFields(line) {
|
|
9
28
|
const held = decoded.get(line);
|
|
10
29
|
if (held !== undefined)
|
|
11
30
|
return held;
|
|
12
|
-
const got =
|
|
31
|
+
const got = parsedLine(line);
|
|
13
32
|
const fields = got.kind === 'fact' ? got.value.fields : {};
|
|
14
33
|
decoded.set(line, fields);
|
|
15
34
|
return fields;
|
|
@@ -19,8 +38,9 @@ export const fieldsOf = (line) => ({ ...wireFields(line) });
|
|
|
19
38
|
export function selfName() { return basename(ownRoot()); }
|
|
20
39
|
export function isWire(line) { return line.startsWith(PROTOCOL); }
|
|
21
40
|
export const wireLinesOf = (text) => (text ?? '').split('\n').filter(isWire);
|
|
22
|
-
export const isConfig = (line) => { const
|
|
23
|
-
|
|
41
|
+
export const isConfig = (line) => { const held = kinds.get(line); if (held !== undefined)
|
|
42
|
+
return held; const k = recordKind(line), value = k.kind === 'fact' && k.value === 'config'; kinds.set(line, value); return value; };
|
|
43
|
+
export const sayingOf = (line) => !isConfig(line) ? ((p) => p.kind === 'fact' ? signedBytes(p.value.fields) : line)(parsedLine(line)) : Object.entries(fieldsOf(line)).filter(([k]) => !ENVELOPE.has(k)).sort(([a], [b]) => (a < b ? -1 : 1)).map(([k, v]) => `${k}=${v}`).join(' ');
|
|
24
44
|
/** One key per claim: scope, role and measure; what a line says, its envelope set aside, is one however often it landed. */
|
|
25
45
|
export function claimKey(line) {
|
|
26
46
|
const f = fieldsOf(line);
|
package/dist/fold/closed.d.ts
CHANGED
|
@@ -12,4 +12,4 @@ export declare function instrumentKeep(store: string, id: string): void;
|
|
|
12
12
|
export declare function receiptPlaces(root: string, store: string): readonly string[];
|
|
13
13
|
export declare function closeReceipts(root: string, store: string, semantic?: ReadonlyMap<string, string>): Promise<readonly string[]>;
|
|
14
14
|
/** One comparison. A place meets its receipt; the root meets when every receipt it names meets. */
|
|
15
|
-
export declare function meets(root: string, store: string, place: string): boolean;
|
|
15
|
+
export declare function meets(root: string, store: string, place: string, current?: boolean, active?: readonly string[]): boolean;
|