@lapxo/bound 0.1.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.
Files changed (186) hide show
  1. package/CONTRIBUTING.md +44 -0
  2. package/LICENSE +22 -0
  3. package/README.md +97 -0
  4. package/TARGET.bound +361 -0
  5. package/dist/cli/accept.d.ts +23 -0
  6. package/dist/cli/accept.js +423 -0
  7. package/dist/cli/args.d.ts +10 -0
  8. package/dist/cli/args.js +34 -0
  9. package/dist/cli/host.d.ts +1 -0
  10. package/dist/cli/host.js +32 -0
  11. package/dist/cli/names.d.ts +25 -0
  12. package/dist/cli/names.js +12 -0
  13. package/dist/cli/observe.d.ts +1 -0
  14. package/dist/cli/observe.js +6 -0
  15. package/dist/cli/owner.d.ts +35 -0
  16. package/dist/cli/owner.js +119 -0
  17. package/dist/cli/pass.d.ts +6 -0
  18. package/dist/cli/pass.js +309 -0
  19. package/dist/cli/place.d.ts +74 -0
  20. package/dist/cli/place.js +290 -0
  21. package/dist/cli/takes.d.ts +30 -0
  22. package/dist/cli/takes.js +108 -0
  23. package/dist/cli/verb.d.ts +2 -0
  24. package/dist/cli/verb.js +478 -0
  25. package/dist/fold/ceilings.d.ts +24 -0
  26. package/dist/fold/ceilings.js +129 -0
  27. package/dist/fold/claims.d.ts +25 -0
  28. package/dist/fold/claims.js +107 -0
  29. package/dist/fold/closed.d.ts +15 -0
  30. package/dist/fold/closed.js +168 -0
  31. package/dist/fold/configures.d.ts +4 -0
  32. package/dist/fold/configures.js +22 -0
  33. package/dist/fold/digests.d.ts +29 -0
  34. package/dist/fold/digests.js +211 -0
  35. package/dist/fold/evidence.d.ts +32 -0
  36. package/dist/fold/evidence.js +22 -0
  37. package/dist/fold/fold-worker.d.ts +1 -0
  38. package/dist/fold/fold-worker.js +13 -0
  39. package/dist/fold/kept.d.ts +29 -0
  40. package/dist/fold/kept.js +142 -0
  41. package/dist/fold/keys.d.ts +17 -0
  42. package/dist/fold/keys.js +84 -0
  43. package/dist/fold/laid.d.ts +17 -0
  44. package/dist/fold/laid.js +90 -0
  45. package/dist/fold/nos.d.ts +8 -0
  46. package/dist/fold/nos.js +48 -0
  47. package/dist/fold/object.d.ts +17 -0
  48. package/dist/fold/object.js +38 -0
  49. package/dist/fold/observed.d.ts +33 -0
  50. package/dist/fold/observed.js +444 -0
  51. package/dist/fold/opened.d.ts +5 -0
  52. package/dist/fold/opened.js +33 -0
  53. package/dist/fold/own.d.ts +24 -0
  54. package/dist/fold/own.js +215 -0
  55. package/dist/fold/paid.d.ts +11 -0
  56. package/dist/fold/paid.js +92 -0
  57. package/dist/fold/place-inputs.d.ts +17 -0
  58. package/dist/fold/place-inputs.js +70 -0
  59. package/dist/fold/places.d.ts +20 -0
  60. package/dist/fold/places.js +84 -0
  61. package/dist/fold/rank.d.ts +3 -0
  62. package/dist/fold/rank.js +9 -0
  63. package/dist/fold/reach.d.ts +13 -0
  64. package/dist/fold/reach.js +65 -0
  65. package/dist/fold/readers.d.ts +44 -0
  66. package/dist/fold/readers.js +132 -0
  67. package/dist/fold/receipts.d.ts +8 -0
  68. package/dist/fold/receipts.js +47 -0
  69. package/dist/fold/region.d.ts +72 -0
  70. package/dist/fold/region.js +286 -0
  71. package/dist/fold/release-policy.d.ts +67 -0
  72. package/dist/fold/release-policy.js +103 -0
  73. package/dist/fold/resolved.d.ts +18 -0
  74. package/dist/fold/resolved.js +123 -0
  75. package/dist/fold/roles.d.ts +17 -0
  76. package/dist/fold/roles.js +59 -0
  77. package/dist/fold/second.d.ts +18 -0
  78. package/dist/fold/second.js +68 -0
  79. package/dist/fold/shards.d.ts +29 -0
  80. package/dist/fold/shards.js +100 -0
  81. package/dist/fold/signed.d.ts +18 -0
  82. package/dist/fold/signed.js +75 -0
  83. package/dist/fold/signers.d.ts +24 -0
  84. package/dist/fold/signers.js +58 -0
  85. package/dist/fold/stranger.d.ts +3 -0
  86. package/dist/fold/stranger.js +24 -0
  87. package/dist/fold/views.d.ts +27 -0
  88. package/dist/fold/views.js +66 -0
  89. package/dist/fold/wire.d.ts +19 -0
  90. package/dist/fold/wire.js +41 -0
  91. package/dist/fold/zoom.d.ts +16 -0
  92. package/dist/fold/zoom.js +80 -0
  93. package/dist/host/adapters/keys/ed25519.d.ts +7 -0
  94. package/dist/host/adapters/keys/ed25519.js +30 -0
  95. package/dist/host/archive.d.ts +11 -0
  96. package/dist/host/archive.js +152 -0
  97. package/dist/host/capsule-process.d.ts +20 -0
  98. package/dist/host/capsule-process.js +54 -0
  99. package/dist/host/capsule.d.ts +13 -0
  100. package/dist/host/capsule.js +149 -0
  101. package/dist/host/cell-receipts.d.ts +2 -0
  102. package/dist/host/cell-receipts.js +124 -0
  103. package/dist/host/digest.d.ts +3 -0
  104. package/dist/host/digest.js +15 -0
  105. package/dist/host/hash.d.ts +2 -0
  106. package/dist/host/hash.js +3 -0
  107. package/dist/host/io.d.ts +9 -0
  108. package/dist/host/io.js +9 -0
  109. package/dist/host/located.d.ts +4 -0
  110. package/dist/host/located.js +105 -0
  111. package/dist/host/objects.d.ts +5 -0
  112. package/dist/host/objects.js +18 -0
  113. package/dist/host/ports/store.d.ts +2 -0
  114. package/dist/host/ports/store.js +18 -0
  115. package/dist/host/provide.d.ts +23 -0
  116. package/dist/host/provide.js +81 -0
  117. package/dist/host/release.d.ts +12 -0
  118. package/dist/host/release.js +213 -0
  119. package/dist/host/selected-capsules.d.ts +8 -0
  120. package/dist/host/selected-capsules.js +19 -0
  121. package/dist/host/selected-topos.d.ts +17 -0
  122. package/dist/host/selected-topos.js +61 -0
  123. package/dist/host/source-content.d.ts +10 -0
  124. package/dist/host/source-content.js +94 -0
  125. package/dist/host/timing.d.ts +2 -0
  126. package/dist/host/timing.js +7 -0
  127. package/dist/judge/late.d.ts +7 -0
  128. package/dist/judge/late.js +33 -0
  129. package/dist/judge/take.d.ts +57 -0
  130. package/dist/judge/take.js +75 -0
  131. package/dist/judge/widening.d.ts +1 -0
  132. package/dist/judge/widening.js +25 -0
  133. package/dist/land/act.d.ts +4 -0
  134. package/dist/land/act.js +209 -0
  135. package/dist/land/alias.d.ts +10 -0
  136. package/dist/land/alias.js +41 -0
  137. package/dist/land/held.d.ts +7 -0
  138. package/dist/land/held.js +23 -0
  139. package/dist/land/inert.d.ts +26 -0
  140. package/dist/land/inert.js +33 -0
  141. package/dist/land/leaving.d.ts +14 -0
  142. package/dist/land/leaving.js +51 -0
  143. package/dist/land/ledger.d.ts +28 -0
  144. package/dist/land/ledger.js +148 -0
  145. package/dist/land/owned.d.ts +23 -0
  146. package/dist/land/owned.js +65 -0
  147. package/dist/land/sign.d.ts +16 -0
  148. package/dist/land/sign.js +30 -0
  149. package/dist/land/vouched.d.ts +21 -0
  150. package/dist/land/vouched.js +112 -0
  151. package/dist/land/withdraw.d.ts +14 -0
  152. package/dist/land/withdraw.js +24 -0
  153. package/dist/observe/files.d.ts +14 -0
  154. package/dist/observe/files.js +68 -0
  155. package/dist/observe/identity.d.ts +19 -0
  156. package/dist/observe/identity.js +61 -0
  157. package/dist/observe/match.d.ts +1 -0
  158. package/dist/observe/match.js +8 -0
  159. package/dist/observe/regions.d.ts +29 -0
  160. package/dist/observe/regions.js +200 -0
  161. package/dist/observe/run.d.ts +30 -0
  162. package/dist/observe/run.js +34 -0
  163. package/dist/observe/runner.d.ts +16 -0
  164. package/dist/observe/runner.js +83 -0
  165. package/dist/render/capsule.d.ts +24 -0
  166. package/dist/render/capsule.js +30 -0
  167. package/dist/render/field.d.ts +9 -0
  168. package/dist/render/field.js +46 -0
  169. package/dist/render/names.d.ts +3 -0
  170. package/dist/render/names.js +4 -0
  171. package/dist/render/open.d.ts +27 -0
  172. package/dist/render/open.js +61 -0
  173. package/dist/render/page.d.ts +3 -0
  174. package/dist/render/page.js +7 -0
  175. package/dist/render/receipts.d.ts +3 -0
  176. package/dist/render/receipts.js +46 -0
  177. package/dist/render/shape.d.ts +16 -0
  178. package/dist/render/shape.js +74 -0
  179. package/dist/render/target.d.ts +18 -0
  180. package/dist/render/target.js +52 -0
  181. package/dist/render/view.d.ts +22 -0
  182. package/dist/render/view.js +191 -0
  183. package/docs/readme-assets/atlas.svg +169 -0
  184. package/docs/usage.md +53 -0
  185. package/package.json +48 -0
  186. package/receipts.bound +59 -0
