@lapxo/bound 0.1.2 → 0.1.4
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 +5 -5
- package/TARGET.bound +27 -20
- package/dist/cli/accept.js +112 -71
- package/dist/cli/owner.js +3 -0
- package/dist/cli/verb.js +54 -12
- package/dist/fold/configures.js +3 -1
- package/dist/fold/digests.js +7 -1
- package/dist/fold/kept.js +5 -1
- package/dist/fold/observed.d.ts +1 -0
- package/dist/fold/observed.js +30 -11
- package/dist/fold/readers.d.ts +2 -0
- package/dist/fold/readers.js +3 -3
- package/dist/fold/region-declarations.d.ts +2 -0
- package/dist/fold/region-declarations.js +13 -0
- package/dist/fold/resolved.js +9 -1
- package/dist/fold/second.js +3 -0
- package/dist/host/adapters/transport/http.d.ts +5 -0
- package/dist/host/adapters/transport/http.js +28 -0
- package/dist/host/capsule-process.d.ts +2 -1
- package/dist/host/capsule-process.js +4 -3
- package/dist/host/capsule.d.ts +1 -0
- package/dist/host/capsule.js +11 -7
- package/dist/host/cell-receipts.js +1 -1
- package/dist/host/content-needed.d.ts +5 -0
- package/dist/host/content-needed.js +8 -0
- package/dist/host/content-store.d.ts +8 -0
- package/dist/host/content-store.js +31 -0
- package/dist/host/lifetime.d.ts +1 -0
- package/dist/host/lifetime.js +40 -0
- package/dist/host/objects.js +1 -1
- package/dist/host/ports/transport.d.ts +1 -0
- package/dist/host/ports/transport.js +48 -0
- package/dist/host/process-lifetime.d.ts +11 -0
- package/dist/host/process-lifetime.js +12 -0
- package/dist/host/read-only.d.ts +3 -0
- package/dist/host/read-only.js +9 -0
- package/dist/host/release.js +2 -1
- package/dist/host/selected-capsules.js +38 -12
- package/dist/host/selected-topos.d.ts +5 -5
- package/dist/host/selected-topos.js +9 -36
- package/dist/host/source-content.d.ts +5 -3
- package/dist/host/source-content.js +36 -30
- package/dist/land/leaving.js +4 -0
- package/dist/land/ledger.js +3 -0
- package/dist/observe/identity.d.ts +2 -0
- package/dist/observe/identity.js +3 -3
- package/dist/observe/regions.js +2 -2
- package/dist/observe/run.d.ts +2 -1
- package/dist/observe/run.js +10 -4
- package/dist/render/receipts.js +2 -1
- package/package.json +2 -2
- package/receipts.bound +73 -72
package/dist/cli/accept.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withoutEffects } from "../host/read-only.js";
|
|
1
2
|
import { selectedWireAt } from "../host/selected-topos.js";
|
|
2
3
|
import { timing } from "../host/timing.js";
|
|
3
4
|
import { admittedObjects } from "../host/objects.js";
|
|
@@ -22,7 +23,7 @@ import { ownLock, ownRoot, ownStore } from "../observe/runner.js";
|
|
|
22
23
|
import { widenedWithoutWitness } from "../judge/widening.js";
|
|
23
24
|
import { retractedTogether, withdrawal } from "../land/withdraw.js";
|
|
24
25
|
import { isCeiling } from "../fold/configures.js";
|
|
25
|
-
import { inertIn
|
|
26
|
+
import { inertIn } from "../land/inert.js";
|
|
26
27
|
import { landSaid } from "./pass.js";
|
|
27
28
|
import { underTheLock, underTheRegions } from "../land/act.js";
|
|
28
29
|
import { openedBy } from "../fold/opened.js";
|
|
@@ -39,6 +40,68 @@ import { ownerOf, epochOf, forksItself, forksJoinedBy, renderInto, sideOf, signe
|
|
|
39
40
|
import { claimLinesIn, entryOf, namedPlaces, placesOfFile, positionalsOf, valueOf } from "./args.js";
|
|
40
41
|
import { FLAGS } from "./names.js";
|
|
41
42
|
import { judgeDemand, landTake } from "./takes.js";
|
|
43
|
+
/** Admission reads an existing evidence snapshot; acquiring observations belongs to fold. */
|
|
44
|
+
function admissionEvidence(root, signed, standing) {
|
|
45
|
+
return withoutEffects(() => {
|
|
46
|
+
const store = storeOf(root);
|
|
47
|
+
const reads = !signed.some(isReaderLock) && signed.some(isCeiling);
|
|
48
|
+
const fold = reads ? coneOf(root, entryOf(root), signed.filter(isCeiling)) : { standing, observed: [], own: {}, kept: true };
|
|
49
|
+
const inert = inertIn(signed, { standing: fold.standing, ceiling: isCeiling, signsReader: !reads, observed: fold.observed, own: fold.own, epoch: epochOf([...lockLines(store), ...signed]) });
|
|
50
|
+
if (inert.length)
|
|
51
|
+
throw Error('REFUSE·inert no existing reading meets these ceilings; fold the declared inputs first');
|
|
52
|
+
const coordinates = coordinatesWithdrawn(root, store, signed, [...signed, ...standing]);
|
|
53
|
+
if (coordinates.refused.length)
|
|
54
|
+
throw Error(`REFUSE·withdraw a file is still read: ${coordinates.refused.map(one => `${one.path} by ${one.by}`).join(' · ')}`);
|
|
55
|
+
const view = `${wordOf(standing, 'families', 'view')}/`;
|
|
56
|
+
const judged = signed.filter(one => isConfig(one) && fieldOf(one, 'role') === 'demands' && fieldOf(one, 'value') !== 'withdraw' && !fieldOf(one, 'scope').startsWith(view)).map(one => judgeDemand(root, one));
|
|
57
|
+
const refused = judged.filter(one => one.kind === 'refused' || (one.kind === 'judged' && one.verdict.kind === 'refuse'));
|
|
58
|
+
if (refused.length)
|
|
59
|
+
throw Error(`REFUSE·takes ${refused.map(one => `${one.scope}: ${one.kind === 'judged' ? one.verdict.why : one.kind === 'refused' ? one.why : ''}`).join(' · ')}`);
|
|
60
|
+
return { coordinates, judged, fold };
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** One witness rule for prospective admission and the locked act. */
|
|
64
|
+
function refusesWidening(signed, standing) {
|
|
65
|
+
const widened = widenedWithoutWitness(signed, standing, isCeiling, wordOf(standing, 'at-classes', 'witness'));
|
|
66
|
+
if (widened.length) {
|
|
67
|
+
for (const line of widened)
|
|
68
|
+
process.stderr.write(`WIDER ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
69
|
+
process.stderr.write(`${selfName()}: REFUSE·widening nothing landed · a ceiling that admits more than it did gives back freedom the lock had spent: sign it under a witness that names what made the old ceiling wrong\n`);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
/** Admission-only checks; observation and mutation belong to the later act. */
|
|
75
|
+
function refusesAdmission(root, signed, standing) {
|
|
76
|
+
if (refusesWidening(signed, standing))
|
|
77
|
+
return true;
|
|
78
|
+
const store = storeOf(root);
|
|
79
|
+
const outside = outsideTheirCapsule(root, standing, signed);
|
|
80
|
+
for (const line of outside)
|
|
81
|
+
process.stderr.write(`OUTSIDE ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
82
|
+
if (outside.length) {
|
|
83
|
+
process.stderr.write(`${selfName()}: REFUSE·outside nothing landed · a reader or a capsule lands in the capsule of its world, never in the wire or the instrument\n`);
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
const forks = forksJoinedBy(store, signed).filter(fork => forksItself(fork.lines) || fork.lines.filter(line => signed.includes(line)).length > 1);
|
|
87
|
+
if (forks.length) {
|
|
88
|
+
for (const fork of forks) {
|
|
89
|
+
process.stderr.write(`FORK ${fork.key}\n`);
|
|
90
|
+
for (const line of fork.lines)
|
|
91
|
+
process.stderr.write(` ${signed.includes(line) ? 'new ' : 'held'} by=${fieldOf(line, 'by')} ${sideOf(line, lockLines(store))}\n`);
|
|
92
|
+
}
|
|
93
|
+
process.stderr.write(`${selfName()}: REFUSE·fork nothing landed · one signer never forks itself, and one act never forks itself: withdraw the held side in this batch, or sign the other reading under its own scope\n`);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
const held = aliasPinned(root, signed);
|
|
97
|
+
if (held.length) {
|
|
98
|
+
for (const one of held)
|
|
99
|
+
process.stderr.write(`ALIAS ${one.scope} · ${one.digest} · ${one.by.join(' ')}\n`);
|
|
100
|
+
process.stderr.write(`${selfName()}: REFUSE·alias nothing landed · an alias is withdrawn only when no pin names its digest\n`);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
42
105
|
/** A batch signed as accept signs it: at the next epoch, by the key it names, each line read by the wire it would land under. */
|
|
43
106
|
export async function signedBatch(root, args, files) {
|
|
44
107
|
const byFile = files.map((file) => [placesOfFile(file), claimLinesIn(file)]);
|
|
@@ -57,10 +120,16 @@ export async function signedBatch(root, args, files) {
|
|
|
57
120
|
}
|
|
58
121
|
const store = storeOf(root);
|
|
59
122
|
const destinations = [...new Set([...namedPlaces(args), ...byFile.flatMap(([heads]) => heads)])];
|
|
123
|
+
const rooted = lockStanding(store);
|
|
124
|
+
const stray = destinations.filter(one => !placesIn(root).includes(one) && !foundableIn(root, rooted, wordOf(rooted, 'families', 'region'), one));
|
|
125
|
+
if (stray.length) {
|
|
126
|
+
process.stderr.write(`${selfName()}: REFUSE·place nothing landed · ${stray.join(', ')} is no place of the tree, and no line of the root founds it: --place names the own lock a line lands in\n`);
|
|
127
|
+
return { kind: 'exit', code: 2 };
|
|
128
|
+
}
|
|
60
129
|
const epoch = epochOf([...lockLines(store), ...destinations.flatMap((place) => appliedIn(root, place))]) + 1;
|
|
61
130
|
const stale = proposed.filter((line) => fieldOf(line, 'sig')).flatMap((line) => ((by, key) => (key === undefined || !verifiesOwnerLine(line, key, signaturesOf(store).admitted)
|
|
62
131
|
? [`${fieldOf(line, 'scope')} · the signature does not hold for ${by || '∅'}`]
|
|
63
|
-
:
|
|
132
|
+
: []))(fieldOf(line, 'by'), publicKeyOf(root, fieldOf(line, 'by'))));
|
|
64
133
|
if (stale.length) {
|
|
65
134
|
for (const one of stale)
|
|
66
135
|
process.stderr.write(`SIGNED ${one}\n`);
|
|
@@ -85,6 +154,13 @@ export async function signedBatch(root, args, files) {
|
|
|
85
154
|
}
|
|
86
155
|
return { kind: 'once', proposed };
|
|
87
156
|
}
|
|
157
|
+
const outdated = proposed.filter(line => fieldOf(line, 'sig') && isConfig(line) && Number(fieldOf(line, 'epoch')) !== epoch);
|
|
158
|
+
if (outdated.length) {
|
|
159
|
+
for (const line of outdated)
|
|
160
|
+
process.stderr.write(`SIGNED ${fieldOf(line, 'scope')} · signed by ${fieldOf(line, 'by')} at epoch ${fieldOf(line, 'epoch')}, and this act lands at ${epoch}: sign it again\n`);
|
|
161
|
+
process.stderr.write(`${selfName()}: REFUSE·signed nothing landed · ${outdated.length} lines a lane signed stand at no epoch this act\n`);
|
|
162
|
+
return { kind: 'exit', code: 1 };
|
|
163
|
+
}
|
|
88
164
|
const keyFile = valueOf(args, FLAGS.keyFile);
|
|
89
165
|
const keyId = valueOf(args, FLAGS.key) ?? ownerOf(store);
|
|
90
166
|
const publicKey = drafted.length ? publicKeyOf(root, keyId) : undefined;
|
|
@@ -121,6 +197,15 @@ export async function signedBatch(root, args, files) {
|
|
|
121
197
|
return { kind: 'exit', code: 1 };
|
|
122
198
|
}
|
|
123
199
|
}
|
|
200
|
+
const taken = retractedTogether(signed);
|
|
201
|
+
if (taken.length) {
|
|
202
|
+
for (const pair of taken) {
|
|
203
|
+
process.stderr.write(`WITHDRAW ${sayingOf(pair.withdraw)}\n`);
|
|
204
|
+
process.stderr.write(`NEW ${sayingOf(pair.line)}\n`);
|
|
205
|
+
}
|
|
206
|
+
process.stderr.write(`${selfName()}: REFUSE·withdraw nothing landed · a withdraw matches a new line in this batch, so it takes that line too\n`);
|
|
207
|
+
return { kind: 'exit', code: 1 };
|
|
208
|
+
}
|
|
124
209
|
const authority = authorityFor([...lockLines(store), ...signed], rootSigner(root), signaturesOf(store).admitted);
|
|
125
210
|
const ownership = ownedOf(root, signed, line => authority.of(line).kind === 'admitted', by => authority.admitted.find(one => one.id === by)?.coverage ?? [], named, line => { const heads = byFile.flatMap(([heads, lines]) => lines.some(draft => sayingOf(draft) === sayingOf(line)) ? heads : []); return heads.length ? heads : undefined; });
|
|
126
211
|
if (ownership.nowhere.length) {
|
|
@@ -128,6 +213,14 @@ export async function signedBatch(root, args, files) {
|
|
|
128
213
|
process.stderr.write(`${selfName()}: REFUSE·signer ${keyId} uncovered ${fieldOf(line, 'scope')} · nothing signed for delivery\n`);
|
|
129
214
|
return { kind: 'exit', code: 1 };
|
|
130
215
|
}
|
|
216
|
+
if (ownership.forked.length) {
|
|
217
|
+
for (const one of ownership.forked)
|
|
218
|
+
process.stderr.write(`FORKED ${one.place}/${LOCK} · ${one.key} · the lot would leave two standing claims where the lock had one\n`);
|
|
219
|
+
process.stderr.write(`${selfName()}: REFUSE·forked nothing landed · ${ownership.forked.length} claims an own lot would fork: a lot for many places lands the same lines at each, and lines meant for one place go in a lot of their own\n`);
|
|
220
|
+
return { kind: 'exit', code: 1 };
|
|
221
|
+
}
|
|
222
|
+
if (refusesAdmission(root, ownership.ledger, lockStanding(store)))
|
|
223
|
+
return { kind: 'exit', code: 1 };
|
|
131
224
|
if (signed.some(line => !isConfig(line))) {
|
|
132
225
|
try {
|
|
133
226
|
await admittedObjects(root, [...signedOwnerLines(store), ...signed], text => process.stdout.write(text + '\n'));
|
|
@@ -137,6 +230,13 @@ export async function signedBatch(root, args, files) {
|
|
|
137
230
|
return { kind: 'exit', code: 1 };
|
|
138
231
|
}
|
|
139
232
|
}
|
|
233
|
+
try {
|
|
234
|
+
admissionEvidence(root, ownership.ledger, lockStanding(store));
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
process.stderr.write(`${selfName()}: ${error instanceof Error ? error.message : String(error)} · nothing landed\n`);
|
|
238
|
+
return { kind: 'exit', code: 1 };
|
|
239
|
+
}
|
|
140
240
|
return { kind: 'signed', signed, epoch, ...(drafted.length ? { keyId } : {}) };
|
|
141
241
|
}
|
|
142
242
|
/**
|
|
@@ -151,26 +251,11 @@ export async function accept(root, args) {
|
|
|
151
251
|
const started = Date.now();
|
|
152
252
|
const named = namedPlaces(args);
|
|
153
253
|
const placed = positionalsOf(args).reduce((all, file) => ((places) => (places.length ? claimLinesIn(file).reduce((got, line) => got.set(sayingOf(line), [...new Set([...(got.get(sayingOf(line)) ?? []), ...places])]), all) : all))(placesOfFile(file)), new Map());
|
|
154
|
-
const rooted = lockStanding(storeOf(root));
|
|
155
|
-
const stray = [...new Set([...named, ...[...placed.values()].flat()])].filter((one) => !placesIn(root).includes(one) && !foundableIn(root, rooted, wordOf(rooted, 'families', 'region'), one));
|
|
156
|
-
if (stray.length) {
|
|
157
|
-
process.stderr.write(`${selfName()}: REFUSE·place nothing landed · ${stray.join(', ')} is no place of the tree, and no line of the root founds it: --place names the own lock a line lands in\n`);
|
|
158
|
-
return 2;
|
|
159
|
-
}
|
|
160
254
|
const batch = await signedBatch(root, args, positionalsOf(args));
|
|
161
255
|
if (batch.kind === 'exit')
|
|
162
256
|
return batch.code;
|
|
163
257
|
if (batch.kind === 'once')
|
|
164
258
|
return underTheLock(storeOf(root), 'land', () => repaid(root, batch.proposed, started));
|
|
165
|
-
const taken = retractedTogether(batch.signed);
|
|
166
|
-
if (taken.length) {
|
|
167
|
-
for (const pair of taken) {
|
|
168
|
-
process.stderr.write(`WITHDRAW ${sayingOf(pair.withdraw)}\n`);
|
|
169
|
-
process.stderr.write(`NEW ${sayingOf(pair.line)}\n`);
|
|
170
|
-
}
|
|
171
|
-
process.stderr.write(`${selfName()}: REFUSE·withdraw nothing landed · a withdraw matches a new line in this batch, so it takes that line too\n`);
|
|
172
|
-
return 1;
|
|
173
|
-
}
|
|
174
259
|
const store = storeOf(root);
|
|
175
260
|
const authority = authorityFor([...lockLines(store), ...batch.signed], rootSigner(root), signaturesOf(store).admitted);
|
|
176
261
|
const owned = ownedOf(root, batch.signed, (line) => authority.of(line).kind === 'admitted', (by) => authority.admitted.find((one) => one.id === by)?.coverage ?? [], named, (line) => placed.get(sayingOf(line)));
|
|
@@ -180,12 +265,6 @@ export async function accept(root, args) {
|
|
|
180
265
|
process.stderr.write(`${selfName()}: REFUSE·nowhere nothing landed · ${owned.nowhere.length} lines neither the ledger nor an own lock admits: a line is landed signed where it stands, never written in bare\n`);
|
|
181
266
|
return 1;
|
|
182
267
|
}
|
|
183
|
-
if (owned.forked.length) {
|
|
184
|
-
for (const one of owned.forked)
|
|
185
|
-
process.stderr.write(`FORKED ${one.place}/${LOCK} · ${one.key} · the lot would leave two standing claims where the lock had one\n`);
|
|
186
|
-
process.stderr.write(`${selfName()}: REFUSE·forked nothing landed · ${owned.forked.length} claims an own lot would fork: a lot for many places lands the same lines at each, and lines meant for one place go in a lot of their own\n`);
|
|
187
|
-
return 1;
|
|
188
|
-
}
|
|
189
268
|
const places = placesIn(root);
|
|
190
269
|
const pinned = [...new Set([...owned.own.keys(), ...named])];
|
|
191
270
|
const touched = pinned.length === 0 && owned.ledger.length ? touchedBy(root, places, owned.ledger, lockStanding(store)) : [];
|
|
@@ -213,42 +292,18 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
213
292
|
return 1;
|
|
214
293
|
}
|
|
215
294
|
}
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
const inert = inertIn(signed, { standing: fold.standing, ceiling: isCeiling, signsReader: !reads, observed: fold.observed, own: fold.own, epoch });
|
|
219
|
-
const widened = widenedWithoutWitness(signed, fold.standing, isCeiling, wordOf(fold.standing, 'at-classes', 'witness'));
|
|
220
|
-
if (widened.length) {
|
|
221
|
-
for (const line of widened)
|
|
222
|
-
process.stderr.write(`WIDER ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
223
|
-
process.stderr.write(`${selfName()}: REFUSE·widening nothing landed · a ceiling that admits more than it did gives back freedom the lock had spent: sign it under a witness that names what made the old ceiling wrong\n`);
|
|
224
|
-
return 1;
|
|
225
|
-
}
|
|
226
|
-
if (inert.length) {
|
|
227
|
-
for (const line of inert)
|
|
228
|
-
process.stderr.write(`INERT ${fieldOf(line, 'scope')} measure=${fieldOf(line, 'measure')}\n`);
|
|
229
|
-
process.stderr.write(`${selfName()}: REFUSE·inert nothing landed · no reading meets these ceilings: sign the reader that meets them in this batch, or leave them out\n`);
|
|
295
|
+
const snapshot = took('lines', () => standingOf(root));
|
|
296
|
+
if (refusesAdmission(root, signed, snapshot.standing))
|
|
230
297
|
return 1;
|
|
298
|
+
let evidence;
|
|
299
|
+
try {
|
|
300
|
+
evidence = took('evidence', () => admissionEvidence(root, signed, snapshot.standing));
|
|
231
301
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
process.stderr.write(`OUTSIDE ${fieldOf(line, 'scope')} · ${fieldOf(line, 'value')}\n`);
|
|
235
|
-
if (outside.length) {
|
|
236
|
-
process.stderr.write(`${selfName()}: REFUSE·outside nothing landed · a reader or a capsule lands in the capsule of its world, never in the wire or the instrument\n`);
|
|
302
|
+
catch (error) {
|
|
303
|
+
process.stderr.write(`${selfName()}: ${error instanceof Error ? error.message : String(error)} · nothing landed\n`);
|
|
237
304
|
return 1;
|
|
238
305
|
}
|
|
239
|
-
const
|
|
240
|
-
if (forks.length) {
|
|
241
|
-
for (const fork of forks) {
|
|
242
|
-
process.stderr.write(`FORK ${fork.key}\n`);
|
|
243
|
-
for (const line of fork.lines)
|
|
244
|
-
process.stderr.write(` ${signed.includes(line) ? 'new ' : 'held'} by=${fieldOf(line, 'by')} ${sideOf(line, lockLines(store))}\n`);
|
|
245
|
-
}
|
|
246
|
-
process.stderr.write(`${selfName()}: REFUSE·fork nothing landed · one signer never forks itself, and one act never forks itself: withdraw the held side in this batch, or sign the other reading under its own scope\n`);
|
|
247
|
-
return 1;
|
|
248
|
-
}
|
|
249
|
-
if (reads)
|
|
250
|
-
for (const line of rankedIn(signed.filter(isCeiling), fold))
|
|
251
|
-
process.stdout.write(`${line}\n`);
|
|
306
|
+
const fold = evidence.fold;
|
|
252
307
|
const authority = took('authority', () => authorityFor([...lockLines(store), ...signed], rootSigner(root), signaturesOf(store).admitted));
|
|
253
308
|
for (const line of signed) {
|
|
254
309
|
const verdict = authority.of(line);
|
|
@@ -257,14 +312,8 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
257
312
|
return 1;
|
|
258
313
|
}
|
|
259
314
|
}
|
|
260
|
-
const coordinates = coordinatesWithdrawn(root, store, signed, [...signed, ...fold.standing]);
|
|
261
|
-
if (coordinates.refused.length) {
|
|
262
|
-
for (const one of coordinates.refused)
|
|
263
|
-
process.stderr.write(`RUN ${one.path} · still read by ${one.by}\n`);
|
|
264
|
-
process.stderr.write(`${selfName()}: REFUSE·withdraw nothing landed · a file a block still reads cannot leave: withdraw what reads it first, or keep it\n`);
|
|
265
|
-
return 1;
|
|
266
|
-
}
|
|
267
315
|
const withdraws = signed.filter((line) => fieldOf(line, 'value') === 'withdraw');
|
|
316
|
+
const coordinates = evidence.coordinates;
|
|
268
317
|
const withdrawn = withdraws.length ? withdrawal(withdraws, lockLines(store)) : null;
|
|
269
318
|
const view = `${wordOf(fold.standing, 'families', 'view')}/`;
|
|
270
319
|
const lot = fullDigest(store, signed);
|
|
@@ -272,8 +321,7 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
272
321
|
? fullDigest(store, [...vouchedCoordinates(store)].sort(([a], [b]) => a.localeCompare(b)).map(([coordinate, digest]) => `${coordinate} ${digest}`))
|
|
273
322
|
: 'key' in fold && typeof fold.key === 'string' ? fold.key : fullDigest(store, fold.standing);
|
|
274
323
|
const cached = keptTakes(keptVerdict(store, tree, lot));
|
|
275
|
-
const judged = cached ??
|
|
276
|
-
.map((line) => judgeDemand(root, line)));
|
|
324
|
+
const judged = cached ?? evidence.judged;
|
|
277
325
|
if (!cached)
|
|
278
326
|
keepVerdict(store, tree, lot, judged.map(packTake));
|
|
279
327
|
const refused = judged.filter((one) => one.kind === 'refused' || (one.kind === 'judged' && one.verdict.kind === 'refuse'));
|
|
@@ -283,13 +331,6 @@ async function acceptNow(root, batch, started, owned, asked = started, descent =
|
|
|
283
331
|
process.stderr.write(`${selfName()}: REFUSE·takes nothing landed · ${refused.length} takes refused: a batch lands whole or not at all\n`);
|
|
284
332
|
return 1;
|
|
285
333
|
}
|
|
286
|
-
const held = aliasPinned(root, signed);
|
|
287
|
-
if (held.length) {
|
|
288
|
-
for (const one of held)
|
|
289
|
-
process.stderr.write(`ALIAS ${one.scope} · ${one.digest} · ${one.by.join(' ')}\n`);
|
|
290
|
-
process.stderr.write(`${selfName()}: REFUSE·alias nothing landed · an alias is withdrawn only when no pin names its digest\n`);
|
|
291
|
-
return 1;
|
|
292
|
-
}
|
|
293
334
|
const told = took('told', () => standingOf(root, undefined, signed));
|
|
294
335
|
for (const name of openedBy(descent, told.standing, signed))
|
|
295
336
|
process.stderr.write(`OPEN ${name}\n`);
|
package/dist/cli/owner.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readOnly } from "../host/read-only.js";
|
|
1
2
|
import { keyFor, lockLines, releaseOf, signedLockLines } from "../fold/keys.js";
|
|
2
3
|
import { existsSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
4
|
import { join, resolve } from 'node:path';
|
|
@@ -83,6 +84,8 @@ export function renderedLock(root, store, told = []) {
|
|
|
83
84
|
return readRelease(released);
|
|
84
85
|
const owned = [...lockLines(store), ...told];
|
|
85
86
|
const render = () => renderTarget(owned, undefined, authorityFor(owned, rootSigner(root), signaturesOf(store, told).admitted).of, forkReceipts(store, owned));
|
|
87
|
+
if (readOnly())
|
|
88
|
+
return render();
|
|
86
89
|
if (told.length) {
|
|
87
90
|
const byLock = rendered.get(lockLines(store)) ?? rendered.set(lockLines(store), new Map()).get(lockLines(store));
|
|
88
91
|
return byLock.get(told) ?? byLock.set(told, render()).get(told);
|
package/dist/cli/verb.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { withContentStore } from "../host/content-store.js";
|
|
3
|
+
import { withoutEffects } from "../host/read-only.js";
|
|
4
|
+
import { resolveSources, resolveRequested } from "../host/source-content.js";
|
|
3
5
|
import { cellsWithReceipts } from "../host/cell-receipts.js";
|
|
6
|
+
import { renderCells } from '@lapxo/topos/cells-view';
|
|
4
7
|
import { releasePolicyLines } from "../fold/release-policy.js";
|
|
5
8
|
import { admittedObjects } from "../host/objects.js";
|
|
6
9
|
import { objectFold } from "../fold/object.js";
|
|
@@ -15,7 +18,7 @@ import { eraOf, signaturesOf } from "../fold/digests.js";
|
|
|
15
18
|
import { fullDigest as bootstrapDigest } from "../host/digest.js";
|
|
16
19
|
import { canonical } from '@lapxo/topos/wire';
|
|
17
20
|
import { EXTENSION, LOCK, fieldOf, foldClaims, isWire, selfName } from "../fold/claims.js";
|
|
18
|
-
import { observedClaims } from "../fold/observed.js";
|
|
21
|
+
import { observedClaims, readerRefusals } from "../fold/observed.js";
|
|
19
22
|
import { rolesOf } from "../fold/roles.js";
|
|
20
23
|
import { authorityFor, releaseSigner, rootSigner, writerFor } from "../fold/signers.js";
|
|
21
24
|
import { land, ledgerLines, storeOf } from "../land/ledger.js";
|
|
@@ -189,10 +192,31 @@ async function view(root, under, asked, told = [], coord, key, includePolicy = t
|
|
|
189
192
|
const rest = told.filter((line) => !ledger.includes(line));
|
|
190
193
|
if (place && rest.length)
|
|
191
194
|
tellOwn(place, rest);
|
|
195
|
+
if (name === NAMED_VIEWS.lines && (told.length || depth === undefined)) {
|
|
196
|
+
const text = standingOf(root, under, ledger).standing.filter(isWire).join('\n');
|
|
197
|
+
process.stdout.write(text ? `${text}\n` : '');
|
|
198
|
+
return EXIT.closed;
|
|
199
|
+
}
|
|
200
|
+
if (told.length) {
|
|
201
|
+
const selected = viewsOf(standingOf(root, under, ledger).standing).get(name);
|
|
202
|
+
if (selected && !selected.shape && selected.regions.some(region => region.name === 'cells')) {
|
|
203
|
+
const history = [...signedOwnerLines(storeOf(root)), ...ledger];
|
|
204
|
+
const held = await admittedObjects(root, history);
|
|
205
|
+
process.stdout.write(`TOLD ${told.length} lines folded as if landed · nothing written\n`);
|
|
206
|
+
for (const line of renderCells(objectFold(held.records, held.context)))
|
|
207
|
+
process.stdout.write(line + '\n');
|
|
208
|
+
return EXIT.closed;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
192
211
|
const own = place ? rest.filter((line) => admittedIn(root, place, line)) : [];
|
|
193
212
|
const fold = told.length
|
|
194
|
-
? foldPlace(root, entryOf(root), under, false, { standing: standingOf(root, under, ledger), observed: observedClaims(root, storeOf(root), { wait: false }) })
|
|
195
|
-
: foldPlace(root, entryOf(root), under,
|
|
213
|
+
? foldPlace(root, entryOf(root), under, false, { standing: standingOf(root, under, ledger), observed: observedClaims(root, storeOf(root), { wait: false }), free: true })
|
|
214
|
+
: foldPlace(root, entryOf(root), under, true);
|
|
215
|
+
if (!told.length && readerRefusals().length) {
|
|
216
|
+
for (const why of readerRefusals())
|
|
217
|
+
process.stderr.write(`${selfName()}: ${why}\n`);
|
|
218
|
+
return EXIT.refuse;
|
|
219
|
+
}
|
|
196
220
|
if (coord)
|
|
197
221
|
askWhy(fold, coord);
|
|
198
222
|
if (name === NAMED_VIEWS.lines) {
|
|
@@ -200,6 +224,9 @@ async function view(root, under, asked, told = [], coord, key, includePolicy = t
|
|
|
200
224
|
beat(root, fold, Date.now() - at);
|
|
201
225
|
const text = fold.standing.filter(isWire).join('\n');
|
|
202
226
|
process.stdout.write(text ? `${text}\n` : '');
|
|
227
|
+
if (depth === '1')
|
|
228
|
+
for (const line of readingsIn([...fold.standing.filter(isCeiling), ...ownCeilings(under)], fold))
|
|
229
|
+
process.stdout.write(`${line}\n`);
|
|
203
230
|
return EXIT.closed;
|
|
204
231
|
}
|
|
205
232
|
const views = viewsOf(fold.standing);
|
|
@@ -371,7 +398,7 @@ function foldFile(at) {
|
|
|
371
398
|
process.stdout.write(`FACT ${folded.standing.length} standing · ${folded.forks.length} forks · ${basename(at)}\n`);
|
|
372
399
|
return EXIT.closed;
|
|
373
400
|
}
|
|
374
|
-
function foldVerb(
|
|
401
|
+
function foldVerb(root, rest) {
|
|
375
402
|
const files = positionalsOf(rest).filter((one) => existsSync(resolve(one)) && !lstatSync(resolve(one)).isDirectory() && one.endsWith(EXTENSION));
|
|
376
403
|
const places = positionalsOf(rest).filter((one) => existsSync(resolve(one)) && lstatSync(resolve(one)).isDirectory());
|
|
377
404
|
if (files.length === 1 && !places.length && valueOf(rest, FLAGS.as) === undefined) {
|
|
@@ -381,16 +408,27 @@ function foldVerb(_root, rest) {
|
|
|
381
408
|
return foldAt(dirname(at), undefined, rest);
|
|
382
409
|
}
|
|
383
410
|
const under = places[0];
|
|
384
|
-
|
|
411
|
+
// A prospective lot is data, not the place whose authority admits it.
|
|
412
|
+
const tree = files.length ? root : resolve('.');
|
|
385
413
|
const place = under ? relative(tree, resolve(under)).split(sep).join('/') : '';
|
|
386
414
|
return foldAt(tree, place ? `${place}/` : undefined, rest);
|
|
387
415
|
}
|
|
388
416
|
async function foldAt(root, under, argv) {
|
|
417
|
+
return withContentStore(storeOf(root), () => foldRequested(root, under, argv), () => standingOf(root, under).standing);
|
|
418
|
+
}
|
|
419
|
+
async function foldRequested(root, under, argv) {
|
|
420
|
+
const as = valueOf(argv, FLAGS.as);
|
|
421
|
+
const prospective = as !== undefined && positionalsOf(argv).some(one => existsSync(resolve(one)) && !lstatSync(resolve(one)).isDirectory());
|
|
422
|
+
if (as === NAMED_VIEWS.help || prospective || argv.includes(FLAGS.check))
|
|
423
|
+
return foldResolved(root, under, argv);
|
|
424
|
+
return resolveRequested(digest => resolveSources(standingOf(root, under).standing, [digest]), () => foldResolved(root, under, argv));
|
|
425
|
+
}
|
|
426
|
+
async function foldResolved(root, under, argv) {
|
|
389
427
|
const as = valueOf(argv, FLAGS.as);
|
|
428
|
+
const inputs = positionalsOf(argv).filter(one => existsSync(resolve(one)) && !lstatSync(resolve(one)).isDirectory());
|
|
390
429
|
// Public content is authenticated by its digest, independently of owner history.
|
|
391
430
|
// A named view does not request mounting every release of the instrument.
|
|
392
|
-
|
|
393
|
-
await resolveSources(standingOf(root, under).standing, as === undefined);
|
|
431
|
+
const receiptCheck = as === undefined && argv.includes(FLAGS.check);
|
|
394
432
|
if (as === OBJECT_VIEW) {
|
|
395
433
|
const inputs = positionalsOf(argv).filter(one => existsSync(resolve(one)) && !lstatSync(resolve(one)).isDirectory());
|
|
396
434
|
if (inputs.length > 1)
|
|
@@ -406,6 +444,8 @@ async function foldAt(root, under, argv) {
|
|
|
406
444
|
const key = valueOf(argv, FLAGS.key);
|
|
407
445
|
if (as === undefined) {
|
|
408
446
|
const exit = await pass(root, entryOf(root), under, argv.includes(FLAGS.check));
|
|
447
|
+
if (receiptCheck)
|
|
448
|
+
return exit;
|
|
409
449
|
if (exit !== 0)
|
|
410
450
|
return exit;
|
|
411
451
|
const history = signedOwnerLines(storeOf(root));
|
|
@@ -421,7 +461,7 @@ async function foldAt(root, under, argv) {
|
|
|
421
461
|
}
|
|
422
462
|
return exit;
|
|
423
463
|
}
|
|
424
|
-
const named =
|
|
464
|
+
const named = inputs;
|
|
425
465
|
const coord = positionalsOf(argv).find((one) => one !== under?.replace(/\/$/, '') && !one.startsWith('-') && !(existsSync(resolve(one)) && lstatSync(resolve(one)).isDirectory()));
|
|
426
466
|
if ((as === 'why' || as === NAMED_VIEWS.because || as.split('@')[0] === 'why') && coord !== undefined)
|
|
427
467
|
return view(root, under, as === NAMED_VIEWS.because ? 'why' : as, [], coord, key);
|
|
@@ -432,7 +472,7 @@ async function foldAt(root, under, argv) {
|
|
|
432
472
|
return batch.code;
|
|
433
473
|
if (batch.kind === 'once')
|
|
434
474
|
process.stdout.write(`ONCE ${batch.proposed.length} lines · every one already landed: the view folds the tree as it stands\n`);
|
|
435
|
-
return view(root, under, as, batch.kind === 'signed' ? batch.signed :
|
|
475
|
+
return withoutEffects(() => view(root, under, as, batch.kind === 'signed' ? batch.signed : batch.proposed, undefined, key));
|
|
436
476
|
}
|
|
437
477
|
const VERBS = {
|
|
438
478
|
fold: (root, rest) => foldVerb(root, rest),
|
|
@@ -459,8 +499,10 @@ function main(argv) {
|
|
|
459
499
|
const verb = argv[0] ?? '';
|
|
460
500
|
const run = verb in VERBS ? VERBS[verb] : undefined;
|
|
461
501
|
const places = positionalsOf(run === undefined ? argv : argv.slice(1)).filter((one) => existsSync(resolve(one)) && lstatSync(resolve(one)).isDirectory());
|
|
462
|
-
if (run !== undefined)
|
|
463
|
-
|
|
502
|
+
if (run !== undefined) {
|
|
503
|
+
const root = resolve(places[0] ?? '.');
|
|
504
|
+
return withContentStore(storeOf(root), () => run(root, argv.slice(1), argv));
|
|
505
|
+
}
|
|
464
506
|
const under = argv[0] ?? '';
|
|
465
507
|
if (under && !under.startsWith('-') && places.includes(under)) {
|
|
466
508
|
const root = resolve('.');
|
package/dist/fold/configures.js
CHANGED
|
@@ -4,6 +4,8 @@ import { isReaderLock } from "./observed.js";
|
|
|
4
4
|
import { isRoleLock } from "./roles.js";
|
|
5
5
|
import { isSignerLock } from "./signers.js";
|
|
6
6
|
import { isReleaseBinding } from "../host/release.js";
|
|
7
|
+
import { isRegionDeclaration } from "./region-declarations.js";
|
|
8
|
+
import { ownLock } from "../observe/runner.js";
|
|
7
9
|
function isEffectLock(line) {
|
|
8
10
|
const got = parse(line);
|
|
9
11
|
return got.kind === 'fact' && got.value.fields['measure'] === 'effect';
|
|
@@ -11,7 +13,7 @@ function isEffectLock(line) {
|
|
|
11
13
|
/** A lock line the instrument itself consumes — an effect it runs, a reader it loads, a role it walks by, a signer it admits, the wire it reads by. */
|
|
12
14
|
function configures(line) {
|
|
13
15
|
const got = parse(line);
|
|
14
|
-
return isReleaseBinding(line) || isEffectLock(line) || isReaderLock(line) || isRoleLock(line) || isSignerLock(line) || (got.kind === 'fact' && isWireClaim(got.value.fields));
|
|
16
|
+
return isReleaseBinding(line) || isEffectLock(line) || isReaderLock(line) || isRoleLock(line) || isSignerLock(line) || (got.kind === 'fact' && isWireClaim(got.value.fields)) || isRegionDeclaration(line, ownLock());
|
|
15
17
|
}
|
|
16
18
|
/** Every reads line that configures nothing is a ceiling: a bound some reading has to meet. */
|
|
17
19
|
export function isCeiling(line) {
|
package/dist/fold/digests.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readOnly } from "../host/read-only.js";
|
|
1
2
|
import { appendFileSync, dirname, join, mkdirSync, readdirSync, relative, resolve } from "../host/io.js";
|
|
2
3
|
import { bytesDigest as bytesWith, fullDigest as fullWith } from "../host/digest.js";
|
|
3
4
|
import { coordinatesUnder, observeFile, observeText, stampOf } from "../observe/files.js";
|
|
@@ -116,6 +117,8 @@ export function coordinateDigest(store, at) {
|
|
|
116
117
|
return held;
|
|
117
118
|
const digest = bytesDigest(store, observeFile(at) ?? new Uint8Array());
|
|
118
119
|
memo.set(key, digest);
|
|
120
|
+
if (readOnly())
|
|
121
|
+
return digest;
|
|
119
122
|
mkdirSync(join(store, 'cas'), { recursive: true });
|
|
120
123
|
appendFileSync(join(store, 'cas', `stamps${EXTENSION}`), `${key}\t${digest}\n`);
|
|
121
124
|
return digest;
|
|
@@ -127,6 +130,8 @@ export function memoized(store, key, compute) {
|
|
|
127
130
|
return held;
|
|
128
131
|
const value = compute();
|
|
129
132
|
memo.set(key, value);
|
|
133
|
+
if (readOnly())
|
|
134
|
+
return value;
|
|
130
135
|
mkdirSync(join(store, 'cas'), { recursive: true });
|
|
131
136
|
appendFileSync(join(store, 'cas', `stamps${EXTENSION}`), `${key}\t${value}\n`);
|
|
132
137
|
return value;
|
|
@@ -141,7 +146,8 @@ const importsOf = (store, at, digest) => {
|
|
|
141
146
|
const found = [...new TextDecoder().decode(observeFile(at) ?? new Uint8Array()).matchAll(/(?:\bfrom\s*|\bimport\s*\(\s*|\bimport\s*)['"]([^'"]*)['"]/g)].map((m) => m[1] ?? '');
|
|
142
147
|
imported.set(digest, found);
|
|
143
148
|
memo.set(key, found.join('|'));
|
|
144
|
-
|
|
149
|
+
if (!readOnly())
|
|
150
|
+
appendFileSync(join(store, 'cas', `stamps${EXTENSION}`), `${key}\t${found.join('|')}\n`);
|
|
145
151
|
return found;
|
|
146
152
|
};
|
|
147
153
|
/**
|
package/dist/fold/kept.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readOnly } from "../host/read-only.js";
|
|
1
2
|
import { createHash, dirname, existsSync, join, mkdirSync, readdirSync, renameSync, writeFileSync } from "../host/io.js";
|
|
2
3
|
import { bytesDigest, coordinateDigest } from "./digests.js";
|
|
3
4
|
import { viewsOf } from "./views.js";
|
|
@@ -129,8 +130,11 @@ export function keptPlace(store, under) {
|
|
|
129
130
|
};
|
|
130
131
|
}
|
|
131
132
|
export const keptRender = (store, key, name) => observeText(memoAt(store, `render/${key}/${name}`));
|
|
132
|
-
export const keepRender = (store, _signer, key, name, _epoch, text_) => {
|
|
133
|
+
export const keepRender = (store, _signer, key, name, _epoch, text_) => { if (!readOnly())
|
|
134
|
+
landMemo(store, `render/${key}/${name}`, text(text_)); };
|
|
133
135
|
export function keepFold(store, key, fold, points, instrument = '') {
|
|
136
|
+
if (readOnly())
|
|
137
|
+
return;
|
|
134
138
|
const packed = {
|
|
135
139
|
...fold,
|
|
136
140
|
standing: joined(fold.standing),
|
package/dist/fold/observed.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare const readersBehind: () => readonly {
|
|
|
15
15
|
readonly module: string;
|
|
16
16
|
readonly places: number;
|
|
17
17
|
}[];
|
|
18
|
+
export declare const readerRefusals: () => readonly string[];
|
|
18
19
|
export declare function readerLines(store: string): readonly string[];
|
|
19
20
|
/**
|
|
20
21
|
* A reader never blocks a fold that did not ask to wait: what it read before is served at once, and a reader whose
|
package/dist/fold/observed.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readerLifetime, readerAllowsEmpty, assertReaderInputs, parse as parseLifetime } from '@lapxo/topos/wire';
|
|
2
|
+
import { readOnly } from "../host/read-only.js";
|
|
1
3
|
import { basename, dirname, existsSync, mkdirSync, resolve, rmSync, spawn, statSync, writeFileSync } from "../host/io.js";
|
|
2
4
|
import { bundleOf, processOf } from "../observe/runner.js";
|
|
3
5
|
import { canonical, parse, PROTOCOL } from '@lapxo/topos/wire';
|
|
@@ -15,7 +17,7 @@ import { capsuleReadersOf, handedAt, lookOf, offersOf } from "./readers.js";
|
|
|
15
17
|
import { runReader, runs } from "../observe/run.js";
|
|
16
18
|
import { LEVEL, OBSERVED, keepObservation, keyOf, legacyOf, observation, observed as observedAt, opened, pointer, readerOf, regionIn, setAside, sha, trimmed } from "./shards.js";
|
|
17
19
|
import { saidDigest } from "./kept.js";
|
|
18
|
-
import { carriedIn } from "./resolved.js";
|
|
20
|
+
import { carriedIn, carriedFrom } from "./resolved.js";
|
|
19
21
|
export const cased = (question) => /^(?:vector|sample)\//.test(question);
|
|
20
22
|
export function isReaderLock(line) {
|
|
21
23
|
const got = parse(line);
|
|
@@ -87,6 +89,8 @@ function takeReadings(observed) {
|
|
|
87
89
|
}
|
|
88
90
|
const behind = [];
|
|
89
91
|
export const readersBehind = () => behind;
|
|
92
|
+
const refused = [];
|
|
93
|
+
export const readerRefusals = () => refused;
|
|
90
94
|
const alive = (pid) => { try {
|
|
91
95
|
return process.kill(pid, 0);
|
|
92
96
|
}
|
|
@@ -170,6 +174,14 @@ export function readerReaches(reach, where) {
|
|
|
170
174
|
return where.some((one) => reached(trimmed(one)));
|
|
171
175
|
}
|
|
172
176
|
export function observedClaims(root, store, options = {}) {
|
|
177
|
+
refused.length = 0;
|
|
178
|
+
if (readOnly()) {
|
|
179
|
+
const carried = (observeText(resolve(root, 'receipts.bound')) ?? '').split('\n').filter(isWire);
|
|
180
|
+
const evidence = carriedFrom(store, carried);
|
|
181
|
+
if (evidence === undefined)
|
|
182
|
+
throw Error('REFUSE·preview native receipt bytes unavailable; fold the declared inputs first');
|
|
183
|
+
return evidence;
|
|
184
|
+
}
|
|
173
185
|
const wait = options.wait ?? true;
|
|
174
186
|
const standing = lockStanding(store);
|
|
175
187
|
const lines = readersOf(store);
|
|
@@ -253,14 +265,15 @@ export function observedClaims(root, store, options = {}) {
|
|
|
253
265
|
}
|
|
254
266
|
function observeOne(reader, started) {
|
|
255
267
|
const module = resolve(root, reader.module);
|
|
256
|
-
const asked = reader.capsule === undefined ? undefined : capsuleAt(reader.capsule.digest, reader.capsule.entry);
|
|
268
|
+
const asked = reader.capsule === undefined ? undefined : reader.capsule.selected ?? capsuleAt(reader.capsule.digest, reader.capsule.entry);
|
|
257
269
|
const source = reader.capsule === undefined ? observeFile(module) : asked === undefined ? undefined : new Uint8Array();
|
|
258
|
-
const bundle = source && reader.capsule === undefined ? bundleOf(module) ??
|
|
270
|
+
const bundle = source && reader.capsule === undefined ? bundleOf(module) ?? bytesDigest(store, source) : 'none';
|
|
259
271
|
const offered = offersOf(root, store, reader, roleOf, look, (where) => reached(trimmed(where)));
|
|
272
|
+
assertReaderInputs(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module, offered.length);
|
|
260
273
|
const vectors = reader.capsule === undefined ? observeText(resolve(root, vectorsOf(reader.module, standing))) : undefined;
|
|
261
274
|
const kept = whole && legacy === undefined && answered === undefined && source ? sha([
|
|
262
275
|
speaker, reader.module, reader.kind, reader.shape.join('|'), reader.where.join('|'), bundle, vectors === undefined ? 'no vectors' : sha(vectors),
|
|
263
|
-
reader.capsule === undefined ? '' : `${reader.capsule.digest} ${reader.capsule.region} ${reader.capsule.reads.join('|')} ${[...reader.capsule.globs].map(([place, globs]) => `${place}${globs.join('|')}`).join(' ')}`,
|
|
276
|
+
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(' ')}`,
|
|
264
277
|
...offered.map((offer) => `${offer.place} ${offer.digest?.() ?? bytesDigest(store, offer.bytes())}`),
|
|
265
278
|
].join('\n')) : undefined;
|
|
266
279
|
const stored = kept === undefined ? undefined : observeText(memoAt(store, `observed/${kept}`));
|
|
@@ -275,8 +288,8 @@ export function observedClaims(root, store, options = {}) {
|
|
|
275
288
|
const own = shardLines(store, speaker, home).filter((line) => fieldOf(line, 'scope') === `reader/${reader.module}`);
|
|
276
289
|
const lineage = own.filter((line) => fieldOf(line, 'measure') === 'identity').map((line) => fieldOf(line, 'value'));
|
|
277
290
|
const sum = source && reader.capsule === undefined ? bytesDigest(store, new TextEncoder().encode(`${reader.module} ${bundle}`)).replace(/^sha256:/, '').slice(0, 12) : 'none';
|
|
278
|
-
const measured = reader.capsule !== undefined ? { by: source ? sha(`${reader.capsule.digest}\n${reader.capsule.region}`).slice(0, 12) : 'none', lines: [] }
|
|
279
|
-
: source ? identityOf({ store, root, speaker, module: reader.module, kind: reader.kind, code: sum, lineage, kept: own.filter((line) => /(?:^|\s)measure=(?:extension|emits)\s/.test(line)) })
|
|
291
|
+
const measured = reader.capsule !== undefined ? { by: source ? sha(`${reader.capsule.selected?.selection ?? reader.capsule.digest}\n${reader.capsule.region}`).slice(0, 12) : 'none', lines: [] }
|
|
292
|
+
: source ? identityOf({ store, root, speaker, module: reader.module, kind: reader.kind, code: sum, lineage, lifetime: readerLifetime(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module), kept: own.filter((line) => /(?:^|\s)measure=(?:extension|emits)\s/.test(line)) })
|
|
280
293
|
: { by: 'none', lines: [] };
|
|
281
294
|
const by = measured.by;
|
|
282
295
|
const level = [...measured.lines];
|
|
@@ -351,8 +364,10 @@ export function observedClaims(root, store, options = {}) {
|
|
|
351
364
|
}
|
|
352
365
|
return [];
|
|
353
366
|
};
|
|
354
|
-
if (due.length && !source)
|
|
367
|
+
if (due.length && !source) {
|
|
368
|
+
refused.push(`REFUSE·reader ${reader.module} unavailable · ${due.length} readings remain due`);
|
|
355
369
|
return false;
|
|
370
|
+
}
|
|
356
371
|
if (due.length && !wait) {
|
|
357
372
|
for (const plan of plans) {
|
|
358
373
|
if (plan.said !== undefined) {
|
|
@@ -394,14 +409,18 @@ export function observedClaims(root, store, options = {}) {
|
|
|
394
409
|
throw new Error(`REFUSE·reader ${reader.module} · ${answer?.why ?? 'no capsule answer'}`);
|
|
395
410
|
return (answer.claims ?? []);
|
|
396
411
|
})
|
|
397
|
-
: runReader(module, root, due.map((d) => ({ place: d.place, ...(reader.kind === 'js' ? { text: new TextDecoder().decode(d.bytes) } : {}), held: heldOf(d.place, d.region) })));
|
|
412
|
+
: runReader(module, root, due.map((d) => ({ place: d.place, ...(reader.kind === 'js' ? { text: new TextDecoder().decode(d.bytes) } : {}), held: heldOf(d.place, d.region) })), readerLifetime(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module));
|
|
398
413
|
}
|
|
399
414
|
catch (error) {
|
|
400
|
-
|
|
415
|
+
const why = `REFUSE·reader ${reader.module} · ${error instanceof Error ? error.message : String(error)}`;
|
|
416
|
+
refused.push(why);
|
|
417
|
+
process.stderr.write(`${why}\n`);
|
|
401
418
|
return false;
|
|
402
419
|
}
|
|
403
|
-
if (rows.every((mine) => !mine.length)) {
|
|
404
|
-
|
|
420
|
+
if (rows.every((mine) => !mine.length) && !readerAllowsEmpty(standing.flatMap(line => { const p = parseLifetime(line); return p.kind === 'fact' ? [p.value.fields] : []; }), reader.module)) {
|
|
421
|
+
const why = `REFUSE·reader ${reader.module} · answered none of ${due.length} places · nothing landed, they stay due`;
|
|
422
|
+
refused.push(why);
|
|
423
|
+
process.stderr.write(`${why}\n`);
|
|
405
424
|
return false;
|
|
406
425
|
}
|
|
407
426
|
ran += due.length;
|