@lapxo/bound 0.2.0 → 0.2.2

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 (235) hide show
  1. package/README.md +40 -121
  2. package/TARGET.bound +65 -32
  3. package/dist/cli/owner.js +2 -1
  4. package/dist/cli/place.js +7 -26
  5. package/dist/cli/retained-judgment.js +25 -0
  6. package/dist/cli/standing-result.js +4 -3
  7. package/dist/cli/verb.js +36 -3
  8. package/dist/engine/encoding.js +2 -0
  9. package/dist/engine/index.d.ts +2 -0
  10. package/dist/engine/index.js +2 -0
  11. package/dist/engine/ports.d.ts +32 -0
  12. package/dist/engine/ports.js +103 -0
  13. package/dist/fold/admission-history.js +6 -11
  14. package/dist/fold/bootstrap-anchor.js +28 -0
  15. package/dist/fold/ceilings.js +13 -0
  16. package/dist/fold/own.js +7 -5
  17. package/dist/fold/signers.js +5 -9
  18. package/dist/host/admitted-place.js +6 -0
  19. package/dist/host/contextual-place.js +2 -2
  20. package/dist/host/io.js +2 -2
  21. package/dist/host/native/module-syntax.js +8 -4
  22. package/dist/host/reference-authenticated.d.ts +12 -0
  23. package/dist/host/reference-authenticated.js +47 -31
  24. package/dist/host/reference-contracts.js +6 -0
  25. package/dist/host/reference-export.d.ts +33 -0
  26. package/dist/host/reference-export.js +81 -0
  27. package/dist/host/reference-native-api.d.ts +3 -0
  28. package/dist/host/reference-native-api.js +3 -0
  29. package/dist/host/reference-native.d.ts +21 -1
  30. package/dist/host/reference-native.js +34 -10
  31. package/dist/host/reference-profile.js +2 -1
  32. package/dist/host/reference-standing.js +18 -0
  33. package/dist/host/refusals.d.ts +14 -0
  34. package/dist/host/refusals.js +43 -0
  35. package/dist/host/signing.js +7 -1
  36. package/dist/observe/files.js +11 -1
  37. package/dist/wasm/object.js +2 -2
  38. package/docs/contracts/authenticated-reference.publication.json +2 -2
  39. package/docs/contracts/host-ports.md +23 -0
  40. package/docs/contracts/host-ports.publication.json +25 -0
  41. package/docs/contracts/native-publication.inventory.json +7 -1
  42. package/docs/contracts/optional-wasm-adapter.publication.json +1 -1
  43. package/docs/contracts/readme.publication.json +25 -0
  44. package/docs/contracts/reference-backend.md +24 -0
  45. package/docs/contracts/reference-backend.publication.json +25 -0
  46. package/docs/contracts/reference-export.md +31 -0
  47. package/docs/contracts/reference-export.publication.json +25 -0
  48. package/docs/contracts/reference-port.md +8 -1
  49. package/docs/contracts/reference-port.publication.json +1 -1
  50. package/docs/contracts/refusals.bound +94 -0
  51. package/docs/contracts/refusals.md +47 -0
  52. package/docs/contracts/refusals.publication.json +25 -0
  53. package/docs/contracts/standing.bound +9 -0
  54. package/docs/contracts/standing.md +24 -0
  55. package/docs/contracts/standing.publication.json +25 -0
  56. package/package.json +52 -6
  57. package/receipts.bound +9703 -7690
  58. package/samples/authenticated-reference/compatibility.json +306 -0
  59. package/samples/authenticated-reference/yes.json +2 -2
  60. package/samples/engine-place/inputs/closure.json +1 -0
  61. package/samples/host-ports/no.json +16 -0
  62. package/samples/host-ports/yes.json +9 -0
  63. package/samples/readme/no.json +1 -0
  64. package/samples/readme/yes.json +1 -0
  65. package/samples/reference-backend/no.json +1 -0
  66. package/samples/reference-backend/world-fixture.json +8 -0
  67. package/samples/reference-backend/yes.json +1 -0
  68. package/samples/reference-export/no.json +5 -0
  69. package/samples/reference-export/yes.json +15 -0
  70. package/samples/reference-port/no/catalog/TARGET.bound +33 -0
  71. package/samples/reference-port/no/route-notes/TARGET.bound +33 -0
  72. package/samples/refusals/no.json +4 -0
  73. package/samples/refusals/yes.json +9 -0
  74. package/samples/standing/no.json +4 -0
  75. package/samples/standing/yes.json +21 -0
  76. package/vectors/native/authenticated-reference-formation.vector.json +55 -1
  77. package/vectors/native/authenticated-reference.vector.json +32 -396
  78. package/vectors/native/host-ports.vector.json +107 -0
  79. package/vectors/native/readme.vector.json +76 -0
  80. package/vectors/native/reference-backend.vector.json +84 -0
  81. package/vectors/native/reference-export.vector.json +78 -0
  82. package/vectors/native/refusals.vector.json +95 -0
  83. package/vectors/native/standing.vector.json +116 -0
  84. package/vectors/wasm-object.cli.json +16 -61
  85. package/dist/cli/accept.d.ts +0 -28
  86. package/dist/cli/act-result.d.ts +0 -12
  87. package/dist/cli/args.d.ts +0 -11
  88. package/dist/cli/custodian.d.ts +0 -1
  89. package/dist/cli/host.d.ts +0 -1
  90. package/dist/cli/names.d.ts +0 -25
  91. package/dist/cli/native-descendant.d.ts +0 -1
  92. package/dist/cli/native.d.ts +0 -1
  93. package/dist/cli/observe.d.ts +0 -1
  94. package/dist/cli/owner.d.ts +0 -37
  95. package/dist/cli/pass.d.ts +0 -6
  96. package/dist/cli/place.d.ts +0 -76
  97. package/dist/cli/release-result.d.ts +0 -5
  98. package/dist/cli/standing-result.d.ts +0 -5
  99. package/dist/cli/takes.d.ts +0 -30
  100. package/dist/fold/admission-history.d.ts +0 -6
  101. package/dist/fold/ceilings.d.ts +0 -24
  102. package/dist/fold/claims.d.ts +0 -29
  103. package/dist/fold/closed.d.ts +0 -15
  104. package/dist/fold/configures.d.ts +0 -4
  105. package/dist/fold/digests.d.ts +0 -29
  106. package/dist/fold/evidence.d.ts +0 -32
  107. package/dist/fold/fold-worker.d.ts +0 -1
  108. package/dist/fold/kept.d.ts +0 -29
  109. package/dist/fold/keys.d.ts +0 -17
  110. package/dist/fold/laid.d.ts +0 -17
  111. package/dist/fold/nos.d.ts +0 -8
  112. package/dist/fold/object.d.ts +0 -3
  113. package/dist/fold/observed.d.ts +0 -35
  114. package/dist/fold/opened.d.ts +0 -5
  115. package/dist/fold/own.d.ts +0 -24
  116. package/dist/fold/paid.d.ts +0 -11
  117. package/dist/fold/place-inputs.d.ts +0 -17
  118. package/dist/fold/places.d.ts +0 -24
  119. package/dist/fold/rank.d.ts +0 -3
  120. package/dist/fold/reach.d.ts +0 -18
  121. package/dist/fold/readers.d.ts +0 -47
  122. package/dist/fold/receipts.d.ts +0 -8
  123. package/dist/fold/region-declarations.d.ts +0 -2
  124. package/dist/fold/region.d.ts +0 -72
  125. package/dist/fold/release-policy.d.ts +0 -67
  126. package/dist/fold/resolved.d.ts +0 -18
  127. package/dist/fold/roles.d.ts +0 -17
  128. package/dist/fold/second.d.ts +0 -18
  129. package/dist/fold/shards.d.ts +0 -29
  130. package/dist/fold/signed.d.ts +0 -23
  131. package/dist/fold/signers.d.ts +0 -24
  132. package/dist/fold/stranger.d.ts +0 -3
  133. package/dist/fold/views.d.ts +0 -27
  134. package/dist/fold/wire.d.ts +0 -19
  135. package/dist/fold/zoom.d.ts +0 -16
  136. package/dist/host/act-cost.d.ts +0 -13
  137. package/dist/host/adapters/keys/ed25519.d.ts +0 -7
  138. package/dist/host/adapters/modules/javascript.d.ts +0 -3
  139. package/dist/host/adapters/transport/http.d.ts +0 -5
  140. package/dist/host/admitted-place.d.ts +0 -5
  141. package/dist/host/archive.d.ts +0 -11
  142. package/dist/host/capsule-process.d.ts +0 -21
  143. package/dist/host/capsule.d.ts +0 -19
  144. package/dist/host/cell-receipts.d.ts +0 -2
  145. package/dist/host/content-needed.d.ts +0 -5
  146. package/dist/host/content-store.d.ts +0 -8
  147. package/dist/host/contextual-place.d.ts +0 -59
  148. package/dist/host/digest.d.ts +0 -3
  149. package/dist/host/hash.d.ts +0 -9
  150. package/dist/host/io.d.ts +0 -11
  151. package/dist/host/lifetime.d.ts +0 -1
  152. package/dist/host/located.d.ts +0 -4
  153. package/dist/host/native/bounded-file.d.ts +0 -8
  154. package/dist/host/native/command.d.ts +0 -36
  155. package/dist/host/native/control-bridge-worker.d.ts +0 -1
  156. package/dist/host/native/control-bridge.d.ts +0 -30
  157. package/dist/host/native/control-selection.d.ts +0 -29
  158. package/dist/host/native/custody.d.ts +0 -5
  159. package/dist/host/native/deadline.d.ts +0 -12
  160. package/dist/host/native/descendants.d.ts +0 -1
  161. package/dist/host/native/generated-custodian.d.ts +0 -122
  162. package/dist/host/native/generated.d.ts +0 -217
  163. package/dist/host/native/image.d.ts +0 -36
  164. package/dist/host/native/jobs.d.ts +0 -75
  165. package/dist/host/native/loader.d.ts +0 -80
  166. package/dist/host/native/materialize.d.ts +0 -22
  167. package/dist/host/native/module-closure.d.ts +0 -27
  168. package/dist/host/native/module-syntax.d.ts +0 -8
  169. package/dist/host/native/native-binary.d.ts +0 -54
  170. package/dist/host/native/native-program.d.ts +0 -56
  171. package/dist/host/native/node-jobs.d.ts +0 -84
  172. package/dist/host/native/node-launch.d.ts +0 -72
  173. package/dist/host/native/preload.d.ts +0 -1
  174. package/dist/host/native/reading.d.ts +0 -91
  175. package/dist/host/native/receipt-environment.d.ts +0 -3
  176. package/dist/host/native/references.d.ts +0 -5
  177. package/dist/host/native/root.d.ts +0 -17
  178. package/dist/host/native/route.d.ts +0 -66
  179. package/dist/host/native/runtime.d.ts +0 -4
  180. package/dist/host/native-reader-context.d.ts +0 -3
  181. package/dist/host/objects.d.ts +0 -6
  182. package/dist/host/place-clock-selection.d.ts +0 -55
  183. package/dist/host/ports/ingress.d.ts +0 -24
  184. package/dist/host/ports/local-act.d.ts +0 -44
  185. package/dist/host/ports/place-act.d.ts +0 -46
  186. package/dist/host/ports/publication.d.ts +0 -10
  187. package/dist/host/ports/signing.d.ts +0 -31
  188. package/dist/host/ports/store.d.ts +0 -2
  189. package/dist/host/ports/transport.d.ts +0 -1
  190. package/dist/host/process-lifetime.d.ts +0 -11
  191. package/dist/host/provide.d.ts +0 -48
  192. package/dist/host/read-only.d.ts +0 -3
  193. package/dist/host/reading-closures.d.ts +0 -47
  194. package/dist/host/reading-context.d.ts +0 -29
  195. package/dist/host/reference.d.ts +0 -6
  196. package/dist/host/release.d.ts +0 -14
  197. package/dist/host/root-clock-source.d.ts +0 -85
  198. package/dist/host/selected-capsules.d.ts +0 -8
  199. package/dist/host/selected-topos.d.ts +0 -24
  200. package/dist/host/signing.d.ts +0 -3
  201. package/dist/host/source-content.d.ts +0 -12
  202. package/dist/host/timing.d.ts +0 -2
  203. package/dist/host/walk.d.ts +0 -6
  204. package/dist/judge/late.d.ts +0 -7
  205. package/dist/judge/take.d.ts +0 -59
  206. package/dist/judge/widening.d.ts +0 -1
  207. package/dist/land/act.d.ts +0 -30
  208. package/dist/land/alias.d.ts +0 -10
  209. package/dist/land/held.d.ts +0 -7
  210. package/dist/land/inert.d.ts +0 -26
  211. package/dist/land/leaving.d.ts +0 -14
  212. package/dist/land/ledger.d.ts +0 -33
  213. package/dist/land/owned.d.ts +0 -23
  214. package/dist/land/sign.d.ts +0 -15
  215. package/dist/land/standing-pin.d.ts +0 -3
  216. package/dist/land/vouched.d.ts +0 -21
  217. package/dist/land/withdraw.d.ts +0 -14
  218. package/dist/observe/files.d.ts +0 -14
  219. package/dist/observe/identity.d.ts +0 -21
  220. package/dist/observe/match.d.ts +0 -1
  221. package/dist/observe/regions.d.ts +0 -33
  222. package/dist/observe/run.d.ts +0 -31
  223. package/dist/observe/runner.d.ts +0 -20
  224. package/dist/render/capsule.d.ts +0 -24
  225. package/dist/render/field.d.ts +0 -3
  226. package/dist/render/names.d.ts +0 -3
  227. package/dist/render/open.d.ts +0 -27
  228. package/dist/render/page.d.ts +0 -3
  229. package/dist/render/receipts.d.ts +0 -3
  230. package/dist/render/shape.d.ts +0 -16
  231. package/dist/render/target.d.ts +0 -18
  232. package/dist/render/view.d.ts +0 -22
  233. package/dist/wasm/node-worker.d.ts +0 -1
  234. package/dist/wasm/object.d.ts +0 -8
  235. package/dist/wasm/worker.d.ts +0 -1