@@ -0,0 +1,290 @@
1
+ import { timing } from "../host/timing.js";
2
+ import { attestationObservations } from "../fold/evidence.js";
3
+ import { parse as parseEvidenceFields } from '@lapxo/topos/wire';
4
+ import { releasePolicy, releaseFaults } from "../fold/release-policy.js";
5
+ import { point, region, within } from '@lapxo/obligations/field';
6
+ import { basename, join } from 'node:path';
7
+ import { observeText } from "../observe/files.js";
8
+ import { placesOf, viewsOf } from "../fold/views.js";
9
+ import { prerender, viewOf } from "../render/view.js";
10
+ import { meets } from "../fold/closed.js";
11
+ import { foldPoints, keepFold, keptPlace } from "../fold/kept.js";
12
+ import { openCells } from "../render/open.js";
13
+ import { boundOf, packRegions, regionsNamed, regionsOf, unlikeReplay } from "../fold/region.js";
14
+ import { answersElsewhere, foldCeilings } from "../fold/ceilings.js";
15
+ import { keyOf, keyFor, lockLines, lockStanding } from "../fold/keys.js";
16
+ import { wordFrom, wordOf, wordOn } from "../fold/wire.js";
17
+ import { bytesDigest, instrumentOf, signaturesOf } from "../fold/digests.js";
18
+ import { claimKey, fieldOf, fieldsOf, isWire } from "../fold/claims.js";
19
+ import { canonical, LOCK, parse } from '@lapxo/topos/wire';
20
+ import { classDefaults, kindsOf, placesIn, spoken } from "../fold/places.js";
21
+ import { isCeiling } from "../fold/configures.js";
22
+ import { observedClaims, placedReadings } from "../fold/observed.js";
23
+ import { capsuleReadingsOver } from "../observe/regions.js";
24
+ import { costReadings, ownReadings } from "../fold/own.js";
25
+ import { paidOf } from "../fold/paid.js";
26
+ import { rolesOf } from "../fold/roles.js";
27
+ import { secondHead } from "../fold/second.js";
28
+ import { authorityFor, rootSigner, writerFor } from "../fold/signers.js";
29
+ import { ledgerLines, storeOf } from "../land/ledger.js";
30
+ import { vouchedCoordinates } from "../land/vouched.js";
31
+ import { ownLock, ownRoot } from "../observe/runner.js";
32
+ import { epochOf, historyOf, renderedLock, standingDemands } from "./owner.js";
33
+ function beatsOf(store, standing, under) {
34
+ const folder = writerFor(standing, 'fold');
35
+ const middle = (at) => {
36
+ const ms = (folder === undefined ? [] : ledgerLines(store, folder))
37
+ .filter((line) => fieldOf(line, 'scope') === `beat/${under ?? '.'}` && fieldOf(line, 'at') === `place:${at}`)
38
+ .map((line) => Number(fieldOf(line, 'value').split('..')[0])).filter((one) => Number.isFinite(one)).slice(-10).sort((a, b) => a - b);
39
+ return ms.length ? ms[Math.floor(ms.length / 2)] ?? 0 : 0;
40
+ };
41
+ return { kept: middle('kept'), folded: middle('folded') };
42
+ }
43
+ const costsOf = (store) => ledgerLines(store, 'take').filter((line) => fieldOf(line, 'measure') === 'ms')
44
+ .map((line) => Number(fieldOf(line, 'value').split('..')[0])).filter((ms) => Number.isFinite(ms)).slice(-10);
45
+ function effectStates(_store) {
46
+ return 'none';
47
+ }
48
+ function listed(misses) {
49
+ const by = new Map();
50
+ for (const o of misses)
51
+ by.set(o.ceiling, [...(by.get(o.ceiling) ?? []), o.question === o.ceiling ? o.got : `${o.question}=${o.got}`]);
52
+ return [...by].map(([scope, got]) => `${scope} · ${got.length > 4 ? `${got.slice(0, 4).join(' ')} +${got.length - 4}` : got.join(' ')}`);
53
+ }
54
+ /**
55
+ * The fold of a place: the standing lock and what readers saw, narrowed to the place when one is named. A demand is the
56
+ * place's when every place it asks about lies there; a SHORT on a question also read outside it is not the place's to
57
+ * answer. The count of a place's own readings is the instrument's, taken inside the place alone. What each key has
58
+ * signed that stands is counted apart: the owner's lines stand in this fold, a second head's in its own ledger, and its
59
+ * word on a lock is asked once for the lines a batch and the ledger own together.
60
+ */
61
+ const counted = new WeakMap();
62
+ const seconds = new WeakMap();
63
+ function secondOf(root, store, attested, owned) {
64
+ const held = seconds.get(owned);
65
+ if (held !== undefined)
66
+ return held;
67
+ const head = keyOf(store, 'attest');
68
+ const heard = head === undefined ? undefined : authorityFor([...owned, ...ledgerLines(store, head)], rootSigner(root), signaturesOf(store).admitted);
69
+ return seconds.set(owned, secondHead(store, attested, (line) => heard?.of(line).kind === 'admitted', owned)).get(owned);
70
+ }
71
+ function signedByKey(store, standing, observed) {
72
+ const signed = new Map();
73
+ const reader = (() => {
74
+ try {
75
+ return keyFor(store, 'read');
76
+ }
77
+ catch {
78
+ return undefined;
79
+ }
80
+ })();
81
+ for (const line of standing)
82
+ signed.set(fieldOf(line, 'by'), (signed.get(fieldOf(line, 'by')) ?? 0) + 1);
83
+ for (const line of standing) {
84
+ const key = /^keys\/([^/]+)$/.exec(fieldOf(line, 'scope'))?.[1];
85
+ const lines = key === undefined || signed.has(key) ? undefined : key === reader ? observed : ledgerLines(store, key);
86
+ if (key !== undefined && lines !== undefined)
87
+ signed.set(key, counted.get(lines) ?? counted.set(lines, new Set(lines.filter(line => fieldOf(line, 'sig') !== '')).size).get(lines));
88
+ }
89
+ return signed;
90
+ }
91
+ /** Generic view checks: declared output equality and one writer per coordinate. Domain measurements belong to selected providers. */
92
+ function viewReadings(place) {
93
+ const leaf = wordOn(place.standing, 'region-leaf', ownLock());
94
+ const at = (coordinate) => join(place.root, place.under ?? '', coordinate);
95
+ const every = [...viewsOf(place.standing).values()].flatMap((view) => ('regions' in view && view.shape ? [view] : []))
96
+ .filter((view) => observeText(at(view.shape)) !== undefined);
97
+ const named = (view) => placesOf(place.standing, view).includes(place.under ?? '');
98
+ const shaped = every.filter((view) => named(view) || (!placesOf(place.standing, view).length && !every.some((other) => other.shape === view.shape && named(other))));
99
+ prerender(place, shaped);
100
+ const same = new Set(shaped.filter((view) => observeText(at(view.shape)) === viewOf(place, view)).map((view) => view.name));
101
+ const differ = shaped.length - same.size;
102
+ const twice = [...every.filter((view) => named(view) || !placesOf(place.standing, view).length)
103
+ .reduce((by, view) => by.set(view.shape, (by.get(view.shape) ?? 0) + 1), new Map()).values()].filter((n) => n > 1).length;
104
+ return { readings: { [`rendered-${leaf}-differ`]: differ, 'rendered-coordinates-differ': differ, [`${leaf}-with-two-views`]: twice, 'coordinates-with-two-views': twice }, same, here: new Set(shaped.map(view => view.name)) };
105
+ }
106
+ const NONE = [];
107
+ const ownings = new WeakMap();
108
+ const ownedOf = (store, told) => ((lock) => ((byLock) => byLock.get(told) ?? byLock.set(told, [...lock, ...told]).get(told))(ownings.get(lock) ?? ownings.set(lock, new WeakMap()).get(lock)))(lockLines(store));
109
+ export function standingOf(root, under, told = NONE) {
110
+ const store = storeOf(root);
111
+ const owned = ownedOf(store, told);
112
+ const rendered = renderedLock(root, store, told);
113
+ const lock = rendered.text.split('\n').filter(isWire);
114
+ const said = spoken(root);
115
+ if (!said.length)
116
+ return { standing: lock, lock, rendered, owned };
117
+ const views = `${wordOf(lock, 'families', 'view')}/`;
118
+ const isView = (line) => fieldOf(line, 'scope').startsWith(views);
119
+ const ruled = new Set(said.filter((one) => !isView(one.line)).map((one) => claimKey(one.line)));
120
+ const owners = new Map();
121
+ for (const one of said.filter((o) => isView(o.line)))
122
+ owners.set(fieldOf(one.line, 'scope'), (owners.get(fieldOf(one.line, 'scope')) ?? new Set()).add(`${one.place}/`));
123
+ const tree = lock.flatMap((line) => {
124
+ const by = isView(line) ? owners.get(fieldOf(line, 'scope')) : undefined;
125
+ if (by === undefined)
126
+ return ruled.has(claimKey(line)) ? [] : [line];
127
+ const needs = fieldOf(line, 'needs').split('|').filter(Boolean);
128
+ const left = needs.filter((need) => ![...by].some((place) => need.startsWith(place)));
129
+ if (!needs.length || left.length === needs.length)
130
+ return [line];
131
+ const got = parse(line);
132
+ return left.length && got.kind === 'fact' ? [canonical({ ...got.value.fields, needs: left.join('|') })] : [];
133
+ });
134
+ const here = under?.replace(/\/$/, '');
135
+ const first = said.filter((one) => one.place === here).map((one) => one.line);
136
+ const rest = said.filter((one) => one.place !== here).map((one) => one.line);
137
+ const standing = [...new Set([...first, ...tree, ...rest])];
138
+ return { standing: [...standing, ...inheritedOf(root, standing)], lock, rendered, owned };
139
+ }
140
+ function inheritedOf(root, standing) {
141
+ const defaults = classDefaults(root);
142
+ if (!defaults.length)
143
+ return [];
144
+ const held = standing.filter(isCeiling);
145
+ const extra = [];
146
+ for (const place of placesIn(root)) {
147
+ const kinds = kindsOf(root, place);
148
+ const prefix = `${place}/`;
149
+ const measures = new Set(held.filter((line) => fieldOf(line, 'scope').startsWith(prefix)).map((line) => fieldOf(line, 'measure')));
150
+ for (const def of defaults) {
151
+ if (!def.classes.includes('*') && !def.classes.some((kind) => kinds.includes(kind)))
152
+ continue;
153
+ const measure = fieldOf(def.line, 'measure');
154
+ if (measures.has(measure))
155
+ continue;
156
+ const got = parse(def.line);
157
+ if (got.kind !== 'fact')
158
+ continue;
159
+ extra.push(canonical({ ...got.value.fields, scope: `${prefix}${fieldOf(def.line, 'scope')}` }));
160
+ measures.add(measure);
161
+ }
162
+ }
163
+ return extra;
164
+ }
165
+ export function coneOf(root, entry, ceilings, descent) {
166
+ const store = storeOf(root);
167
+ const { standing, rendered } = standingOf(root);
168
+ const named = regionsNamed(standing);
169
+ const reach = descent !== undefined && descent.length ? [...descent] : [...new Set(ceilings.map((line) => boundOf(named, line).region))];
170
+ const read = observedClaims(root, store, { wait: false, ...(reach.includes('') ? {} : { reach }) });
171
+ const observed = [...read, ...capsuleReadingsOver({ root, store, standing, observed: read })];
172
+ const own = {
173
+ ...ownReadings({ root, store, entry, roleOf: rolesOf(store), standing, observed, unadmitted: rendered.grey.length + rendered.refused.length, orphans: 0 }),
174
+ ...costReadings(store, standing),
175
+ };
176
+ const measured = new Set([...Object.keys(own), ...placedReadings(observed).map((reading) => reading.measure), wordOf(standing, 'states', 'unread')]);
177
+ const reached = ceilings.every((line) => measured.has(fieldOf(line, 'measure')) || fieldOf(line, 'scope') in own);
178
+ if (reached)
179
+ return { standing, observed, own, kept: true };
180
+ const whole = foldPlace(root, entry);
181
+ return { ...whole, kept: whole.kept ?? false };
182
+ }
183
+ export const ownCeilings = (under) => ((home) => (under === undefined || under === `${home}/`
184
+ ? ownLock().filter(isCeiling).map((line) => canonical({ ...fieldsOf(line), scope: `${home}/${fieldOf(line, 'scope')}` })) : []))(basename(ownRoot()));
185
+ export function foldPlace(root, entry, under, look = true, given) {
186
+ const store = storeOf(root);
187
+ const digestAt = Date.now();
188
+ const closed = meets(root, store, under ?? '');
189
+ const digestMs = Date.now() - digestAt;
190
+ if (closed && given?.free !== true) {
191
+ const prior = keptPlace(store, under);
192
+ if (prior !== undefined) {
193
+ process.stderr.write(`CLOSED ${under || '.'} · digest ${digestMs} ms\n`);
194
+ return { ...prior, kept: true };
195
+ }
196
+ }
197
+ const { standing, lock: attested, rendered, owned } = given?.standing ?? standingOf(root, under);
198
+ const folder = writerFor(standing, 'fold');
199
+ const answered = given === undefined && under ? new Map() : undefined;
200
+ const reached = given?.observed ?? observedClaims(root, store, { wait: look, ...(under ? { reach: [under], answered } : {}) });
201
+ const self = instrumentOf(store, entry, standing, root, ownLock());
202
+ const inside = (place) => !under || within(point(place.replace(/\/\*$/, '')), region(under));
203
+ const history = historyOf(root, store, standingDemands(store));
204
+ const theirs = history.live.filter((line) => ((needs) => !under || (needs.length > 0 && needs.every(inside)))(fieldOf(line, 'needs').split('|').filter(Boolean)));
205
+ const reads = under && under !== `${basename(ownRoot())}/` ? { owned, place: under, scopes: new Set(theirs.map((line) => fieldOf(line, 'scope'))) } : undefined;
206
+ const spent = [];
207
+ const took = timing(spent);
208
+ const read = given?.observed ?? (under ? took('observe', () => observedClaims(root, store, { wait: look })) : reached);
209
+ const everywhere = [...read, ...took('capsules', () => capsuleReadingsOver({ root, store, ...(under ? { under } : {}), standing, observed: read }))];
210
+ const points = foldPoints(store, standing, under, folder, self, reached, root, answered, reads);
211
+ const taken = bytesDigest(store, new TextEncoder().encode(points.join('\n'))).replace(/^sha256:/, '');
212
+ const observed = everywhere.filter((line) => !/ measure=observed /.test(line) || inside(fieldOf(line, 'scope')));
213
+ const shared = new Set(under ? placedReadings(everywhere).filter((r) => !inside(r.place)).map((r) => r.question) : []);
214
+ const live = history;
215
+ const demands = theirs;
216
+ const orphans = [];
217
+ const ceilings = [...standing.filter((line) => isCeiling(line) && !(under && fieldOf(line, 'measure') === 'unread')), ...ownCeilings(under)];
218
+ const own = took('own', () => ownReadings({
219
+ root, store, entry, roleOf: rolesOf(store), standing, observed: everywhere,
220
+ unadmitted: rendered.grey.length + rendered.refused.length, orphans: orphans.length, ...(under ? { under } : {}),
221
+ }));
222
+ const regions = took('regions', () => regionsOf(standing, ceilings.filter((line) => !answersElsewhere(line, own, under, new Set(placesIn(root)))), placedReadings(observed)));
223
+ const fold = (docs) => foldCeilings({ standing, ceilings, observed, own: { ...own, ...docs }, epoch: epochOf(owned), ...(under ? { under, places: new Set(placesIn(root)) } : {}) });
224
+ const folded = took('ceilings', () => fold({}));
225
+ const { paid, missing } = took('paid', () => paidOf(store, demands, observed, `${wordFrom(standing, 'families', 'view', lockStanding(store))}/`));
226
+ const lock = (observeText(join(root, under ?? '', LOCK)) ?? '').split('\n').filter(isWire).length;
227
+ const second = secondOf(root, store, attested, owned);
228
+ const policyStanding = standing.filter((line) => !rendered.grey.includes(line) && !rendered.refused.includes(line));
229
+ const faults = releaseFaults({ forks: rendered.forks, refused: rendered.refused, grey: rendered.grey, orphans, second });
230
+ const place = {
231
+ release: releasePolicy({ standing: policyStanding, demands, paid, ceilings, readings: folded, faults, verdicts: attestationObservations(policyStanding.map(line => { const r = parseEvidenceFields(line); return r.kind === 'fact' ? r.value.fields : {}; }), second), snapshot: { fold: taken, instrument: self } }),
232
+ root, store, ...(under ? { under } : {}), epoch: epochOf(owned), standing, claims: rendered.standing,
233
+ forks: rendered.forks, grey: rendered.grey, refused: rendered.refused, vacuous: rendered.vacuous.length,
234
+ demands, paid, missing,
235
+ history: live.history.filter((line) => fieldOf(line, 'needs').split('|').filter(Boolean).some(inside)),
236
+ observed,
237
+ ceilings: {
238
+ read: folded.read.length,
239
+ total: ceilings.length,
240
+ unread: folded.unread.map((line) => fieldOf(line, 'scope')),
241
+ vacuous: folded.vacuous.map((line) => fieldOf(line, 'scope')),
242
+ short: listed(folded.over.filter((o) => o.side === 'short' && !shared.has(o.question))),
243
+ over: listed(folded.over.filter((o) => o.side === 'over')),
244
+ },
245
+ orphans,
246
+ lock,
247
+ signed: signedByKey(store, standing, everywhere),
248
+ second,
249
+ effects: effectStates(store),
250
+ key: taken,
251
+ instrument: self,
252
+ own,
253
+ open: openCells({ store, standing, observed, grey: rendered.grey, epoch: epochOf(owned) }),
254
+ regions: packRegions(regions),
255
+ beats: beatsOf(store, standing, under),
256
+ landed: [...vouchedCoordinates(store).keys()].filter((coordinate) => !under || coordinate.startsWith(under)).length,
257
+ costs: costsOf(store),
258
+ };
259
+ const { readings: found, same, here } = took('docs', () => viewReadings(place));
260
+ const family = `${wordFrom(standing, 'families', 'view', lockStanding(store))}/`;
261
+ const coordinates = new Set([...here].map((name) => `${family}${name}`));
262
+ const writes = (line) => coordinates.has(fieldOf(line, 'scope'));
263
+ const holds = (line) => same.has(fieldOf(line, 'scope').slice(family.length));
264
+ const owed = [...place.missing.filter((line) => !writes(line) || !holds(line)), ...place.paid.filter((line) => writes(line) && !holds(line))];
265
+ const docs = {
266
+ ...found, 'payments-lost-on-equal-output': owed.filter((line) => writes(line) && holds(line)).length,
267
+ 'poles-unlike-replay': unlikeReplay(regions, new Set(folded.over.map((one) => one.ceiling)), { ...own, unread: folded.unread.length + folded.vacuous.length }),
268
+ };
269
+ const again = took('ceilings', () => fold(docs));
270
+ const finalPaid = [...place.paid.filter((line) => !writes(line) || holds(line)), ...place.missing.filter((line) => writes(line) && holds(line))];
271
+ const whole = {
272
+ ...place,
273
+ paid: finalPaid,
274
+ release: releasePolicy({ standing: policyStanding, demands, paid: finalPaid, ceilings, readings: again, faults, verdicts: attestationObservations(policyStanding.map(line => { const r = parseEvidenceFields(line); return r.kind === 'fact' ? r.value.fields : {}; }), second), snapshot: { fold: taken, instrument: self } }),
275
+ missing: owed,
276
+ own: { ...place.own, ...docs },
277
+ ceilings: {
278
+ ...place.ceilings,
279
+ read: again.read.length,
280
+ unread: again.unread.map((line) => fieldOf(line, 'scope')),
281
+ vacuous: again.vacuous.map((line) => fieldOf(line, 'scope')),
282
+ short: listed(again.over.filter((o) => o.side === 'short' && !shared.has(o.question))),
283
+ over: listed(again.over.filter((o) => o.side === 'over')),
284
+ },
285
+ };
286
+ if (folder !== undefined && closed)
287
+ took('keep', () => keepFold(store, taken, whole, points, self));
288
+ process.stderr.write(`SPENT fold ${spent.join(' ms · ')} ms\n`);
289
+ return whole;
290
+ }
@@ -0,0 +1,30 @@
1
+ import { judgeTake } from '../judge/take.ts';
2
+ import type { Gate } from '../judge/take.ts';
3
+ export type Judged = {
4
+ readonly kind: 'refused';
5
+ readonly scope: string;
6
+ readonly why: string;
7
+ } | {
8
+ readonly kind: 'owed';
9
+ readonly scope: string;
10
+ readonly why: string;
11
+ } | {
12
+ readonly kind: 'conditioned';
13
+ readonly scope: string;
14
+ readonly demand: string;
15
+ readonly receipt: string;
16
+ readonly condition: string;
17
+ } | {
18
+ readonly kind: 'judged';
19
+ readonly scope: string;
20
+ readonly demand: string;
21
+ readonly locations: readonly string[];
22
+ readonly before: ReadonlyMap<string, string>;
23
+ readonly after: ReadonlyMap<string, string>;
24
+ readonly verdict: ReturnType<typeof judgeTake>;
25
+ readonly ignored: ReadonlyMap<string, number>;
26
+ readonly started: number;
27
+ };
28
+ export declare function judgeDemand(root: string, demand: string): Judged;
29
+ /** A take its batch let land: its receipt sealed with the gates the batch passed, its cone vouched, its fact landed. */
30
+ export declare function landTake(root: string, one: Judged, gates: readonly Gate[]): void;
@@ -0,0 +1,108 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { fullDigest } from "../fold/digests.js";
4
+ import { canonical } from '@lapxo/topos/wire';
5
+ import { fieldOf, foldClaims } from "../fold/claims.js";
6
+ import { rolesOf } from "../fold/roles.js";
7
+ import { writerFor } from "../fold/signers.js";
8
+ import { judgeTake, sealed } from "../judge/take.js";
9
+ import { land, landEnvelope, ledgerLines, storeOf } from "../land/ledger.js";
10
+ import { wordOf } from "../fold/wire.js";
11
+ import { hasVouchedTree, inside, landCoordinates, coordinatesOf, locationsOf, vouchedCoordinates, witnessOf } from "../land/vouched.js";
12
+ import { ownerOf, forkedScopes, signedOwnerLines } from "./owner.js";
13
+ export function judgeDemand(root, demand) {
14
+ const started = Date.now();
15
+ const store = storeOf(root);
16
+ const scope = fieldOf(demand, 'scope');
17
+ const refuse = (why) => ({ kind: 'refused', scope, why });
18
+ if (!hasVouchedTree(store))
19
+ return refuse('no source is vouched; land the lock once');
20
+ if (forkedScopes(store).has(scope))
21
+ return refuse('it stands as a fork; the owner narrows or withdraws one line first');
22
+ const condition = fieldOf(demand, 'condition');
23
+ if (condition) {
24
+ const paid = ledgerLines(store, 'judge').filter((line) => fieldOf(line, 'scope') === condition && fieldOf(line, 'value') === 'present').pop();
25
+ if (!paid)
26
+ return { kind: 'owed', scope, why: `it rests on ${condition}, which has no FACT: it stands owed until that is paid` };
27
+ const absent = locationsOf(fieldOf(demand, 'needs')).locations.filter((l) => !existsSync(join(root, l.replace(/\/$/, ''))));
28
+ if (absent.length)
29
+ return refuse(`demanded locations absent: ${absent.join(', ')}`);
30
+ return { kind: 'conditioned', scope, demand, receipt: fieldOf(paid, 'at'), condition };
31
+ }
32
+ const { locations, refused } = locationsOf(fieldOf(demand, 'needs'));
33
+ if (refused.length)
34
+ return refuse(`needs that are not locations: ${refused.join(', ')}`);
35
+ const roleOf = rolesOf(store);
36
+ const ignored = new Map();
37
+ const walked = (coordinate) => {
38
+ const role = roleOf(coordinate);
39
+ if (role !== 'source')
40
+ ignored.set(role, (ignored.get(role) ?? 0) + 1);
41
+ return role;
42
+ };
43
+ const before = new Map([...vouchedCoordinates(store)].filter(([coordinate]) => locations.some((l) => inside(coordinate, l)) && roleOf(coordinate) === 'source'));
44
+ const after = new Map();
45
+ for (const location of locations)
46
+ for (const [coordinate, digest] of coordinatesOf(root, location, walked))
47
+ after.set(coordinate, digest);
48
+ const law = [scope.split('/').pop() ?? scope, fieldOf(demand, 'at').replace(/^witness:/, '')].filter(Boolean);
49
+ const verdict = judgeTake({
50
+ root, scope, value: fieldOf(demand, 'value'), locations, before, after, law,
51
+ shape: fieldOf(demand, 'shape'), restsOn: fieldOf(demand, 'restsOn'), witnessOf: (coordinate) => witnessOf(root, coordinate),
52
+ template: wordOf(foldClaims(signedOwnerLines(store)).standing, 'templates', '{roots}'),
53
+ });
54
+ return { kind: 'judged', scope, demand, locations, before, after, verdict, ignored, started };
55
+ }
56
+ /** A take its batch let land: its receipt sealed with the gates the batch passed, its cone vouched, its fact landed. */
57
+ export function landTake(root, one, gates) {
58
+ const store = storeOf(root);
59
+ if (one.kind === 'refused')
60
+ return;
61
+ if (one.kind === 'owed') {
62
+ process.stdout.write(`OWED take ${one.scope} · ${one.why}\n`);
63
+ return;
64
+ }
65
+ if (one.kind === 'conditioned') {
66
+ const { scope, demand, receipt, condition } = one;
67
+ land(store, 'judge', [canonical({
68
+ scope, role: 'writes', form: 'alphabet', measure: fieldOf(demand, 'measure') || 'status', value: fieldOf(demand, 'value') || 'present', by: 'judge', at: receipt, condition,
69
+ })]);
70
+ land(store, 'take', [canonical({ scope: `take/${scope}`, role: 'writes', form: 'alphabet', measure: 'status', value: 'fact', by: 'judge', at: receipt })]);
71
+ process.stdout.write(`FACT take ${scope} · paid by ${receipt} · condition ${condition} · no moved set\n`);
72
+ return;
73
+ }
74
+ const { scope, demand, before, after, ignored, started } = one;
75
+ const verdict = sealed(root, one.verdict, gates);
76
+ const who = writerFor(signedOwnerLines(store), 'fold') ?? ownerOf(store);
77
+ const cone = fullDigest(store, [...before].map(([path, digest]) => `${path} ${digest}`));
78
+ land(store, 'take', [canonical({ scope: `take/${scope}`, role: 'writes', form: 'alphabet', measure: 'status', value: 'open', by: who, at: `place:${cone}` })]);
79
+ landEnvelope(store, verdict.digest, `${JSON.stringify(verdict.envelope, null, 1)}\n`);
80
+ const receipt = `receipt:${verdict.digest}`;
81
+ const generation = fullDigest(store, [...after].sort().map(([coordinate, digest]) => `${coordinate} ${digest}`));
82
+ land(store, 'judge', verdict.envelope.effects.map((effect) => canonical({
83
+ scope: `${effect.kind}/${generation}`, role: 'writes', form: 'alphabet', measure: 'status', value: effect.status, by: 'judge', at: receipt,
84
+ })));
85
+ if (verdict.kind === 'fact') {
86
+ const present = new Map(verdict.changed.filter((path) => after.has(path)).map((path) => [path, after.get(path) ?? '']));
87
+ const gone = verdict.changed.filter((path) => !after.has(path));
88
+ landCoordinates(store, present, gone, receipt);
89
+ land(store, 'judge', [
90
+ canonical({
91
+ scope, role: 'writes', form: 'alphabet', measure: fieldOf(demand, 'measure') || 'status', value: fieldOf(demand, 'value') || 'present', by: 'judge', at: receipt,
92
+ }),
93
+ canonical({ scope, role: 'writes', form: 'alphabet', measure: 'cone', value: verdict.changed.join('|'), by: 'judge', at: receipt }),
94
+ ]);
95
+ }
96
+ const ms = Date.now() - started;
97
+ land(store, 'take', [
98
+ canonical({ scope: `take/${scope}`, role: 'writes', form: 'alphabet', measure: 'status', value: verdict.kind, by: 'judge', at: receipt }),
99
+ canonical({ scope: `take/${scope}`, role: 'writes', form: 'interval', measure: 'ms', value: `${ms}..${ms}`, by: 'judge', at: receipt }),
100
+ ]);
101
+ const effects = verdict.envelope.effects.map((e) => `${e.kind}@${e.at || '.'}:${e.admitted ? e.status : `${e.status}·grey`}(${e.ms} ms)`).join(' ') || 'none';
102
+ process.stdout.write(`${verdict.kind === 'fact' ? 'FACT ' : 'REFUSE'} take ${scope} · ${verdict.why}\n`
103
+ + `MOVED ${verdict.changed.length} sources: ${verdict.changed.join(' ')}\n`
104
+ + `IGNORED ${[...ignored].map(([role, n]) => `${n} ${role}`).join(' · ') || 'none'} (not walked, never landed)\n`
105
+ + `${verdict.notOwned.length ? `NOT OWN ${verdict.notOwned.length} witnesses of other laws, left for them: ${verdict.notOwned.join(' ')}\n` : ''}`
106
+ + `EFFECTS ${effects}\n`
107
+ + `RECEIPT ${verdict.digest} · ${ms} ms\n`);
108
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};