@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
package/dist/fold/closed.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { actCosts } from "../host/act-cost.js";
|
|
2
2
|
import { verifiedReadingReceipts } from "../host/reading-closures.js";
|
|
3
|
+
import { readingProfile } from "../host/reading-context.js";
|
|
4
|
+
import { currentReadingEnvironment } from "../host/native/receipt-environment.js";
|
|
5
|
+
import { childFlags } from "../host/capsule.js";
|
|
3
6
|
import { dirname, existsSync, join, mkdirSync, relative, resolve, statSync, writeFileSync } from "../host/io.js";
|
|
4
7
|
import { byBytes, canonical, LOCK, parse, publicationOf, roleAt, roleClaimsOf } from '@lapxo/topos/wire';
|
|
5
8
|
import { RECEIPTS, fieldOf, foldClaims, isConfig, isWire } from "./claims.js";
|
|
@@ -7,9 +10,10 @@ import { bytesDigest as hashBytes, fullDigest as hashFull } from "../host/digest
|
|
|
7
10
|
import { mountedCoordinatesIn, worldAt } from "./places.js";
|
|
8
11
|
import { ownLockOf } from "./signed.js";
|
|
9
12
|
import { viewsOf } from "./views.js";
|
|
13
|
+
import { keptPlace } from "./kept.js";
|
|
10
14
|
import { storeAt, storeOf } from "../land/ledger.js";
|
|
11
15
|
import { coordinatesUnder, observeFile, observeText } from "../observe/files.js";
|
|
12
|
-
import { carriedFrom } from "./resolved.js";
|
|
16
|
+
import { bytesOnly, carriedFrom } from "./resolved.js";
|
|
13
17
|
import { takenFor } from "../fold/place-inputs.js";
|
|
14
18
|
/** A region is closed when the digest of its bytes is the one its receipt names. Folding a closed region is idle: idleCount is how many were already closed, actSeconds the largest measured act or unpartitioned host work, receiptsSeen how many receipts were read and how long that took. */
|
|
15
19
|
let idle = 0;
|
|
@@ -60,13 +64,21 @@ function filesOf(root, place, region, inputs) {
|
|
|
60
64
|
return [...new Set([...owned, ...observed, ...own])].filter(rel => rel !== receipt && !rel.split('/').some(part => part === '.bound' || part === '.cache' || part === '.git'));
|
|
61
65
|
}
|
|
62
66
|
const rooted = new Map();
|
|
67
|
+
let lastConfiguration;
|
|
63
68
|
function publicConfiguration(lines) {
|
|
69
|
+
const input = lines.join('\n');
|
|
70
|
+
// Retain only this pure projection. Callers still read and hash the actual
|
|
71
|
+
// files; neither a timestamp nor a previous seal proves their current bytes.
|
|
72
|
+
if (lastConfiguration?.input === input)
|
|
73
|
+
return lastConfiguration.output;
|
|
64
74
|
if (!lines.length || !lines.every(isConfig))
|
|
65
75
|
return lines;
|
|
66
76
|
const folded = foldClaims(lines);
|
|
67
77
|
if (folded.forks.length)
|
|
68
78
|
throw Error('REFUSE·receipt disputed configuration standing');
|
|
69
|
-
|
|
79
|
+
const output = publicationOf(folded.standing.filter(line => fieldOf(line, 'value') !== 'withdraw'));
|
|
80
|
+
lastConfiguration = { input, output };
|
|
81
|
+
return output;
|
|
70
82
|
}
|
|
71
83
|
function rootLines(root, place) {
|
|
72
84
|
const name = place.replace(/\/$/, '');
|
|
@@ -167,7 +179,7 @@ export async function closeReceipts(root, store, semantic) {
|
|
|
167
179
|
return open;
|
|
168
180
|
}
|
|
169
181
|
/** One comparison. A place meets its receipt; the root meets when every receipt it names meets. */
|
|
170
|
-
export function meets(root, store, place) {
|
|
182
|
+
export function meets(root, store, place, current = true, active) {
|
|
171
183
|
const name = place.replace(/\/$/, '');
|
|
172
184
|
if (name === '') {
|
|
173
185
|
const at = Date.now();
|
|
@@ -178,14 +190,31 @@ export function meets(root, store, place) {
|
|
|
178
190
|
let closed = (own.length > 0 ? ownClosed : named.size > 0) && [...named].every(([one, expected]) => {
|
|
179
191
|
const bytes = observeFile(join(root, one, RECEIPTS));
|
|
180
192
|
const algorithm = expected.split(':')[0];
|
|
181
|
-
return bytes !== undefined && hashBytes(bytes, algorithm) === expected && meets(root, store, `${one}
|
|
193
|
+
return bytes !== undefined && hashBytes(bytes, algorithm) === expected && meets(root, store, `${one}/`, current);
|
|
182
194
|
});
|
|
183
195
|
if (closed && carried) {
|
|
184
|
-
const algorithm = algorithmIn(own.join('\n'));
|
|
185
|
-
const
|
|
196
|
+
const algorithm = algorithmIn(own.join('\n')), hash = (text) => hashFull(text, algorithm);
|
|
197
|
+
const profile = readingProfile((observeText(join(root, LOCK)) ?? '').split('\n').filter(isWire), fieldOf);
|
|
198
|
+
// History keeps its canonical identity and bytes. It does not become a
|
|
199
|
+
// current execution merely because it shares a public carrier with one.
|
|
200
|
+
const readings = verifiedReadingReceipts(store, carried, hash, undefined, profile);
|
|
186
201
|
if (readings === undefined)
|
|
187
202
|
closed = false;
|
|
188
|
-
else if (readings)
|
|
203
|
+
else if (current && profile && readings) {
|
|
204
|
+
const stamp = instrumentKept(store);
|
|
205
|
+
const snapshot = active ?? (stamp ? keptPlace(store, undefined, stamp)?.observed : undefined);
|
|
206
|
+
if (snapshot === undefined)
|
|
207
|
+
closed = false;
|
|
208
|
+
else {
|
|
209
|
+
const units = snapshot.filter(line => fieldOf(line, 'scope').startsWith('receipts/readings/') && fieldOf(line, 'role') === 'writes');
|
|
210
|
+
const supplied = new Set(carried);
|
|
211
|
+
const present = units.length > 0 && units.every(line => supplied.has(line) || (fieldOf(line, 'measure') === 'observed' && supplied.has(bytesOnly(line))));
|
|
212
|
+
const fresh = present ? verifiedReadingReceipts(store, snapshot, hash, currentReadingEnvironment(store, root, hash, childFlags()), profile) : undefined;
|
|
213
|
+
if (!fresh)
|
|
214
|
+
closed = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (closed && readings)
|
|
189
218
|
process.stderr.write(`RECEIPTS ${readings} read · 0 opened · reading closures\n`);
|
|
190
219
|
}
|
|
191
220
|
seen = { count: named.size + (own.length > 0 ? 1 : 0), ms: Date.now() - at };
|
package/dist/fold/digests.d.ts
CHANGED
|
@@ -26,4 +26,4 @@ export declare function memoized(store: string, key: string, compute: () => stri
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function instrumentOf(store: string, entry: string, standing?: readonly string[], root?: string, releases?: readonly string[]): string;
|
|
28
28
|
export declare function instrumentDigest(store: string, entry: string, standing?: readonly string[], root?: string, releases?: readonly string[]): string;
|
|
29
|
-
export declare function instrumentCoordinates(store: string, entry: string, standing?: readonly string[], root?: string, releases?: readonly string[]): ReadonlyMap<string, string>;
|
|
29
|
+
export declare function instrumentCoordinates(store: string, entry: string, standing?: readonly string[], root?: string, releases?: readonly string[], fresh?: boolean): ReadonlyMap<string, string>;
|
package/dist/fold/digests.js
CHANGED
|
@@ -160,19 +160,21 @@ const importsOf = (store, at, digest) => {
|
|
|
160
160
|
* A fold is a function of its points and the instrument is one of them, so a fold kept by another bound is another
|
|
161
161
|
* origin's fold — readable as history, never as this instrument's own state.
|
|
162
162
|
*/
|
|
163
|
-
export function instrumentOf(store, entry, standing = [], root
|
|
164
|
-
|
|
163
|
+
export function instrumentOf(store, entry, standing = [], root, releases = []) {
|
|
164
|
+
const coordinate = root === undefined ? resolve(entry) : resolve(root, entry);
|
|
165
|
+
return instrumentDigest(store, coordinate, standing, root ?? dirname(coordinate), releases).replace(/^[^:]*:/, '').slice(0, 12);
|
|
165
166
|
}
|
|
166
167
|
export function instrumentDigest(store, entry, standing = [], root = dirname(resolve(entry)), releases = []) {
|
|
167
168
|
const seen = instrumentCoordinates(store, entry, standing, root, releases);
|
|
168
169
|
return bytesDigest(store, new TextEncoder().encode([...seen.values()].sort().join('\n')));
|
|
169
170
|
}
|
|
170
|
-
export function instrumentCoordinates(store, entry, standing = [], root = dirname(resolve(entry)), releases = []) {
|
|
171
|
+
export function instrumentCoordinates(store, entry, standing = [], root = dirname(resolve(entry)), releases = [], fresh = false) {
|
|
171
172
|
const seen = new Map();
|
|
172
173
|
const walk = (at) => {
|
|
173
174
|
if (seen.has(at))
|
|
174
175
|
return;
|
|
175
|
-
const
|
|
176
|
+
const bytes = fresh ? observeFile(at) : undefined;
|
|
177
|
+
const digest = fresh ? (bytes === undefined ? undefined : bytesDigest(store, bytes)) : coordinateDigest(store, at);
|
|
176
178
|
if (digest === undefined)
|
|
177
179
|
return;
|
|
178
180
|
// The host loader resolves links before loading a module. Count that module
|
package/dist/fold/evidence.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface SnapshotInput {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
export declare function snapshotVerdict(input: SnapshotInput): {
|
|
25
|
-
verdict: "none" | "grey" | "
|
|
25
|
+
verdict: "none" | "grey" | "stale" | "agrees" | "forks";
|
|
26
26
|
external: boolean;
|
|
27
27
|
epoch: number;
|
|
28
28
|
};
|
package/dist/fold/kept.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeUTF8 } from "../host/io.js";
|
|
1
2
|
import { actLines, committedLocalActs } from "../host/ports/local-act.js";
|
|
2
3
|
import { readOnly } from "../host/read-only.js";
|
|
3
4
|
import { createHash, dirname, existsSync, join, mkdirSync, readdirSync, renameSync, writeFileSync } from "../host/io.js";
|
|
@@ -10,7 +11,7 @@ import { keyFor, keyOf, lockSigners } from "./keys.js";
|
|
|
10
11
|
import { sourceOf, vouching } from "../land/vouched.js";
|
|
11
12
|
import { wordsOf } from "./wire.js";
|
|
12
13
|
import { ownLock } from "../observe/runner.js";
|
|
13
|
-
const text =
|
|
14
|
+
const text = encodeUTF8;
|
|
14
15
|
const atOf = (line) => {
|
|
15
16
|
if (line.includes(' about='))
|
|
16
17
|
return fieldOf(line, 'at');
|
package/dist/fold/object.d.ts
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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[];
|
|
1
|
+
/** Compatibility path; the engine owns the single object projection. */
|
|
2
|
+
export { objectFold } from '../engine/index.ts';
|
|
3
|
+
export type { ObjectReading } from '../engine/index.ts';
|
package/dist/fold/object.js
CHANGED
|
@@ -1,38 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
+
/** Compatibility path; the engine owns the single object projection. */
|
|
2
|
+
export { objectFold } from "../engine/index.js";
|
package/dist/fold/observed.d.ts
CHANGED
package/dist/fold/observed.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import { authenticatedStanding } from "../host/admitted-place.js";
|
|
1
2
|
import { actCosts } from "../host/act-cost.js";
|
|
2
3
|
import { readingClosures } from "../host/reading-closures.js";
|
|
4
|
+
import { readingExecution, readingProfile } from "../host/reading-context.js";
|
|
5
|
+
import { withNativeReaderRoute } from "../host/native-reader-context.js";
|
|
6
|
+
import { prepareNativeReaderRoute, assertNativeRouteCurrent, materializeNativeRoute } from "../host/native/route.js";
|
|
7
|
+
import { verifiedContent } from "../host/content-store.js";
|
|
8
|
+
import { ownLock, ownRoot, ownStore } from "../observe/runner.js";
|
|
3
9
|
import { readerLifetime, readerAllowsEmpty, assertReaderInputs, parse as parseLifetime } from '@lapxo/topos/wire';
|
|
4
10
|
import { readOnly } from "../host/read-only.js";
|
|
5
|
-
import { basename, dirname, existsSync, mkdirSync, resolve, rmSync, spawn, statSync, writeFileSync } from "../host/io.js";
|
|
11
|
+
import { basename, dirname, relative, existsSync, mkdirSync, resolve, rmSync, spawn, statSync, writeFileSync } from "../host/io.js";
|
|
6
12
|
import { bundleOf, processOf } from "../observe/runner.js";
|
|
7
13
|
import { canonical, parse, PROTOCOL } from '@lapxo/topos/wire';
|
|
8
|
-
import { bytesDigest, memoized } from "./digests.js";
|
|
14
|
+
import { bytesDigest, memoized, instrumentCoordinates } from "./digests.js";
|
|
9
15
|
import { land, landMemo, landShard, memoAt, shardLines, storeAt } from "../land/ledger.js";
|
|
10
16
|
import { fieldOf, isWire } from "./claims.js";
|
|
11
17
|
import { rolesOf } from "./roles.js";
|
|
@@ -154,8 +160,10 @@ function carried(store) {
|
|
|
154
160
|
return carriedIn(store).flatMap((file) => (observeText(file) ?? '').split('\n'))
|
|
155
161
|
.filter((line) => isWire(line) && speaker !== undefined && fieldOf(line, 'by').split(':')[0] === speaker);
|
|
156
162
|
}
|
|
163
|
+
const readerSelection = (reader) => reader.capsule?.selected?.selection === undefined ? undefined : 'sha256:' + sha(JSON.stringify([reader.capsule.selected.selection, reader.capsule.region, reader.module, reader.where, [...reader.capsule.globs]]));
|
|
164
|
+
const readerScope = (reader) => reader.capsule?.selected?.selection === undefined ? `reader/${reader.module}` : `reader/${reader.module}/${sha(`${reader.capsule.selected.selection}\n${reader.capsule.region}`)}`;
|
|
157
165
|
const lineagesOf = (store, speaker, readers, regions) => new Set(readers.flatMap((reader) => shardLines(store, speaker, regionIn(regions, reader.module))
|
|
158
|
-
.filter((line) => fieldOf(line, 'scope') ===
|
|
166
|
+
.filter((line) => fieldOf(line, 'scope') === readerScope(reader) && /(?:^|\s)measure=(?:identity|extension)\s/.test(line)).map((line) => fieldOf(line, 'value'))));
|
|
159
167
|
export function readerLines(store) {
|
|
160
168
|
const readers = readersOf(store);
|
|
161
169
|
const regions = [...new Set(readers.flatMap((reader) => reader.where.map(trimmed)))];
|
|
@@ -188,8 +196,28 @@ export function observedClaims(root, store, options = {}) {
|
|
|
188
196
|
const standing = lockStanding(store);
|
|
189
197
|
const lines = readersOf(store);
|
|
190
198
|
const readers = [...lines, ...capsuleReadersOf(root, store, standing, lines)];
|
|
199
|
+
if (options.selected !== undefined) {
|
|
200
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(options.selected) || options.only === undefined)
|
|
201
|
+
throw Error('REFUSE·reader invalid internal background selector');
|
|
202
|
+
if (readers.filter(reader => reader.module === options.only && readerSelection(reader) === options.selected).length !== 1)
|
|
203
|
+
throw Error('REFUSE·reader internal background selector is not uniquely adopted');
|
|
204
|
+
}
|
|
191
205
|
if (!readers.length)
|
|
192
206
|
return carried(store);
|
|
207
|
+
const modern = readingProfile(standing, fieldOf);
|
|
208
|
+
const implementation = modern ? instrumentCoordinates(store, processOf('verb'), [], ownRoot(), ownLock(), true) : undefined;
|
|
209
|
+
if (implementation)
|
|
210
|
+
for (const module of [processOf('host'), processOf('lifetime', 'host')])
|
|
211
|
+
for (const [coordinate, digest] of instrumentCoordinates(store, module, [], ownRoot(), ownLock(), true))
|
|
212
|
+
implementation.set(coordinate, digest);
|
|
213
|
+
const code = implementation ? bytesDigest(store, new TextEncoder().encode([...implementation.values()].sort().join('\n'))) : undefined;
|
|
214
|
+
const transitive = implementation ? [...implementation].map(([coordinate, digest]) => [relative(ownRoot(), coordinate), digest]) : [];
|
|
215
|
+
if (modern)
|
|
216
|
+
for (const line of ownLock().filter(line => fieldOf(line, 'scope').startsWith('dep/') && fieldOf(line, 'role') === 'reads' && fieldOf(line, 'value') !== 'withdraw')) {
|
|
217
|
+
const digest = fieldOf(line, 'value');
|
|
218
|
+
verifiedContent(digest, store, ownStore());
|
|
219
|
+
transitive.push([fieldOf(line, 'scope'), digest]);
|
|
220
|
+
}
|
|
193
221
|
const speaker = keyFor(store, 'read');
|
|
194
222
|
const regions = [...new Set(readers.flatMap((reader) => reader.where.map(trimmed)))];
|
|
195
223
|
const whole = options.only === undefined && options.reach === undefined;
|
|
@@ -258,6 +286,8 @@ export function observedClaims(root, store, options = {}) {
|
|
|
258
286
|
for (const reader of readers) {
|
|
259
287
|
if (options.only !== undefined && reader.module !== options.only)
|
|
260
288
|
continue;
|
|
289
|
+
if (options.selected !== undefined && readerSelection(reader) !== options.selected)
|
|
290
|
+
continue;
|
|
261
291
|
if (!readerReaches(options.reach, reader.where))
|
|
262
292
|
continue;
|
|
263
293
|
const started = Date.now();
|
|
@@ -274,12 +304,23 @@ export function observedClaims(root, store, options = {}) {
|
|
|
274
304
|
if (projection.length !== 1 || !asked)
|
|
275
305
|
throw Error('REFUSE·input projection is ambiguous ' + reader.module);
|
|
276
306
|
const files = [...new Set(reader.where.flatMap(where => handedAt(root, reader, roleOf, look, where)))].sort().map(place => ({ place, text: observeText(resolve(root, place)) ?? '' }));
|
|
277
|
-
const
|
|
307
|
+
const hash = (text) => bytesDigest(store, Buffer.from(text));
|
|
308
|
+
const allowsEmpty = readerAllowsEmpty(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module);
|
|
309
|
+
const native = prepareNativeReaderRoute(store, { id: reader.id, module: reader.module });
|
|
310
|
+
if (native && !modern)
|
|
311
|
+
throw Error('REFUSE·native reader requires complete reading identity ' + reader.module);
|
|
312
|
+
if (native && asked.digest !== native.profile.selection.archive)
|
|
313
|
+
throw Error('REFUSE·native reader implementation differs ' + reader.module);
|
|
314
|
+
const image = native ? materializeNativeRoute(native) : undefined;
|
|
315
|
+
const execution = modern ? readingExecution({ instrument: code, implementation: asked.digest, policy: hash(JSON.stringify([reader.id, reader.module, reader.kind, reader.shape, reader.where, lifetime ?? null, allowsEmpty])), inputs: [...transitive, ...(native?.inputs ?? []), ...(image ? [['native/mount', image.mountIdentity]] : [])] }, hash, { env: process.env, cwd: image?.cwd ?? root, flags: native ? [] : childFlags() }) : undefined;
|
|
316
|
+
const result = withNativeReaderRoute(native, () => readingClosures({ root, store, ...(execution ? { context: execution.context, execution } : {}), reader: reader.module, speaker, digest: text => bytesDigest(store, Buffer.from(text)), capsule: asked, ...(native ? { assertCurrent: () => assertNativeRouteCurrent(native) } : {}), region: reader.capsule.region, projection: fieldOf(projection[0], 'value'), livePlace: () => authenticatedStanding(root), readerReference: { id: reader.id, module: reader.module }, lifetime, allowsEmpty, files, emit: line => process.stderr.write(line + '\n') }));
|
|
278
317
|
out.push(...result.lines);
|
|
279
318
|
ran += result.executed;
|
|
280
319
|
read += result.read - result.opened;
|
|
281
320
|
return false;
|
|
282
321
|
}
|
|
322
|
+
if (modern)
|
|
323
|
+
throw Error('REFUSE·reader ' + reader.module + ' complete reading identity requires a declared input projection');
|
|
283
324
|
const endAct = actCosts.begin();
|
|
284
325
|
try {
|
|
285
326
|
const source = reader.capsule === undefined ? observeFile(module) : asked === undefined ? undefined : new Uint8Array();
|
|
@@ -287,9 +328,11 @@ export function observedClaims(root, store, options = {}) {
|
|
|
287
328
|
const offered = offersOf(root, store, reader, roleOf, look, (where) => reached(trimmed(where)));
|
|
288
329
|
assertReaderInputs(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module, offered.length);
|
|
289
330
|
const vectors = reader.capsule === undefined ? observeText(resolve(root, vectorsOf(reader.module, standing))) : undefined;
|
|
331
|
+
const selectedBy = reader.capsule?.selected?.selection === undefined ? undefined : sha(`${reader.capsule.selected.selection}\n${reader.capsule.region}${lifetime === undefined ? "" : "\n" + JSON.stringify(lifetime)}`);
|
|
290
332
|
const kept = whole && legacy === undefined && answered === undefined && source ? sha([
|
|
291
333
|
speaker, reader.module, JSON.stringify(lifetime), reader.kind, reader.shape.join('|'), reader.where.join('|'), bundle, vectors === undefined ? 'no vectors' : sha(vectors),
|
|
292
334
|
reader.capsule === undefined ? '' : `${reader.capsule.selected?.selection ?? reader.capsule.digest} ${reader.capsule.region} ${reader.capsule.reads.join('|')} ${[...reader.capsule.globs].map(([place, globs]) => `${place}${globs.join('|')}`).join(' ')}`,
|
|
335
|
+
...(selectedBy === undefined ? [] : [selectedBy]),
|
|
293
336
|
...offered.map((offer) => `${offer.place} ${offer.digest?.() ?? bytesDigest(store, offer.bytes())}`),
|
|
294
337
|
].join('\n')) : undefined;
|
|
295
338
|
const stored = kept === undefined ? undefined : observeText(memoAt(store, `observed/${kept}`));
|
|
@@ -301,10 +344,12 @@ export function observedClaims(root, store, options = {}) {
|
|
|
301
344
|
}
|
|
302
345
|
const mark = out.length;
|
|
303
346
|
const home = regionIn(regions, reader.module);
|
|
304
|
-
const own = shardLines(store, speaker, home).filter((line) => fieldOf(line, 'scope') ===
|
|
305
|
-
|
|
347
|
+
const own = shardLines(store, speaker, home).filter((line) => fieldOf(line, 'scope') === readerScope(reader));
|
|
348
|
+
// Short selected-origin identities remain stored history; they cannot name
|
|
349
|
+
// an unambiguous current origin or supply its held observations.
|
|
350
|
+
const lineage = own.filter((line) => fieldOf(line, 'measure') === 'identity').map((line) => fieldOf(line, 'value')).filter(value => selectedBy === undefined || /^[a-f0-9]{64}$/.test(value));
|
|
306
351
|
const sum = source && reader.capsule === undefined ? bytesDigest(store, new TextEncoder().encode(`${reader.module} ${bundle}${lifetime === undefined ? "" : "\n" + JSON.stringify(lifetime)}`)).replace(/^sha256:/, '').slice(0, 12) : 'none';
|
|
307
|
-
const measured = reader.capsule !== undefined ? { by: source ? sha(`${reader.capsule.
|
|
352
|
+
const measured = reader.capsule !== undefined ? { by: source ? selectedBy ?? sha(`${reader.capsule.digest}\n${reader.capsule.region}${lifetime === undefined ? "" : "\n" + JSON.stringify(lifetime)}`).slice(0, 12) : 'none', lines: [] }
|
|
308
353
|
: source ? identityOf({ store, root, speaker, module: reader.module, kind: reader.kind, code: sum, lineage, lifetime, kept: own.filter((line) => /(?:^|\s)measure=(?:extension|emits)\s/.test(line)) })
|
|
309
354
|
: { by: 'none', lines: [] };
|
|
310
355
|
const by = measured.by;
|
|
@@ -400,7 +445,7 @@ export function observedClaims(root, store, options = {}) {
|
|
|
400
445
|
const running = existsSync(marker) && Date.now() - statSync(marker).mtimeMs < 30 * 60 * 1000 && Number.isInteger(pid) && pid > 0 && alive(pid);
|
|
401
446
|
if (!running) {
|
|
402
447
|
mkdirSync(dirname(marker), { recursive: true });
|
|
403
|
-
const child = spawn(process.execPath, [...childFlags(), processOf('observe'), root, reader.module], { cwd: root, detached: true, stdio: 'ignore' });
|
|
448
|
+
const child = spawn(process.execPath, [...childFlags(), processOf('observe'), root, reader.module, ...(readerSelection(reader) === undefined ? [] : [readerSelection(reader)])], { cwd: root, detached: true, stdio: 'ignore' });
|
|
404
449
|
child.unref();
|
|
405
450
|
writeFileSync(marker, `${reader.module}\n${child.pid ?? ''}\n`);
|
|
406
451
|
}
|
|
@@ -455,7 +500,7 @@ export function observedClaims(root, store, options = {}) {
|
|
|
455
500
|
const over = bytesDigest(store, new TextEncoder().encode(due.map((d) => d.digest).sort().join('\n'))).replace(/^sha256:/, '');
|
|
456
501
|
level.push(canonical({ scope: `cost/reader/${reader.module}`, role: 'writes', form: 'interval', measure: 'ms', value: `${spent}..${spent}`, by: `${speaker}:${by}`, at: `place:${over}` }));
|
|
457
502
|
if (lineage.at(-1) !== by)
|
|
458
|
-
level.push(canonical({ scope:
|
|
503
|
+
level.push(canonical({ scope: readerScope(reader), role: 'writes', form: 'alphabet', measure: 'identity', value: by, by: `${speaker}:${by}`, at: `place:${by}` }));
|
|
459
504
|
rmSync(storeAt(store, 'pending', by), { force: true });
|
|
460
505
|
}
|
|
461
506
|
for (const plan of plans.filter((one) => one.said !== undefined)) {
|
package/dist/fold/readers.d.ts
CHANGED
|
@@ -30,9 +30,10 @@ export type Look = {
|
|
|
30
30
|
export declare function lookOf(root: string, roleOf: (coordinate: string) => CoordinateRole): Look;
|
|
31
31
|
/**
|
|
32
32
|
* The reader regions of the capsules a place can run, where the place's own lock offers them or, at a world, the wire's offers/world list does for a
|
|
33
|
-
* region its own lock does not name:
|
|
34
|
-
*
|
|
35
|
-
*
|
|
33
|
+
* region its own lock does not name: each selected capsule that writes a declared region reads the coordinates
|
|
34
|
+
* it declares among the place's offered coordinates. Selection identifies attribution, never independence.
|
|
35
|
+
* An existing reader suppresses only that same selected provider, region and place; an ambiguous legacy
|
|
36
|
+
* owner refuses instead of hiding another provider or invoking the same provider twice.
|
|
36
37
|
* A newly declared region does not need a retired reader in private history to be observed.
|
|
37
38
|
*/
|
|
38
39
|
export declare function capsuleReadersOf(root: string, store: string, standing: readonly string[], lines: readonly ReaderClaim[], resolve?: typeof capsulesFor): readonly ReaderClaim[];
|
package/dist/fold/readers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from "../host/io.js";
|
|
2
|
-
import { canonical, fields, matches } from '@lapxo/topos/wire';
|
|
2
|
+
import { canonical, fields, matches, byBytes } from '@lapxo/topos/wire';
|
|
3
3
|
import { namesAt, wordOn, wordsOf, wireLine } from "./wire.js";
|
|
4
4
|
import { fits } from "../observe/match.js";
|
|
5
5
|
import { bytesDigest, coordinateDigest } from "./digests.js";
|
|
@@ -36,13 +36,14 @@ const reachOfLine = (module, where) => {
|
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
38
|
* The reader regions of the capsules a place can run, where the place's own lock offers them or, at a world, the wire's offers/world list does for a
|
|
39
|
-
* region its own lock does not name:
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* region its own lock does not name: each selected capsule that writes a declared region reads the coordinates
|
|
40
|
+
* it declares among the place's offered coordinates. Selection identifies attribution, never independence.
|
|
41
|
+
* An existing reader suppresses only that same selected provider, region and place; an ambiguous legacy
|
|
42
|
+
* owner refuses instead of hiding another provider or invoking the same provider twice.
|
|
42
43
|
* A newly declared region does not need a retired reader in private history to be observed.
|
|
43
44
|
*/
|
|
44
45
|
export function capsuleReadersOf(root, store, standing, lines, resolve = capsulesFor) {
|
|
45
|
-
const
|
|
46
|
+
const origin = (capsule) => capsule?.selected?.selection;
|
|
46
47
|
const coordinateMeasure = wordOn(standing, 'region-coordinate', ownLock());
|
|
47
48
|
const localMeasures = wordsOf(standing, 'region-measures');
|
|
48
49
|
const pins = standing.filter(line => fieldOf(line, 'scope').startsWith('uses/') && fieldOf(line, 'value') !== 'withdraw');
|
|
@@ -59,16 +60,20 @@ export function capsuleReadersOf(root, store, standing, lines, resolve = capsule
|
|
|
59
60
|
const capsules = resolve(standing, place, root);
|
|
60
61
|
for (const line of offered) {
|
|
61
62
|
const region = fieldOf(line, 'scope').slice('region/'.length);
|
|
62
|
-
const by
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
for (const by of capsules.filter(({ capsule }) => capsule.lines.some((one) => fieldOf(one, 'scope') === `region/${region}` && fieldOf(one, 'measure') === 'writes'))) {
|
|
64
|
+
const pkg = fieldOf(by.offer, 'scope').split('/')[1] ?? '';
|
|
65
|
+
const reaches = lines.filter(reader => reachOfLine(reader.module, reader.where).includes(`${pkg} ${region} ${where || '/'}`));
|
|
66
|
+
if (reaches.some(reader => origin(reader.capsule) === undefined))
|
|
67
|
+
throw Error(`REFUSE·reader ${pkg}/${region} existing provider origin unmeasured at ${where || '/'}`);
|
|
68
|
+
if (by.capsule.selection !== undefined && lines.some(reader => origin(reader.capsule) === by.capsule.selection && reader.capsule?.region === region && reader.where.some(place => place.replace(/\/?$/, '/') === (where || '/'))))
|
|
69
|
+
continue;
|
|
70
|
+
const key = `${by.capsule.selection ?? by.capsule.digest} ${region}`;
|
|
71
|
+
const group = groups.get(key) ?? groups.set(key, { module: `${pkg}/${region}`, digest: by.capsule.digest, entry: fieldOf(by.offer, 'shape'), selected: by.capsule, region, reads: by.capsule.declaration.regions[region] ?? [], globs: new Map() }).get(key);
|
|
72
|
+
group.globs.set(where, fieldOf(line, 'value').split('|').filter(Boolean));
|
|
73
|
+
}
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
|
-
return [...groups.
|
|
76
|
+
return [...groups.entries()].sort(([a], [b]) => byBytes(a, b)).map(([, group]) => ({ id: group.module, shape: ['run'], where: [...group.globs.keys()], module: group.module, kind: 'process',
|
|
72
77
|
capsule: { selected: group.selected, digest: group.digest, entry: group.entry, region: group.region, reads: group.reads, globs: group.globs } }));
|
|
73
78
|
}
|
|
74
79
|
export function handedAt(root, reader, roleOf, look, place) {
|
package/dist/fold/resolved.js
CHANGED
|
@@ -41,7 +41,17 @@ export function receiptsOf(fold) {
|
|
|
41
41
|
const ran = [...new Set(fold.observed.filter((line) => fieldOf(line, 'measure') !== 'observed'
|
|
42
42
|
&& mine.has(`${fieldOf(line, 'by')} ${fieldOf(line, 'at')}`)))];
|
|
43
43
|
const ranAt = new Set(ran.map((line) => `${fieldOf(line, 'by')} ${fieldOf(line, 'at')}`));
|
|
44
|
-
const cones = new Set(fold.observed.filter((line) =>
|
|
44
|
+
const cones = new Set(fold.observed.filter((line) => {
|
|
45
|
+
if (fieldOf(line, 'measure') !== 'observed')
|
|
46
|
+
return false;
|
|
47
|
+
const at = fieldOf(line, 'at'), by = fieldOf(line, 'by');
|
|
48
|
+
// A physical input witnesses an owned reading's base, without becoming
|
|
49
|
+
// another location of its result. Even a foreign input belongs in that
|
|
50
|
+
// reading's portable carrier; its own child place is not the reader.
|
|
51
|
+
if (at.startsWith('witness:'))
|
|
52
|
+
return ranAt.has(`${by} place:${at.slice('witness:'.length)}`);
|
|
53
|
+
return own(fieldOf(line, 'scope')) && ranAt.has(`${by} ${at}`);
|
|
54
|
+
}).map(bytesOnly));
|
|
45
55
|
const paid = ledgerLines(fold.store, 'judge').filter((line) => fold.paid.some((demand) => fieldOf(demand, 'scope') === fieldOf(line, 'scope')
|
|
46
56
|
&& !(closed.length > 0 && fieldOf(demand, 'needs').split('|').filter(Boolean).length > 0
|
|
47
57
|
&& fieldOf(demand, 'needs').split('|').filter(Boolean).every((need) => closed.some((one) => need.startsWith(one))))));
|
|
@@ -50,7 +60,7 @@ export function receiptsOf(fold) {
|
|
|
50
60
|
return canonical({ scope: `${sourced(fold.standing)}/${place}${shape}`, role: 'writes', form: 'alphabet', measure: 'digest', value: digest, by: writerFor(fold.standing, 'fold') ?? '', at: `place:${digest}` });
|
|
51
61
|
});
|
|
52
62
|
const place = under.replace(/\/$/, '');
|
|
53
|
-
const lines = [...named, ...[...cones].sort(), ...[...ran].sort(), ...paid]
|
|
63
|
+
const lines = [...new Set([...named, ...[...cones].sort(), ...[...ran].sort(), ...paid, ...(fold.receiptHistory ?? [])])]
|
|
54
64
|
.map((line) => (place && !fieldOf(line, 'sig') ? zoomed(line, place) : line));
|
|
55
65
|
if (!lines.length) {
|
|
56
66
|
const shipped = (observeText(join(fold.root, under, RECEIPTS)) ?? '').split('\n').filter(isWire);
|
package/dist/fold/signers.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, join } from "../host/io.js";
|
|
2
|
-
import { authorityOf, isKeyClaim,
|
|
2
|
+
import { authorityOf, isKeyClaim, signersOf } from '@lapxo/topos/wire';
|
|
3
3
|
import { verifiesFields } from "../land/sign.js";
|
|
4
|
-
import { fieldOf, selfName } from "./claims.js";
|
|
4
|
+
import { fieldOf, selfName, parsedLine as parse } from "./claims.js";
|
|
5
5
|
import { keyFor, lockStanding } from "./keys.js";
|
|
6
6
|
import { storeRoot } from "../host/ports/store.js";
|
|
7
7
|
import { storeOf } from "../land/ledger.js";
|
|
@@ -15,12 +15,7 @@ export function moduleImports(source, coordinate) {
|
|
|
15
15
|
throw Error('REFUSE·source module syntax cannot be read: ' + coordinate);
|
|
16
16
|
}
|
|
17
17
|
const found = new Set();
|
|
18
|
-
const literal =
|
|
19
|
-
if (!node || typeof node !== 'object')
|
|
20
|
-
return;
|
|
21
|
-
const n = node;
|
|
22
|
-
return n['type'] === 'Literal' && typeof n['value'] === 'string' ? n['value'] : undefined;
|
|
23
|
-
};
|
|
18
|
+
const literal = stringLiteral;
|
|
24
19
|
const visit = (node) => {
|
|
25
20
|
if (!node || typeof node !== 'object')
|
|
26
21
|
return;
|
|
@@ -46,3 +41,10 @@ export function moduleImports(source, coordinate) {
|
|
|
46
41
|
visit(tree);
|
|
47
42
|
return [...found];
|
|
48
43
|
}
|
|
44
|
+
/** A JavaScript literal value; syntax inventory never executes it. */
|
|
45
|
+
export const stringLiteral = (node) => {
|
|
46
|
+
if (!node || typeof node !== 'object')
|
|
47
|
+
return;
|
|
48
|
+
const n = node;
|
|
49
|
+
return n['type'] === 'Literal' && typeof n['value'] === 'string' ? n['value'] : undefined;
|
|
50
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Existing admission-snapshot authentication and folded live projection.
|
|
2
|
+
* Consumer configuration evidence only; never a new authority lock. */
|
|
3
|
+
export declare function authenticatedRootStanding(root: string): readonly string[];
|
|
4
|
+
/** Legacy Root lines remain unchanged; contextual public output has its own carrier. */
|
|
5
|
+
export declare const authenticatedStanding: typeof authenticatedRootStanding;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { hashText } from "./hash.js";
|
|
2
|
+
import { admissionAnchor, admissionHistoryAt } from "../fold/admission-history.js";
|
|
3
|
+
import { authorityFor } from "../fold/signers.js";
|
|
4
|
+
import { eraOf } from "../fold/digests.js";
|
|
5
|
+
import { fieldOf, foldClaims, isConfig } from "../fold/claims.js";
|
|
6
|
+
import { foldedEvidence } from '@lapxo/topos/contract';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
// One bounded historical projection, never a current authority/lease verdict.
|
|
9
|
+
// Its complete inputs are reread before lookup, including original signatures.
|
|
10
|
+
let historicalProjection;
|
|
11
|
+
function historicalIdentity(history, anchor) {
|
|
12
|
+
const hash = createHash('sha256'), text = hashText.bind(undefined, hash);
|
|
13
|
+
text('authenticated-root-history/1');
|
|
14
|
+
text(String(history.length));
|
|
15
|
+
for (const line of history)
|
|
16
|
+
text(line);
|
|
17
|
+
text(JSON.stringify(anchor));
|
|
18
|
+
return hash.digest('hex');
|
|
19
|
+
}
|
|
20
|
+
/** Existing admission-snapshot authentication and folded live projection.
|
|
21
|
+
* Consumer configuration evidence only; never a new authority lock. */
|
|
22
|
+
export function authenticatedRootStanding(root) {
|
|
23
|
+
const history = admissionHistoryAt(root, Number.MAX_SAFE_INTEGER), anchor = admissionAnchor(root);
|
|
24
|
+
const identity = historicalIdentity(history, anchor);
|
|
25
|
+
if (historicalProjection?.identity === identity)
|
|
26
|
+
return [...historicalProjection.standing];
|
|
27
|
+
const snapshots = new Map();
|
|
28
|
+
const admitted = history.filter(line => {
|
|
29
|
+
const epoch = Number(fieldOf(line, 'epoch')) || 0;
|
|
30
|
+
let authority = snapshots.get(epoch);
|
|
31
|
+
if (!authority) {
|
|
32
|
+
// This invocation has freshly read the complete signed inventory. Derive
|
|
33
|
+
// the same historical cutoff without reopening it for every epoch; the
|
|
34
|
+
// next invocation still rereads every authority input.
|
|
35
|
+
const snapshot = history.filter(record => !isConfig(record) || Number(fieldOf(record, 'epoch')) <= epoch);
|
|
36
|
+
// The signature vocabulary is configuration, not the as-yet
|
|
37
|
+
// unauthenticated evidence whose values are about to be folded.
|
|
38
|
+
const wire = snapshot.filter(record => {
|
|
39
|
+
const scope = fieldOf(record, 'scope');
|
|
40
|
+
return scope.startsWith('wire/') || scope.startsWith('audit/wire/');
|
|
41
|
+
});
|
|
42
|
+
authority = authorityFor(snapshot, anchor, eraOf(foldClaims(wire).standing).admitted);
|
|
43
|
+
snapshots.set(epoch, authority);
|
|
44
|
+
}
|
|
45
|
+
return authority.of(line).kind === 'admitted';
|
|
46
|
+
});
|
|
47
|
+
// The host authenticates against historical authority; Topos projects the
|
|
48
|
+
// authenticated history using the instrument's existing fold.
|
|
49
|
+
const { standing } = foldedEvidence(admitted, {
|
|
50
|
+
classification: () => 'local',
|
|
51
|
+
fold: lines => foldClaims(lines).standing,
|
|
52
|
+
});
|
|
53
|
+
historicalProjection = { identity, standing: Object.freeze([...standing]) };
|
|
54
|
+
return [...standing];
|
|
55
|
+
}
|
|
56
|
+
/** Legacy Root lines remain unchanged; contextual public output has its own carrier. */
|
|
57
|
+
export const authenticatedStanding = authenticatedRootStanding;
|
|
@@ -18,4 +18,4 @@ export declare class CapsuleProcessError extends Error {
|
|
|
18
18
|
}
|
|
19
19
|
export declare function validResponse(value: unknown, request: Request): value is Response;
|
|
20
20
|
/** Last-line JSON is the wire framing. No partial batch, failed exit or synthetic missing response is accepted. */
|
|
21
|
-
export declare function executeCapsule(command: string, args: readonly string[], requests: readonly Request[], limits?: Pick<SpawnSyncOptionsWithStringEncoding, 'timeout' | 'maxBuffer'>, lifetime?: ReaderLifetime): readonly Response[];
|
|
21
|
+
export declare function executeCapsule(command: string, args: readonly string[], requests: readonly Request[], limits?: Pick<SpawnSyncOptionsWithStringEncoding, 'timeout' | 'maxBuffer' | 'env' | 'cwd'>, lifetime?: ReaderLifetime): readonly Response[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { actCosts } from "./act-cost.js";
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
2
3
|
import { boundedProcess } from "./process-lifetime.js";
|
|
3
4
|
import { spawnSync } from 'node:child_process';
|
|
4
5
|
import { PROTOCOL } from '@lapxo/topos/wire';
|
|
@@ -35,7 +36,9 @@ export function validResponse(value, request) {
|
|
|
35
36
|
/** Last-line JSON is the wire framing. No partial batch, failed exit or synthetic missing response is accepted. */
|
|
36
37
|
export function executeCapsule(command, args, requests, limits = {}, lifetime) {
|
|
37
38
|
return actCosts.measure(() => {
|
|
38
|
-
const
|
|
39
|
+
const cwd = limits.cwd;
|
|
40
|
+
const directory = cwd === undefined ? undefined : typeof cwd === 'string' ? cwd : fileURLToPath(cwd);
|
|
41
|
+
const run = lifetime === undefined ? spawnSync(command, args, { input: JSON.stringify(requests), encoding: 'utf8', maxBuffer: 1 << 26, ...limits }) : boundedProcess(command, args, JSON.stringify(requests), lifetime, directory, limits.env);
|
|
39
42
|
if ('error' in run && run.error)
|
|
40
43
|
throw new CapsuleProcessError(`failed: ${run.error.message}`, run);
|
|
41
44
|
if (run.signal !== null || run.status !== 0)
|