package/dist/cli/place.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { refreshRetainedJudgment } from "./retained-judgment.js";
1
2
  import { timing } from "../host/timing.js";
2
3
  import { attestationObservations } from "../fold/evidence.js";
3
4
  import { parse as parseEvidenceFields } from '@lapxo/topos/wire';
@@ -11,7 +12,7 @@ import { meets, instrumentKept } from "../fold/closed.js";
11
12
  import { foldPoints, keepFold, keptPlace } from "../fold/kept.js";
12
13
  import { openCells } from "../render/open.js";
13
14
  import { boundOf, packRegions, regionsNamed, regionsOf, unlikeReplay } from "../fold/region.js";
14
- import { answersElsewhere, foldCeilings } from "../fold/ceilings.js";
15
+ import { answersElsewhere, foldCeilings, ceilingSummary } from "../fold/ceilings.js";
15
16
  import { keyOf, keyFor, lockLines, lockStanding } from "../fold/keys.js";
16
17
  import { wordFrom, wordOf, wordOn } from "../fold/wire.js";
17
18
  import { bytesDigest, instrumentOf, signaturesOf } from "../fold/digests.js";
@@ -21,7 +22,7 @@ import { classDefaults, kindsOf, placesIn, spoken } from "../fold/places.js";
21
22
  import { isCeiling } from "../fold/configures.js";
22
23
  import { observedClaims, placedReadings } from "../fold/observed.js";
23
24
  import { capsuleReadingsOver, currentReceiptObservations, retiredReceiptHistory } from "../observe/regions.js";
24
- import { costReadings, ownReadings } from "../fold/own.js";
25
+ import { costReadings, ownReadings, currentActReadings } from "../fold/own.js";
25
26
  import { paidOf } from "../fold/paid.js";
26
27
  import { rolesOf } from "../fold/roles.js";
27
28
  import { secondHead } from "../fold/second.js";
@@ -45,12 +46,6 @@ const costsOf = (store) => ledgerLines(store, 'take').filter((line) => fieldOf(l
45
46
  function effectStates(_store) {
46
47
  return 'none';
47
48
  }
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
49
  /**
55
50
  * 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
51
  * 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
@@ -170,7 +165,7 @@ export function coneOf(root, entry, ceilings, descent) {
170
165
  if (meets(root, store, '') && instrumentKept(store) === instrumentOf(store, entry, standing, root, ownLock())) {
171
166
  const held = keptPlace(store);
172
167
  if (held !== undefined)
173
- return { standing, observed: held.observed, own: held.own, kept: true };
168
+ return { standing, observed: held.observed, own: { ...held.own, ...currentActReadings() }, kept: true };
174
169
  }
175
170
  const named = regionsNamed(standing);
176
171
  const reach = descent !== undefined && descent.length ? [...descent] : [...new Set(ceilings.map((line) => boundOf(named, line).region))];
@@ -199,7 +194,7 @@ export function foldPlace(root, entry, under, look = true, given) {
199
194
  const prior = keptPlace(store, under, instrumentOf(store, entry, standingOf(root).standing, root, ownLock()));
200
195
  if (prior !== undefined) {
201
196
  process.stderr.write(`CLOSED ${under || '.'} · digest ${digestMs} ms\n`);
202
- return { ...prior, kept: true };
197
+ return refreshRetainedJudgment(prior, [...prior.standing.filter((line) => isCeiling(line) && !(under && fieldOf(line, 'measure') === 'unread')), ...ownCeilings(under)]);
203
198
  }
204
199
  }
205
200
  const { standing, lock: attested, rendered, owned } = given?.standing ?? standingOf(root, under);
@@ -244,14 +239,7 @@ export function foldPlace(root, entry, under, look = true, given) {
244
239
  history: live.history.filter((line) => fieldOf(line, 'needs').split('|').filter(Boolean).some(inside)),
245
240
  observed,
246
241
  receiptHistory: retiredReceiptHistory({ root, store, ...(under ? { under } : {}), standing, observed: read }),
247
- ceilings: {
248
- read: folded.read.length,
249
- total: ceilings.length,
250
- unread: folded.unread.map((line) => fieldOf(line, 'scope')),
251
- vacuous: folded.vacuous.map((line) => fieldOf(line, 'scope')),
252
- short: listed(folded.over.filter((o) => o.side === 'short' && !shared.has(o.question))),
253
- over: listed(folded.over.filter((o) => o.side === 'over')),
254
- },
242
+ ceilings: ceilingSummary(folded, ceilings.length, shared),
255
243
  orphans,
256
244
  lock,
257
245
  signed: signedByKey(store, standing, everywhere),
@@ -284,14 +272,7 @@ export function foldPlace(root, entry, under, look = true, given) {
284
272
  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 } }),
285
273
  missing: owed,
286
274
  own: { ...place.own, ...docs },
287
- ceilings: {
288
- ...place.ceilings,
289
- read: again.read.length,
290
- unread: again.unread.map((line) => fieldOf(line, 'scope')),
291
- vacuous: again.vacuous.map((line) => fieldOf(line, 'scope')),
292
- short: listed(again.over.filter((o) => o.side === 'short' && !shared.has(o.question))),
293
- over: listed(again.over.filter((o) => o.side === 'over')),
294
- },
275
+ ceilings: ceilingSummary(again, ceilings.length, shared),
295
276
  };
296
277
  if (folder !== undefined && meets(root, store, under ?? '', true, whole.observed))
297
278
  took('keep', () => keepFold(store, taken, whole, points, self));
@@ -0,0 +1,25 @@
1
+ import { foldCeilings, ceilingSummary } from "../fold/ceilings.js";
2
+ import { currentActReadings } from "../fold/own.js";
3
+ import { placedReadings } from "../fold/observed.js";
4
+ import { placesIn } from "../fold/places.js";
5
+ import { releasePolicy, releaseFaults } from "../fold/release-policy.js";
6
+ import { attestationObservations } from "../fold/evidence.js";
7
+ import { parse } from '@lapxo/topos/wire';
8
+ import { point, region, within } from '@lapxo/obligations/field';
9
+ /** A verified semantic fold can be reused. Its previous act's measurements cannot.
10
+ * Keep history intact and judge current measurements with the ordinary interpreters.
11
+ */
12
+ export function refreshRetainedJudgment(prior, ceilings, current = currentActReadings(prior.under)) {
13
+ const own = { ...prior.own, ...current };
14
+ const readings = foldCeilings({ standing: prior.standing, ceilings, observed: prior.observed,
15
+ own, epoch: prior.epoch, ...(prior.under ? { under: prior.under, places: new Set(placesIn(prior.root)) } : {}) });
16
+ const standing = prior.standing.filter(line => !prior.grey.includes(line) && !prior.refused.includes(line));
17
+ const shared = new Set(prior.under ? placedReadings(prior.observed)
18
+ .filter(reading => !within(point(reading.place.replace(/\/\*$/, '')), region(prior.under)))
19
+ .map(reading => reading.question) : []);
20
+ return { ...prior, kept: true, own, ceilings: ceilingSummary(readings, ceilings.length, shared),
21
+ release: releasePolicy({ standing, demands: prior.demands, paid: prior.paid, ceilings, readings,
22
+ faults: releaseFaults(prior),
23
+ verdicts: attestationObservations(standing.map(line => { const got = parse(line); return got.kind === 'fact' ? got.value.fields : {}; }), prior.second),
24
+ snapshot: { fold: prior.key, instrument: prior.instrument } }) };
25
+ }
@@ -1,5 +1,6 @@
1
+ import { BoundRefusal } from "../host/refusals.js";
1
2
  import { hasContextualPlace, contextualStanding } from "../host/contextual-place.js";
2
- import { authenticatedStanding } from "../host/admitted-place.js";
3
+ import { publicStandingLines } from "../host/admitted-place.js";
3
4
  import { viewsOf } from "../fold/views.js";
4
5
  import { lockStanding } from "../fold/keys.js";
5
6
  import { storeOf } from "../land/ledger.js";
@@ -10,11 +11,11 @@ import { storeOf } from "../land/ledger.js";
10
11
  export function printStandingResult(root) {
11
12
  const store = storeOf(root), view = viewsOf(lockStanding(store)).get('standing');
12
13
  if (!view || view.shape || !view.regions.some(region => region.name === 'standing'))
13
- throw Error('REFUSE·view standing requires a declared standing view');
14
+ throw new BoundRefusal('standing/view', 'REFUSE·view standing requires a declared standing view');
14
15
  if (hasContextualPlace(root)) {
15
16
  process.stdout.write(JSON.stringify(contextualStanding(root)) + '\n');
16
17
  return;
17
18
  }
18
- const standing = authenticatedStanding(root);
19
+ const standing = publicStandingLines(root);
19
20
  process.stdout.write(standing.length ? standing.join('\n') + '\n' : '');
20
21
  }
package/dist/cli/verb.js CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { BoundRefusal, describeRefusal, readRefusalCatalog } from "../host/refusals.js";
3
+ import { readFileSync as readCatalogFile } from 'node:fs';
4
+ import { sha256 as catalogDigest } from "../host/hash.js";
2
5
  import { printReleaseApproval } from "./release-result.js";
3
6
  import { inspectReference } from "../host/reference.js";
7
+ import { exportAuthenticatedReference } from "../host/reference-export.js";
4
8
  import { authenticatedReferenceSelected, openAuthenticatedReference } from "../host/reference-native.js";
5
9
  import { printActResult } from "./act-result.js";
6
10
  import { printStandingResult } from "./standing-result.js";
@@ -209,7 +213,7 @@ async function view(root, under, asked, told = [], coord, key, includePolicy = t
209
213
  }
210
214
  if (name === 'standing') {
211
215
  if (under || told.length || coord || depth !== undefined)
212
- throw Error('REFUSE·standing local committed projection only');
216
+ throw new BoundRefusal('standing/query', 'REFUSE·standing local committed projection only');
213
217
  printStandingResult(root);
214
218
  return EXIT.closed;
215
219
  }
@@ -374,6 +378,15 @@ async function view(root, under, asked, told = [], coord, key, includePolicy = t
374
378
  return shown(fold);
375
379
  }
376
380
  async function signVerb(root, rest) {
381
+ const as = valueOf(rest, FLAGS.as);
382
+ if (as !== undefined) {
383
+ const sources = positionalsOf(rest);
384
+ if (as !== 'reference' || sources.length !== 1 || rest.includes(FLAGS.check))
385
+ throw new BoundRefusal('reference-export/usage', 'REFUSE·reference-export usage: sign --as reference <source-url>');
386
+ const result = await exportAuthenticatedReference(root, sources[0], { key: valueOf(rest, FLAGS.key), keyFile: valueOf(rest, FLAGS.keyFile), signer: valueOf(rest, FLAGS.signer) });
387
+ process.stdout.write(JSON.stringify(result) + '\n');
388
+ return EXIT.closed;
389
+ }
377
390
  const batch = await signedBatch(root, rest, positionalsOf(rest));
378
391
  if (batch.kind === 'exit')
379
392
  return batch.code;
@@ -633,18 +646,38 @@ function main(argv) {
633
646
  process.stderr.write(`${selfName()}: ${helpLines().join(' · ')}\n`);
634
647
  return EXIT.usage;
635
648
  }
649
+ function printRefusal(error) {
650
+ try {
651
+ const text = readCatalogFile(new URL('../../docs/contracts/refusals.bound', import.meta.url), 'utf8');
652
+ const entry = describeRefusal(error, readRefusalCatalog(text));
653
+ process.stderr.write(JSON.stringify({ profile: 'bound-refusal@1', ...entry, catalog: catalogDigest(text) }) + '\n');
654
+ }
655
+ catch {
656
+ // A missing/invalid catalog cannot supply trustworthy metadata. Keep the
657
+ // failure named instead of recursively failing while formatting a refusal.
658
+ process.stderr.write(JSON.stringify({ profile: 'bound-refusal@1', code: 'catalog/invalid', unmeasured: ['category', 'meaning', 'next', 'catalog'] }) + '\n');
659
+ }
660
+ }
661
+ // Legacy numeric refusals receive a generic code by exit result, never by parsing
662
+ // a diagnostic. Specific causes retain their own typed code in the error path.
663
+ function finished(code) {
664
+ if (code === EXIT.refuse || code === EXIT.usage)
665
+ printRefusal(new BoundRefusal(code === EXIT.usage ? 'operation/usage' : 'operation/failed', ''));
666
+ process.exitCode = code;
667
+ }
636
668
  // The same refusal boundary covers synchronous operations and asynchronous processes.
637
669
  const refused = (error) => {
638
670
  const message = error instanceof Error ? error.message : String(error);
639
671
  process.stderr.write(`${selfName()}: ${message.startsWith('REFUSE·') ? message : `REFUSE·crash ${message}`}\n`);
672
+ printRefusal(error instanceof BoundRefusal ? error : new BoundRefusal('operation/failed', message));
640
673
  process.exitCode = EXIT.refuse;
641
674
  };
642
675
  try {
643
676
  const ran = main(process.argv.slice(2));
644
677
  if (ran instanceof Promise)
645
- ran.then((code) => { process.exitCode = code; }).catch(refused);
678
+ ran.then(finished).catch(refused);
646
679
  else
647
- process.exitCode = ran;
680
+ finished(ran);
648
681
  }
649
682
  catch (error) {
650
683
  refused(error);
@@ -0,0 +1,2 @@
1
+ /** Shared, host-free UTF-8 encoding for protocol byte budgets. */
2
+ export const encodeUTF8 = (text) => new TextEncoder().encode(text);
@@ -9,3 +9,5 @@
9
9
  export { objectFold } from './object.ts';
10
10
  export type { ObjectReading } from './object.ts';
11
11
  export type { ObjectRecord, ObjectContext } from '@lapxo/topos/wire';
12
+ export { readContent, retainContent, invokeSigningPort } from './ports.ts';
13
+ export type { PortLimits, ContentReadPort, PersistencePort, DigestPort, SigningPort, SigningLot, SignatureRecord } from './ports.ts';
@@ -7,3 +7,5 @@
7
7
  * Object operations delegate to the existing Obligations implementation.
8
8
  */
9
9
  export { objectFold } from "./object.js";
10
+ // Optional host operations are explicit and injected; objectFold itself never invokes them.
11
+ export { readContent, retainContent, invokeSigningPort } from "./ports.js";
@@ -0,0 +1,32 @@
1
+ export interface PortLimits {
2
+ readonly timeoutMs: number;
3
+ readonly maxBytes: number;
4
+ }
5
+ export interface SigningLot {
6
+ readonly bytes: readonly string[];
7
+ readonly keyId: string;
8
+ readonly algorithm: string;
9
+ }
10
+ export interface SignatureRecord {
11
+ readonly keyId: string;
12
+ readonly signature: string;
13
+ }
14
+ export type SigningPort = (lot: SigningLot, signal: AbortSignal) => Promise<readonly SignatureRecord[]>;
15
+ export type ContentReadPort = (source: string, digest: string, signal: AbortSignal) => Promise<Uint8Array>;
16
+ /** Atomic byte retention supplied by the host. This is neither admission nor a current-answer cache. */
17
+ export type PersistencePort = (digest: string, bytes: Uint8Array, signal: AbortSignal) => Promise<void>;
18
+ export type DigestPort = (bytes: Uint8Array) => string | Promise<string>;
19
+ export declare function readContent(source: string, digest: string, ports: {
20
+ readonly read: ContentReadPort;
21
+ readonly digestBytes: DigestPort;
22
+ }, limits: PortLimits, signal?: AbortSignal): Promise<Uint8Array>;
23
+ /** Verify before invoking retention; no operation automatically writes the projected result. */
24
+ export declare function retainContent(digest: string, bytes: Uint8Array, ports: {
25
+ readonly retain: PersistencePort;
26
+ readonly digestBytes: DigestPort;
27
+ }, limits: PortLimits, signal?: AbortSignal): Promise<{
28
+ readonly digest: string;
29
+ readonly bytes: number;
30
+ }>;
31
+ /** Acquire protocol-shaped signatures only; the existing consent path verifies them and decides authority. */
32
+ export declare function invokeSigningPort(lot: SigningLot, sign: SigningPort, limits: PortLimits, signal?: AbortSignal): Promise<readonly SignatureRecord[]>;
@@ -0,0 +1,103 @@
1
+ import { signerRequestBytes, signerResponseBytes, signerResponseOf } from '@lapxo/topos/wire';
2
+ import { BoundRefusal } from "../host/refusals.js";
3
+ import { encodeUTF8 as encoded } from "./encoding.js";
4
+ class PortFault extends BoundRefusal {
5
+ }
6
+ const fail = (code) => { throw new PortFault('host-port/' + code, 'REFUSE·host-port/' + code); };
7
+ function limitsOf(limits) { if (!limits || !Number.isSafeInteger(limits.timeoutMs) || limits.timeoutMs < 1 || limits.timeoutMs > 2147483647 || !Number.isSafeInteger(limits.maxBytes) || limits.maxBytes < 1)
8
+ fail('budget'); }
9
+ /** The callback must cooperate with cancellation; JavaScript callbacks are not a sandbox. */
10
+ async function bounded(limits, signal, run) {
11
+ limitsOf(limits);
12
+ if (signal?.aborted)
13
+ fail('cancelled');
14
+ return new Promise((resolve, reject) => {
15
+ const controller = new AbortController();
16
+ let done = false;
17
+ const finish = (code, value) => { if (done)
18
+ return; done = true; clearTimeout(timer); signal?.removeEventListener('abort', abort); if (code) {
19
+ controller.abort();
20
+ reject(new BoundRefusal('host-port/' + code, 'REFUSE·host-port/' + code));
21
+ }
22
+ else
23
+ resolve(value); };
24
+ const abort = () => finish('cancelled'), timer = setTimeout(() => finish('timeout'), limits.timeoutMs);
25
+ signal?.addEventListener('abort', abort, { once: true });
26
+ if (signal?.aborted) {
27
+ abort();
28
+ return;
29
+ }
30
+ Promise.resolve().then(() => { if (done)
31
+ fail('cancelled'); return run(controller.signal); }).then(value => finish(undefined, value), error => finish(error instanceof PortFault ? error.code.slice('host-port/'.length) : 'failed'));
32
+ });
33
+ }
34
+ function owned(bytes, maxBytes) { if (!(bytes instanceof Uint8Array))
35
+ fail('response'); if (bytes.byteLength > maxBytes)
36
+ fail('budget'); if (typeof SharedArrayBuffer !== 'undefined' && bytes.buffer instanceof SharedArrayBuffer)
37
+ fail('response'); return new Uint8Array(bytes); }
38
+ const identity = (digest) => { if (!/^sha256:[a-f0-9]{64}$/.test(digest))
39
+ fail('integrity'); };
40
+ export async function readContent(source, digest, ports, limits, signal) {
41
+ limitsOf(limits);
42
+ identity(digest);
43
+ return bounded(limits, signal, async (s) => { const bytes = owned(await ports.read(source, digest, s), limits.maxBytes); if (s.aborted)
44
+ fail('cancelled'); if (await ports.digestBytes(new Uint8Array(bytes)) !== digest)
45
+ fail('integrity'); if (s.aborted)
46
+ fail('cancelled'); return bytes; });
47
+ }
48
+ /** Verify before invoking retention; no operation automatically writes the projected result. */
49
+ export async function retainContent(digest, bytes, ports, limits, signal) {
50
+ limitsOf(limits);
51
+ identity(digest);
52
+ if (signal?.aborted)
53
+ fail('cancelled');
54
+ const copy = owned(bytes, limits.maxBytes);
55
+ return bounded(limits, signal, async (s) => { if (await ports.digestBytes(new Uint8Array(copy)) !== digest)
56
+ fail('integrity'); if (s.aborted)
57
+ fail('cancelled'); const result = await ports.retain(digest, copy, s); if (result !== undefined)
58
+ fail('response'); return Object.freeze({ digest, bytes: copy.byteLength }); });
59
+ }
60
+ /** Acquire protocol-shaped signatures only; the existing consent path verifies them and decides authority. */
61
+ export async function invokeSigningPort(lot, sign, limits, signal) {
62
+ limitsOf(limits);
63
+ if (!lot || !Array.isArray(lot.bytes))
64
+ fail('budget');
65
+ let size = 0;
66
+ for (const bytes of lot.bytes) {
67
+ if (typeof bytes !== 'string' || bytes.length > limits.maxBytes - size)
68
+ fail('budget');
69
+ size += encoded(bytes).length + 1;
70
+ if (size > limits.maxBytes)
71
+ fail('budget');
72
+ }
73
+ let request;
74
+ try {
75
+ request = signerRequestBytes(lot);
76
+ }
77
+ catch {
78
+ return fail('response');
79
+ }
80
+ if (encoded(request).length > limits.maxBytes)
81
+ fail('budget');
82
+ const input = Object.freeze({ ...lot, bytes: Object.freeze([...lot.bytes]) });
83
+ return bounded(limits, signal, async (s) => {
84
+ const records = await sign(input, s);
85
+ if (!Array.isArray(records) || records.length !== lot.bytes.length || records.some(r => !r || typeof r.signature !== 'string' || r.signature.length > limits.maxBytes))
86
+ fail('response');
87
+ let response;
88
+ try {
89
+ response = signerResponseBytes(records);
90
+ }
91
+ catch {
92
+ return fail('response');
93
+ }
94
+ if (encoded(response).length > limits.maxBytes)
95
+ fail('budget');
96
+ try {
97
+ return Object.freeze(signerResponseOf(response, lot).map(record => Object.freeze({ ...record })));
98
+ }
99
+ catch {
100
+ return fail('response');
101
+ }
102
+ });
103
+ }
@@ -1,7 +1,6 @@
1
- import { join } from 'node:path';
2
- import { readFileSync } from 'node:fs';
1
+ import { bootstrapAnchor } from "./bootstrap-anchor.js";
3
2
  import { rootLedgerLines, storeOf } from "../land/ledger.js";
4
- import { fieldOf, isConfig, selfName } from "./claims.js";
3
+ import { fieldOf, isConfig } from "./claims.js";
5
4
  /** Local admission history only. Foreign ingress is evidence, never coverage.
6
5
  * The clock cutoff is meaningful for configuration; object clocks stay intact. */
7
6
  export function admissionHistoryAt(root, epoch) {
@@ -9,14 +8,10 @@ export function admissionHistoryAt(root, epoch) {
9
8
  return [...new Set(rootLedgerLines(store))]
10
9
  .filter(line => fieldOf(line, 'sig') !== '' && (!isConfig(line) || Number(fieldOf(line, 'epoch')) <= epoch));
11
10
  }
12
- /** The existing bootstrap's public root of trust, not today's key selection. */
11
+ /** The original local bootstrap, never today's key selection. */
13
12
  export function admissionAnchor(root) {
14
- const at = join(storeOf(root), `${selfName()}.keys`);
15
- const keys = JSON.parse(readFileSync(at, 'utf8'));
16
- const anchors = Object.values(keys);
17
- if (anchors.length !== 1 || !anchors[0]?.publicKey || !anchors[0].coverage.length)
13
+ const anchor = bootstrapAnchor(root);
14
+ if (!anchor)
18
15
  throw Error('REFUSE·act historical admission requires one bootstrap anchor');
19
- const anchor = anchors[0];
20
- return { id: anchor.id, keyClass: 'authorize', publicKey: anchor.publicKey, coverage: anchor.coverage,
21
- depth: { lo: 1, hi: 16 }, admittedBy: [] };
16
+ return { id: anchor.id, keyClass: 'authorize', publicKey: anchor.publicKey, coverage: anchor.coverage, depth: { lo: 1, hi: 16 }, admittedBy: [] };
22
17
  }
@@ -0,0 +1,28 @@
1
+ import { join } from 'node:path';
2
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
3
+ import { storeOf } from "../land/ledger.js";
4
+ /** Read the existing place-local root of trust. Names and current claims select no authority. */
5
+ export function bootstrapAnchor(root) {
6
+ const store = storeOf(root);
7
+ const files = existsSync(store) ? readdirSync(store).filter(name => name.endsWith('.keys')).sort() : [];
8
+ if (!files.length)
9
+ return undefined;
10
+ const candidates = files.map(name => {
11
+ let keys;
12
+ try {
13
+ keys = JSON.parse(readFileSync(join(store, name), 'utf8'));
14
+ }
15
+ catch {
16
+ throw Error('REFUSE·act bootstrap anchor is unreadable');
17
+ }
18
+ const anchors = Object.values(keys ?? {}), anchor = anchors[0];
19
+ if (anchors.length !== 1 || !anchor || typeof anchor.id !== 'string' || !anchor.id || typeof anchor.publicKey !== 'string' || !anchor.publicKey || !Array.isArray(anchor.coverage) || !anchor.coverage.length || anchor.coverage.some(scope => typeof scope !== 'string' || !scope))
20
+ throw Error('REFUSE·act historical admission requires one bootstrap anchor');
21
+ return anchor;
22
+ });
23
+ const identities = new Set(candidates.map(anchor => JSON.stringify([anchor.id, anchor.publicKey, [...new Set(anchor.coverage)].sort()])));
24
+ if (identities.size !== 1)
25
+ throw Error('REFUSE·act conflicting bootstrap anchors');
26
+ const anchor = candidates[0];
27
+ return { id: anchor.id, publicKey: anchor.publicKey, coverage: anchor.coverage };
28
+ }
@@ -127,3 +127,16 @@ export function foldCeilings(input) {
127
127
  readings: said,
128
128
  };
129
129
  }
130
+ function listed(misses) {
131
+ const by = new Map();
132
+ for (const o of misses)
133
+ by.set(o.ceiling, [...(by.get(o.ceiling) ?? []), o.question === o.ceiling ? o.got : `${o.question}=${o.got}`]);
134
+ return [...by].map(([scope, got]) => `${scope} · ${got.length > 4 ? `${got.slice(0, 4).join(' ')} +${got.length - 4}` : got.join(' ')}`);
135
+ }
136
+ /** One summary for fresh and retained judgments over the same declared bounds. */
137
+ export function ceilingSummary(fold, total, shared = new Set()) {
138
+ return { read: fold.read.length, total, unread: fold.unread.map(line => fieldOf(line, 'scope')),
139
+ vacuous: fold.vacuous.map(line => fieldOf(line, 'scope')),
140
+ short: listed(fold.over.filter(one => one.side === 'short' && !shared.has(one.question))),
141
+ over: listed(fold.over.filter(one => one.side === 'over')) };
142
+ }
package/dist/fold/own.js CHANGED
@@ -27,6 +27,12 @@ import { writtenIn } from "./signed.js";
27
27
  import { laidDiffers } from "./laid.js";
28
28
  import { heldBytes } from "../land/held.js";
29
29
  import { capsuleAt, placesIn, worldAt } from "./places.js";
30
+ /** Measurements of this invocation; never evidence of an earlier kept fold. */
31
+ export function currentActReadings(under) {
32
+ const receipts = receiptsSeen();
33
+ return placeOnly({ idle: idleCount(), s: actSeconds(), 'walk-read': receipts.count, 'walk-ms': receipts.ms,
34
+ 'kept-folds-read-under-another-instrument': foldsElsewhere() }, under);
35
+ }
30
36
  const entered = { foreign: 0 };
31
37
  /** Host and instrument measurements. Domain contracts require their selected readers; missing readings are not fabricated zeroes. */
32
38
  function shipped(root, store, standing, under) {
@@ -193,12 +199,8 @@ export function ownReadings(input) {
193
199
  ...Object.fromEntries(standing.filter((line) => isCeiling(line) && (fieldOf(line, 'measure') === 'reader-modules' || fieldOf(line, 'scope').split('/').pop() === 'reader-modules'))
194
200
  .flatMap((line) => ((place) => place === undefined ? [] : [[fieldOf(line, 'scope'), tree(() => exporting(observed, `${place}/`, ['observe', 'run']))]])(fieldOf(line, 'scope').split('/').find((step) => capsuleAt(root, step))))),
195
201
  ...ownFrom(ceilingsNamed(standing, 'world-lines-outside-their-capsule').find((line) => fieldOf(line, 'form') === 'interval'), 'world-lines-outside-their-capsule', tree(() => outsideTheirCapsule(root, standing, standing).length)),
196
- idle: idleCount(),
197
- s: actSeconds(),
202
+ ...currentActReadings(),
198
203
  'cli-verbs': VERB_NAMES.length,
199
- 'walk-read': receiptsSeen().count,
200
- 'walk-ms': receiptsSeen().ms,
201
- 'kept-folds-read-under-another-instrument': tree(() => foldsElsewhere()),
202
204
  'accepts-that-refolded': tree(() => counted(store, standing, 'beat/accept', 'folded')),
203
205
  ...(keyOf(store, 'attest') === undefined ? {} : { [`${keyOf(store, 'attest')}-ms`]: tree(() => attestBeat(store, standing)) }),
204
206
  ship: took('ship', () => shipped(root, store, standing, under)),
@@ -1,11 +1,9 @@
1
- import { existsSync, join } from "../host/io.js";
1
+ import { bootstrapAnchor } from "./bootstrap-anchor.js";
2
2
  import { authorityOf, isKeyClaim, signersOf } from '@lapxo/topos/wire';
3
3
  import { verifiesFields } from "../land/sign.js";
4
- import { fieldOf, selfName, parsedLine as parse } from "./claims.js";
4
+ import { fieldOf, parsedLine as parse } from "./claims.js";
5
5
  import { keyFor, lockStanding } from "./keys.js";
6
- import { storeRoot } from "../host/ports/store.js";
7
6
  import { storeOf } from "../land/ledger.js";
8
- import { observeText } from "../observe/files.js";
9
7
  /** A lock line about the signers: the authority fold reads it. */
10
8
  export function isSignerLock(line) {
11
9
  const got = parse(line);
@@ -38,11 +36,9 @@ export function writerFor(standing, kind) {
38
36
  return undefined;
39
37
  }
40
38
  export function publicKeyOf(root, keyId) {
41
- const at = [join(storeRoot(root), `${selfName()}.keys`), join(storeOf(root), `${selfName()}.keys`)].find((one) => existsSync(one));
42
- const keys = at === undefined ? {} : JSON.parse(observeText(at) ?? '{}');
43
- const anchored = keys[keyId]?.publicKey;
44
- if (anchored !== undefined)
45
- return anchored;
39
+ const anchor = bootstrapAnchor(root);
40
+ if (anchor?.id === keyId)
41
+ return anchor.publicKey;
46
42
  const said = lockStanding(storeOf(root))
47
43
  .find((line) => fieldOf(line, 'scope') === `keys/${keyId}` && fieldOf(line, 'measure') === 'public-key' && fieldOf(line, 'value') !== 'withdraw');
48
44
  return said === undefined ? undefined : fieldOf(said, 'value');
@@ -55,3 +55,9 @@ export function authenticatedRootStanding(root) {
55
55
  }
56
56
  /** Legacy Root lines remain unchanged; contextual public output has its own carrier. */
57
57
  export const authenticatedStanding = authenticatedRootStanding;
58
+ /** Public current configuration omits withdrawal markers; typed effective history
59
+ * remains intact for the existing typed-object projection. Internal readers keep
60
+ * authenticatedStanding, including its historical markers. */
61
+ export function publicStandingLines(root) {
62
+ return authenticatedRootStanding(root).filter(line => !isConfig(line) || fieldOf(line, 'value') !== 'withdraw');
63
+ }
@@ -5,7 +5,7 @@ import { commitPlaceAct, placeActResult, committedPlaceActResults } from "./port
5
5
  import { placesIn } from "../fold/places.js";
6
6
  import { appliedHistoryIn } from "../fold/signed.js";
7
7
  import { storeOf } from "../land/ledger.js";
8
- import { authenticatedRootStanding } from "./admitted-place.js";
8
+ import { publicStandingLines } from "./admitted-place.js";
9
9
  import { foldClaims, fieldOf } from "../fold/claims.js";
10
10
  const fail = (s) => { throw Error('REFUSE·contextual place ' + s); };
11
11
  function read(path, limit) {
@@ -73,5 +73,5 @@ export function contextualStanding(root) {
73
73
  }
74
74
  }
75
75
  const legacyPlaces = placesIn(root).map(place => { const history = appliedHistoryIn(root, place), folded = foldClaims(history); return { namespace: 'legacy-global', place: [place, 'TARGET.bound'].join('/'), standing: folded.standing.filter(line => fieldOf(line, 'value') !== 'withdraw'), history }; });
76
- return { profile: PLACE_ACT_CONTEXT, root: authenticatedRootStanding(root), legacyPlaces, contexts: acts.map(a => ({ identity: a.identity, context: a.bundle.context, receipts: a.bundle.receipts, authority: selected.authority(a.bundle.context) })), places: [...groups.values()].map(group => { const folded = foldClaims(group.lines); return { namespace: group.namespace, place: group.place, standing: folded.standing.filter(line => fieldOf(line, 'value') !== 'withdraw'), retracted: folded.retracted, superseded: folded.superseded, forks: folded.forks, contexts: group.contexts }; }) };
76
+ return { profile: PLACE_ACT_CONTEXT, root: publicStandingLines(root), legacyPlaces, contexts: acts.map(a => ({ identity: a.identity, context: a.bundle.context, receipts: a.bundle.receipts, authority: selected.authority(a.bundle.context) })), places: [...groups.values()].map(group => { const folded = foldClaims(group.lines); return { namespace: group.namespace, place: group.place, standing: folded.standing.filter(line => fieldOf(line, 'value') !== 'withdraw'), retracted: folded.retracted, superseded: folded.superseded, forks: folded.forks, contexts: group.contexts }; }) };
77
77
  }
package/dist/host/io.js CHANGED
@@ -7,5 +7,5 @@ export { basename, dirname, join, relative, resolve } from 'node:path';
7
7
  export { fileURLToPath } from 'node:url';
8
8
  export { parentPort, workerData } from 'node:worker_threads';
9
9
  export { gzipSync } from 'node:zlib';
10
- /** UTF-8 encoding for host byte formats. */
11
- export const encodeUTF8 = (text) => new TextEncoder().encode(text);
10
+ /** UTF-8 encoding is shared with host-free protocol ports. */
11
+ export { encodeUTF8 } from "../engine/encoding.js";
@@ -18,12 +18,12 @@ export function moduleImportSyntax(source, coordinate) {
18
18
  }
19
19
  const found = new Set(), unresolved = new Set();
20
20
  const literal = stringLiteral;
21
- const visit = (node, parent, key) => {
21
+ const visit = (node, parent, key, reexportSource = false) => {
22
22
  if (!node || typeof node !== 'object')
23
23
  return;
24
24
  if (Array.isArray(node)) {
25
25
  for (const child of node)
26
- visit(child, parent, key);
26
+ visit(child, parent, key, reexportSource);
27
27
  return;
28
28
  }
29
29
  const n = node;
@@ -32,7 +32,11 @@ export function moduleImportSyntax(source, coordinate) {
32
32
  if (n['type'] === 'Identifier' && n['name'] === 'require') {
33
33
  const direct = parent?.['type'] === 'CallExpression' && key === 'callee';
34
34
  const namedProperty = (parent?.['type'] === 'MemberExpression' && key === 'property' && !parent['computed']) || ((parent?.['type'] === 'Property' || parent?.['type'] === 'MethodDefinition') && key === 'key' && !parent['computed'] && !parent['shorthand']);
35
- if (!direct && !namedProperty)
35
+ // Declaration names are not loader references. This does not resolve shadowing:
36
+ // references to a binding named require remain conservative, including local calls.
37
+ const declarationName = ((parent?.['type'] === 'ImportSpecifier' || parent?.['type'] === 'ImportDefaultSpecifier' || parent?.['type'] === 'ImportNamespaceSpecifier') && (key === 'imported' || key === 'local')) || (parent?.['type'] === 'FunctionDeclaration' && key === 'id');
38
+ const reexportName = parent?.['type'] === 'ExportSpecifier' && (key === 'exported' || (key === 'local' && reexportSource));
39
+ if (!direct && !namedProperty && !declarationName && !reexportName)
36
40
  unresolved.add('require reference at ' + String(n['start']));
37
41
  }
38
42
  let specifier;
@@ -52,7 +56,7 @@ export function moduleImportSyntax(source, coordinate) {
52
56
  if (specifier !== undefined)
53
57
  found.add(specifier);
54
58
  for (const [childKey, child] of Object.entries(n))
55
- visit(child, n, childKey);
59
+ visit(child, n, childKey, n['type'] === 'ExportNamedDeclaration' ? n['source'] !== null && n['source'] !== undefined : reexportSource);
56
60
  };
57
61
  visit(tree);
58
62
  return { imports: [...found], unresolved: [...unresolved] };
@@ -9,6 +9,10 @@ export interface ReferenceTrust {
9
9
  readonly formImplementation: string;
10
10
  readonly signers: readonly Signer[];
11
11
  readonly algorithms: readonly string[];
12
+ readonly contracts?: {
13
+ readonly refusals: string;
14
+ readonly standing: string;
15
+ };
12
16
  readonly objects: ObjectContext;
13
17
  readonly maxBytes: number;
14
18
  readonly maxRecords: number;
@@ -18,6 +22,10 @@ export interface ReferenceTrust {
18
22
  }
19
23
  /** Prospective authenticated-standing@1 host composition; no effects and no authority from transport. */
20
24
  export declare function inspectAuthenticatedReference(fragment: string, trust: ReferenceTrust): Promise<{
25
+ contracts?: {
26
+ refusals: string;
27
+ standing: string;
28
+ } | undefined;
21
29
  reference: import("./reference-profile.ts").StandingReference;
22
30
  records: readonly import("@lapxo/topos/wire").ObjectRecord[];
23
31
  semanticIdentity: string;
@@ -26,3 +34,7 @@ export declare function inspectAuthenticatedReference(fragment: string, trust: R
26
34
  originalRecords: readonly string[];
27
35
  }>;
28
36
  export { encodeReference, decodeReference } from './reference-profile.ts';
37
+ export { BoundRefusal, readRefusalCatalog, describeRefusal } from './refusals.ts';
38
+ export type { RefusalEntry } from './refusals.ts';
39
+ export { readContent, retainContent, invokeSigningPort } from '../engine/ports.ts';
40
+ export type { PortLimits, ContentReadPort, PersistencePort, DigestPort, SigningPort, SigningLot, SignatureRecord } from '../engine/ports.ts';