foottrace 1.2.0 → 1.3.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 (66) hide show
  1. package/README.md +27 -2
  2. package/dist/esm/index.d.ts +4 -0
  3. package/dist/esm/index.js +1 -0
  4. package/dist/esm/lib/cause/explain.js +7 -7
  5. package/dist/esm/lib/cause/queryMemo.d.ts +18 -0
  6. package/dist/esm/lib/cause/queryMemo.js +46 -0
  7. package/dist/esm/lib/cause/recordAdapter.js +12 -19
  8. package/dist/esm/lib/cause/recordChildren.d.ts +3 -3
  9. package/dist/esm/lib/cause/recordChildren.js +3 -4
  10. package/dist/esm/lib/cause/recordCoverage.d.ts +2 -2
  11. package/dist/esm/lib/cause/recordCoverage.js +1 -1
  12. package/dist/esm/lib/cause/recordIdentity.js +5 -5
  13. package/dist/esm/lib/cause/recordLoading.js +3 -3
  14. package/dist/esm/lib/cause/recordQuery.d.ts +9 -0
  15. package/dist/esm/lib/cause/recordQuery.js +22 -0
  16. package/dist/esm/lib/cause/recordScope.js +13 -13
  17. package/dist/esm/lib/cause/recordValidation.d.ts +4 -4
  18. package/dist/esm/lib/cause/recordValidation.js +17 -17
  19. package/dist/esm/lib/cause/session.js +9 -6
  20. package/dist/esm/lib/cause/storedRecordAdapter.js +16 -10
  21. package/dist/esm/lib/cause/types.d.ts +2 -1
  22. package/dist/esm/lib/cause/validation.d.ts +4 -4
  23. package/dist/esm/lib/cause/validation.js +19 -36
  24. package/dist/esm/lib/{cause → evidence}/admission.d.ts +5 -1
  25. package/dist/esm/lib/{cause → evidence}/admission.js +14 -1
  26. package/dist/esm/lib/evidence/codes.d.ts +33 -0
  27. package/dist/esm/lib/evidence/codes.js +28 -0
  28. package/dist/esm/lib/evidence/requirementTypes.d.ts +46 -0
  29. package/dist/esm/lib/evidence/requirementTypes.js +1 -0
  30. package/dist/esm/lib/evidence/requirements.d.ts +24 -0
  31. package/dist/esm/lib/evidence/requirements.js +185 -0
  32. package/dist/index.js +5 -1
  33. package/dist/lib/cause/explain.js +6 -6
  34. package/dist/lib/cause/queryMemo.js +52 -0
  35. package/dist/lib/cause/recordAdapter.js +10 -17
  36. package/dist/lib/cause/recordChildren.js +3 -4
  37. package/dist/lib/cause/recordCoverage.js +1 -1
  38. package/dist/lib/cause/recordIdentity.js +4 -4
  39. package/dist/lib/cause/recordLoading.js +2 -2
  40. package/dist/lib/cause/recordQuery.js +27 -0
  41. package/dist/lib/cause/recordScope.js +12 -12
  42. package/dist/lib/cause/recordValidation.js +21 -21
  43. package/dist/lib/cause/session.js +8 -5
  44. package/dist/lib/cause/storedRecordAdapter.js +15 -9
  45. package/dist/lib/cause/validation.js +23 -40
  46. package/dist/lib/{cause → evidence}/admission.js +14 -1
  47. package/dist/lib/evidence/codes.js +33 -0
  48. package/dist/lib/evidence/requirementTypes.js +2 -0
  49. package/dist/lib/evidence/requirements.js +190 -0
  50. package/dist/types/index.d.ts +4 -0
  51. package/dist/types/lib/cause/queryMemo.d.ts +18 -0
  52. package/dist/types/lib/cause/recordChildren.d.ts +3 -3
  53. package/dist/types/lib/cause/recordCoverage.d.ts +2 -2
  54. package/dist/types/lib/cause/recordQuery.d.ts +9 -0
  55. package/dist/types/lib/cause/recordValidation.d.ts +4 -4
  56. package/dist/types/lib/cause/types.d.ts +2 -1
  57. package/dist/types/lib/cause/validation.d.ts +4 -4
  58. package/dist/types/lib/{cause → evidence}/admission.d.ts +5 -1
  59. package/dist/types/lib/evidence/codes.d.ts +33 -0
  60. package/dist/types/lib/evidence/requirementTypes.d.ts +46 -0
  61. package/dist/types/lib/evidence/requirements.d.ts +24 -0
  62. package/package.json +1 -1
  63. /package/dist/esm/lib/cause/{recordParents.d.ts → recordInspection.d.ts} +0 -0
  64. /package/dist/esm/lib/cause/{recordParents.js → recordInspection.js} +0 -0
  65. /package/dist/lib/cause/{recordParents.js → recordInspection.js} +0 -0
  66. /package/dist/types/lib/cause/{recordParents.d.ts → recordInspection.d.ts} +0 -0
@@ -7,13 +7,13 @@ const validation_js_1 = require("./validation.js");
7
7
  const ranking_js_1 = require("./ranking.js");
8
8
  /** Read-only deterministic cause localisation and impact. No inference from timestamps or structural ancestry. */
9
9
  async function explain(graph, nodeId, options = {}) {
10
- (0, validation_js_1.name)(nodeId);
10
+ (0, validation_js_1.graphName)(nodeId);
11
11
  const session = new session_js_1.Session(graph, options);
12
12
  try {
13
13
  const backward = await (0, walk_js_1.walk)(session, [nodeId], 'parents');
14
14
  const missing = [...backward.gaps];
15
15
  let candidates = (0, walk_js_1.frontier)(backward).map((item) => item.nodeId);
16
- const rank = (0, validation_js_1.own)(options, 'rankRoots');
16
+ const rank = (0, validation_js_1.graphOwn)(options, 'rankRoots');
17
17
  if (rank !== undefined) {
18
18
  if (typeof rank !== 'function')
19
19
  throw new TypeError('CAUSE_CONFIGURATION_INVALID');
@@ -34,7 +34,7 @@ async function explain(graph, nodeId, options = {}) {
34
34
  const rootCause = causeComplete && candidates.length === 1 ? candidates[0] : undefined;
35
35
  const forward = await (0, walk_js_1.walk)(session, [nodeId], 'children');
36
36
  let impactNodes = Object.freeze(forward.nodes.filter((id) => id !== nodeId));
37
- const impactGaps = [...forward.gaps], rankImpact = (0, validation_js_1.own)(options, 'rankImpact');
37
+ const impactGaps = [...forward.gaps], rankImpact = (0, validation_js_1.graphOwn)(options, 'rankImpact');
38
38
  if (typeof rankImpact === 'function') {
39
39
  const selection = await session.invoke(undefined, () => rankImpact(impactNodes, session.context), (raw) => (0, ranking_js_1.admitRanking)(raw, new Set(impactNodes), {
40
40
  exactPermutation: true,
@@ -73,19 +73,19 @@ async function attentionList(graph, options = {}) {
73
73
  const session = new session_js_1.Session(graph, options);
74
74
  try {
75
75
  let seeds = [], missing = [];
76
- const requested = (0, validation_js_1.own)(options, 'nodeIds');
76
+ const requested = (0, validation_js_1.graphOwn)(options, 'nodeIds');
77
77
  const admitSeeds = (raw) => {
78
78
  // Only inspect the bounded prefix; the unread tail is explicitly incomplete.
79
79
  if (!Array.isArray(raw))
80
80
  return (0, validation_js_1.nodeIds)(raw, session.limits.maxNodes);
81
- const length = (0, validation_js_1.own)(raw, 'length');
81
+ const length = (0, validation_js_1.graphOwn)(raw, 'length');
82
82
  if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
83
83
  return (0, validation_js_1.nodeIds)(raw, session.limits.maxNodes);
84
84
  if (length > session.limits.maxNodes)
85
85
  missing.push((0, validation_js_1.gap)('node-limit'));
86
86
  const prefix = [];
87
87
  for (let i = 0; i < Math.min(length, session.limits.maxNodes); i++)
88
- prefix.push((0, validation_js_1.own)(raw, String(i)));
88
+ prefix.push((0, validation_js_1.graphOwn)(raw, String(i)));
89
89
  return (0, validation_js_1.nodeIds)(prefix, session.limits.maxNodes);
90
90
  };
91
91
  if (requested !== undefined) {
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.endQueryMemo = exports.queryMemo = exports.beginQueryMemo = void 0;
4
+ /** Share bounded derived work within one query without retaining it in the graph's storage cache. */
5
+ class QueryMemo {
6
+ maximumEntries;
7
+ owners = new Map();
8
+ entries = 0;
9
+ closed = false;
10
+ constructor(maximumEntries) {
11
+ this.maximumEntries = maximumEntries;
12
+ }
13
+ remember(owner, key, create) {
14
+ const previous = this.owners.get(owner);
15
+ if (previous?.has(key))
16
+ return previous.get(key);
17
+ if (this.closed || this.entries >= this.maximumEntries)
18
+ return create();
19
+ const value = create();
20
+ // Creation can finish after disposal or re-enter other readers; neither may refill a closed/full memo.
21
+ if (!this.closed && this.entries < this.maximumEntries) {
22
+ const bucket = this.owners.get(owner) ?? new Map();
23
+ if (!bucket.has(key))
24
+ this.entries++;
25
+ bucket.set(key, value);
26
+ this.owners.set(owner, bucket);
27
+ }
28
+ return value;
29
+ }
30
+ close() {
31
+ this.closed = true;
32
+ this.owners.clear();
33
+ this.entries = 0;
34
+ }
35
+ }
36
+ const queries = new WeakMap();
37
+ /** Reserve one resolution and one inspection per admitted node, shared across all adapter owners. */
38
+ function beginQueryMemo(context, maximumNodes) {
39
+ queries.set(context, new QueryMemo(maximumNodes * 2));
40
+ }
41
+ exports.beginQueryMemo = beginQueryMemo;
42
+ /** Direct graph calls have no managed query lifetime and deliberately remain uncached. */
43
+ function queryMemo(context) {
44
+ return queries.get(context);
45
+ }
46
+ exports.queryMemo = queryMemo;
47
+ /** Clear synchronously without aborting an otherwise successful query's public signal. */
48
+ function endQueryMemo(context) {
49
+ queries.get(context)?.close();
50
+ queries.delete(context);
51
+ }
52
+ exports.endQueryMemo = endQueryMemo;
@@ -5,38 +5,31 @@ const recordChildren_js_1 = require("./recordChildren.js");
5
5
  const recordCoverage_js_1 = require("./recordCoverage.js");
6
6
  const recordIdentity_js_1 = require("./recordIdentity.js");
7
7
  const recordLoading_js_1 = require("./recordLoading.js");
8
- const recordParents_js_1 = require("./recordParents.js");
8
+ const recordQuery_js_1 = require("./recordQuery.js");
9
9
  const recordScope_js_1 = require("./recordScope.js");
10
10
  const recordValidation_js_1 = require("./recordValidation.js");
11
+ /** Give each failed port its own incomplete page rather than sharing a mutable edge array. */
12
+ const unavailableAdjacency = () => ({ edges: [], complete: false });
11
13
  var recordScope_js_2 = require("./recordScope.js");
12
14
  Object.defineProperty(exports, "recordOptions", { enumerable: true, get: function () { return recordScope_js_2.recordOptions; } });
13
15
  /** Common engine for memory and one-scope-at-a-time host storage. Loader functions are trusted executable code. */
14
16
  function createLazyRecordGraph(load, options = {}) {
15
17
  const limits = (0, recordScope_js_1.recordOptions)(options), loader = (0, recordLoading_js_1.createRecordScopeLoader)(load, limits);
16
- const resolve = (nodeId, context) => (0, recordIdentity_js_1.resolveRecordNode)(nodeId, context, loader);
18
+ const query = (0, recordQuery_js_1.createRecordQuery)(loader, limits.maxEdges);
17
19
  return Object.freeze({
18
20
  nodeId: (address, node) => (0, recordIdentity_js_1.nodeIdFor)(address, node),
19
21
  openScope: (address, context) => (0, recordLoading_js_1.openRecordScope)(address, context, loader),
20
22
  async parents(nodeId, context) {
21
- const node = await resolve(nodeId, context);
22
- return 'failure' in node
23
- ? { edges: [], complete: false }
24
- : (0, recordParents_js_1.inspectRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope)).adjacency;
23
+ return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => query.inspect(node, context).adjacency, unavailableAdjacency);
25
24
  },
26
25
  async gaps(nodeId, context) {
27
- const node = await resolve(nodeId, context);
28
- return 'failure' in node
29
- ? (0, recordCoverage_js_1.gapForRecordFailure)(node.failure)
30
- : (0, recordParents_js_1.inspectRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope)).gaps;
26
+ return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => query.inspect(node, context).gaps, (failure) => (0, recordCoverage_js_1.gapForRecordFailure)(failure.failure));
31
27
  },
32
28
  async attention(nodeId, context) {
33
- return (0, recordCoverage_js_1.attentionForRecordNode)(await resolve(nodeId, context));
29
+ return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), recordCoverage_js_1.attentionForRecordNode, () => []);
34
30
  },
35
31
  async children(nodeId, context) {
36
- const node = await resolve(nodeId, context);
37
- return 'failure' in node
38
- ? { edges: [], complete: false }
39
- : (0, recordChildren_js_1.childrenForRecordNode)(node, limits.maxEdges, loader.extraGapCodes(node.scope));
32
+ return (0, recordQuery_js_1.whenResolved)(await query.resolve(nodeId, context), (node) => (0, recordChildren_js_1.childrenForRecordNode)(node, limits.maxEdges, query.inspect(node, context)), unavailableAdjacency);
40
33
  },
41
34
  });
42
35
  }
@@ -45,8 +38,8 @@ exports.createLazyRecordGraph = createLazyRecordGraph;
45
38
  function createRecordGraph(scopes, options = {}) {
46
39
  const limits = (0, recordScope_js_1.recordOptions)(options);
47
40
  return createLazyRecordGraph((address) => {
48
- for (const raw of (0, recordValidation_js_1.list)(scopes, limits.maxScopes)) {
49
- if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.own)(raw, 'address'))) === (0, recordValidation_js_1.addressKey)(address))
41
+ for (const raw of (0, recordValidation_js_1.recordList)(scopes, limits.maxScopes)) {
42
+ if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(raw, 'address'))) === (0, recordValidation_js_1.addressKey)(address))
50
43
  return { scope: raw };
51
44
  }
52
45
  throw new recordValidation_js_1.RecordRefusal('unavailable');
@@ -5,7 +5,6 @@ const forwardSliceForKey_js_1 = require("../slice/forwardSliceForKey.js");
5
5
  const recordControl_js_1 = require("./recordControl.js");
6
6
  const recordCoverage_js_1 = require("./recordCoverage.js");
7
7
  const recordIdentity_js_1 = require("./recordIdentity.js");
8
- const recordParents_js_1 = require("./recordParents.js");
9
8
  const recordScope_js_1 = require("./recordScope.js");
10
9
  /** Keep per-write and conservative fed edges distinct while retaining existing cap and deduplication order. */
11
10
  function appendFedChildren(scope, root, maximumEdges, edges) {
@@ -70,10 +69,10 @@ function appendDataChildren(scope, identity, commitIndex, maximumEdges, edges) {
70
69
  return complete;
71
70
  }
72
71
  /** Share parent-side coverage checks before appending data then control children in their established order. */
73
- function childrenForRecordNode(node, maximumEdges, extraGapCodes) {
72
+ function childrenForRecordNode(node, maximumEdges, inspection) {
74
73
  const { scope, identity, commitIndex } = node;
75
- const base = (0, recordParents_js_1.inspectRecordNode)(node, maximumEdges, extraGapCodes), edges = [];
76
- let complete = base.gaps.length === 0;
74
+ const edges = [];
75
+ let complete = inspection.gaps.length === 0;
77
76
  if (!(0, recordCoverage_js_1.allStageReadsCollected)(scope))
78
77
  complete = false;
79
78
  complete = appendDataChildren(scope, identity, commitIndex, maximumEdges, edges) && complete;
@@ -25,7 +25,7 @@ exports.gapForRecordFailure = gapForRecordFailure;
25
25
  /** Return captured mark references without treating an omitted attention map as collected evidence. */
26
26
  function attentionForRecordNode(node) {
27
27
  // An omitted map stays unknown coverage; it is never replaced by an affirmative empty map.
28
- return 'failure' in node ? [] : node.scope.marks?.get(node.identity.runtimeStageId) ?? [];
28
+ return node.scope.marks?.get(node.identity.runtimeStageId) ?? [];
29
29
  }
30
30
  exports.attentionForRecordNode = attentionForRecordNode;
31
31
  /** Emit host and capture gaps before query-derived gaps so existing evidence order stays stable. */
@@ -14,7 +14,7 @@ function readNodeIdentity(nodeId) {
14
14
  catch {
15
15
  throw new recordValidation_js_1.RecordRefusal();
16
16
  }
17
- const address = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.own)(fields, 'address')), runtimeStageId = (0, recordValidation_js_1.name)((0, recordValidation_js_1.own)(fields, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.own)(fields, 'commitIdx'), key = (0, recordValidation_js_1.own)(fields, 'key'), read = (0, recordValidation_js_1.own)(fields, 'read');
17
+ const address = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(fields, 'address')), runtimeStageId = (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(fields, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.recordOwn)(fields, 'commitIdx'), key = (0, recordValidation_js_1.recordOwn)(fields, 'key'), read = (0, recordValidation_js_1.recordOwn)(fields, 'read');
18
18
  if (commitIndex !== undefined && (!Number.isSafeInteger(commitIndex) || commitIndex < 0))
19
19
  throw new recordValidation_js_1.RecordRefusal();
20
20
  if ((read !== undefined && read !== true) || (read === true && key === undefined))
@@ -23,7 +23,7 @@ function readNodeIdentity(nodeId) {
23
23
  address,
24
24
  runtimeStageId,
25
25
  ...(commitIndex === undefined ? {} : { commitIdx: commitIndex }),
26
- ...(key === undefined ? {} : { key: (0, recordValidation_js_1.name)(key, true) }),
26
+ ...(key === undefined ? {} : { key: (0, recordValidation_js_1.recordName)(key, true) }),
27
27
  ...(read === true ? { read: true } : {}),
28
28
  };
29
29
  }
@@ -31,7 +31,7 @@ exports.readNodeIdentity = readNodeIdentity;
31
31
  /** Stable field order preserves existing address/execution/key IDs across storage and memory readers. */
32
32
  function nodeIdFor(addressInput, node, read) {
33
33
  try {
34
- const address = (0, recordValidation_js_1.addressOf)(addressInput), runtimeStageId = (0, recordValidation_js_1.name)((0, recordValidation_js_1.own)(node, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.own)(node, 'commitIdx'), key = (0, recordValidation_js_1.own)(node, 'key');
34
+ const address = (0, recordValidation_js_1.addressOf)(addressInput), runtimeStageId = (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(node, 'runtimeStageId')), commitIndex = (0, recordValidation_js_1.recordOwn)(node, 'commitIdx'), key = (0, recordValidation_js_1.recordOwn)(node, 'key');
35
35
  if (commitIndex !== undefined && (!Number.isSafeInteger(commitIndex) || commitIndex < 0))
36
36
  throw new recordValidation_js_1.RecordRefusal();
37
37
  const nodeId = 'record:' +
@@ -39,7 +39,7 @@ function nodeIdFor(addressInput, node, read) {
39
39
  address,
40
40
  runtimeStageId,
41
41
  ...(commitIndex === undefined ? {} : { commitIdx: commitIndex }),
42
- ...(key === undefined ? {} : { key: (0, recordValidation_js_1.name)(key, true) }),
42
+ ...(key === undefined ? {} : { key: (0, recordValidation_js_1.recordName)(key, true) }),
43
43
  ...(read ? { read: true } : {}),
44
44
  });
45
45
  return nodeId.length <= 2048 ? nodeId : 'record:invalid';
@@ -13,8 +13,8 @@ function admitLoadedScope(result, request, limits, state) {
13
13
  }
14
14
  let prepared;
15
15
  try {
16
- prepared = (0, recordScope_js_1.prepareRecordScope)((0, recordValidation_js_1.own)(result, 'scope'), request.address, limits.maxCommits, limits.maxFields);
17
- const extra = (0, recordValidation_js_1.list)((0, recordValidation_js_1.own)(result, 'gaps') ?? [], 32);
16
+ prepared = (0, recordScope_js_1.prepareRecordScope)((0, recordValidation_js_1.recordOwn)(result, 'scope'), request.address, limits.maxCommits, limits.maxFields);
17
+ const extra = (0, recordValidation_js_1.recordList)((0, recordValidation_js_1.recordOwn)(result, 'gaps') ?? [], 32);
18
18
  // Coverage belongs to this admitted object, so cached scopes retain the same gap ordering and ownership.
19
19
  state.extraGaps.set(prepared, (0, validation_js_1.gaps)(extra.map((code) => ({ code, evidence: [] }))).map((gap) => gap.code));
20
20
  }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.whenResolved = exports.createRecordQuery = void 0;
4
+ const queryMemo_js_1 = require("./queryMemo.js");
5
+ const recordIdentity_js_1 = require("./recordIdentity.js");
6
+ const recordInspection_js_1 = require("./recordInspection.js");
7
+ /** Both dependency directions share the same admitted node and canonical inspection within a query. */
8
+ function createRecordQuery(loader, maximumEdges) {
9
+ const resolutionOwner = {}, inspectionOwner = {};
10
+ return {
11
+ resolve(nodeId, context) {
12
+ const resolve = () => (0, recordIdentity_js_1.resolveRecordNode)(nodeId, context, loader), memo = (0, queryMemo_js_1.queryMemo)(context);
13
+ // A retained success must never bypass the loader's existing cancellation check.
14
+ return memo && !context.signal.aborted ? memo.remember(resolutionOwner, nodeId, resolve) : resolve();
15
+ },
16
+ inspect(node, context) {
17
+ const inspect = () => (0, recordInspection_js_1.inspectRecordNode)(node, maximumEdges, loader.extraGapCodes(node.scope));
18
+ return (0, queryMemo_js_1.queryMemo)(context)?.remember(inspectionOwner, node, inspect) ?? inspect();
19
+ },
20
+ };
21
+ }
22
+ exports.createRecordQuery = createRecordQuery;
23
+ /** Every port maps the same fixed loading failure while projecting only admitted nodes. */
24
+ function whenResolved(node, onNode, onFailure) {
25
+ return 'failure' in node ? onFailure(node) : onNode(node);
26
+ }
27
+ exports.whenResolved = whenResolved;
@@ -19,11 +19,11 @@ function recordOptions(options) {
19
19
  if (prototype !== Object.prototype && prototype !== null)
20
20
  throw new TypeError();
21
21
  return Object.freeze({
22
- maxCommits: boundedOption((0, recordValidation_js_1.own)(options, 'maxCommits'), 256, 4096),
23
- maxFields: boundedOption((0, recordValidation_js_1.own)(options, 'maxFields'), 20000, 1000000),
24
- maxEdges: boundedOption((0, recordValidation_js_1.own)(options, 'maxEdges'), 64, 256),
25
- maxScopes: boundedOption((0, recordValidation_js_1.own)(options, 'maxScopes'), 32, 256),
26
- loadTimeoutMs: boundedOption((0, recordValidation_js_1.own)(options, 'loadTimeoutMs'), 1000, 30000),
22
+ maxCommits: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxCommits'), 256, 4096),
23
+ maxFields: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxFields'), 20000, 1000000),
24
+ maxEdges: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxEdges'), 64, 256),
25
+ maxScopes: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'maxScopes'), 32, 256),
26
+ loadTimeoutMs: boundedOption((0, recordValidation_js_1.recordOwn)(options, 'loadTimeoutMs'), 1000, 30000),
27
27
  });
28
28
  }
29
29
  catch {
@@ -33,22 +33,22 @@ function recordOptions(options) {
33
33
  exports.recordOptions = recordOptions;
34
34
  /** Spend one shared field budget before canonical readers see any untrusted scope data. */
35
35
  function prepareRecordScope(value, address, maximumCommits, maximumFields) {
36
- if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.own)(value, 'address'))) !== (0, recordValidation_js_1.addressKey)(address))
36
+ if ((0, recordValidation_js_1.addressKey)((0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(value, 'address'))) !== (0, recordValidation_js_1.addressKey)(address))
37
37
  throw new recordValidation_js_1.RecordRefusal();
38
- const rawLog = (0, recordValidation_js_1.list)((0, recordValidation_js_1.own)(value, 'commitLog'), maximumCommits), budget = { left: maximumFields };
39
- const log = rawLog.map((_, commitIndex) => (0, recordValidation_js_1.bundleOf)((0, recordValidation_js_1.own)(rawLog, String(commitIndex)), commitIndex, budget));
40
- const reads = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.own)(value, 'reads'), maximumCommits, (value) => {
38
+ const rawLog = (0, recordValidation_js_1.recordList)((0, recordValidation_js_1.recordOwn)(value, 'commitLog'), maximumCommits), budget = { left: maximumFields };
39
+ const log = rawLog.map((_, commitIndex) => (0, recordValidation_js_1.bundleOf)((0, recordValidation_js_1.recordOwn)(rawLog, String(commitIndex)), commitIndex, budget));
40
+ const reads = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'reads'), maximumCommits, (value) => {
41
41
  const readKeys = (0, recordValidation_js_1.names)(value, 128, true);
42
42
  (0, recordValidation_js_1.spend)(budget, readKeys.length);
43
43
  return readKeys;
44
44
  }, budget);
45
- const control = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.own)(value, 'controlDeps'), maximumCommits, (value) => ({ deciderId: (0, recordValidation_js_1.name)((0, recordValidation_js_1.own)(value, 'deciderId')) }), budget);
46
- const marks = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.own)(value, 'attention'), maximumCommits, (value) => {
45
+ const control = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'controlDeps'), maximumCommits, (value) => ({ deciderId: (0, recordValidation_js_1.recordName)((0, recordValidation_js_1.recordOwn)(value, 'deciderId')) }), budget);
46
+ const marks = (0, recordValidation_js_1.mapOf)((0, recordValidation_js_1.recordOwn)(value, 'attention'), maximumCommits, (value) => {
47
47
  const attention = (0, recordValidation_js_1.marksOf)(value);
48
48
  (0, recordValidation_js_1.spend)(budget, attention.length + attention.reduce((count, mark) => count + mark.evidence.length, 0));
49
49
  return attention;
50
50
  }, budget);
51
- return { address, log, reads, control, marks, complete: (0, recordValidation_js_1.own)(value, 'complete') === true };
51
+ return { address, log, reads, control, marks, complete: (0, recordValidation_js_1.recordOwn)(value, 'complete') === true };
52
52
  }
53
53
  exports.prepareRecordScope = prepareRecordScope;
54
54
  /** Preserve both stage reads and stronger per-write prefixes, including their original encounter order. */
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.projectLoaded = exports.mapOf = exports.bundleOf = exports.dataCopy = exports.addressKey = exports.spend = exports.addressOf = exports.list = exports.name = exports.names = exports.own = exports.RecordRefusal = exports.marksOf = void 0;
3
+ exports.projectLoaded = exports.mapOf = exports.bundleOf = exports.dataCopy = exports.addressKey = exports.spend = exports.addressOf = exports.recordList = exports.recordName = exports.names = exports.recordOwn = exports.RecordRefusal = exports.marksOf = void 0;
4
4
  const validation_js_1 = require("./validation.js");
5
5
  Object.defineProperty(exports, "marksOf", { enumerable: true, get: function () { return validation_js_1.attention; } });
6
- const admission_js_1 = require("./admission.js");
6
+ const admission_js_1 = require("../evidence/admission.js");
7
7
  /** Loader refusals stay distinct from graph-port refusals so a failed host load keeps its original classification. */
8
8
  class RecordRefusal extends admission_js_1.EvidenceRefusal {
9
9
  code;
@@ -15,19 +15,19 @@ class RecordRefusal extends admission_js_1.EvidenceRefusal {
15
15
  exports.RecordRefusal = RecordRefusal;
16
16
  const refuseRecord = (code) => new RecordRefusal(code);
17
17
  const recordDescriptors = { translateTrapErrors: true, requireOwnValue: true };
18
- function own(value, key) {
18
+ function recordOwn(value, key) {
19
19
  return (0, admission_js_1.ownData)(value, key, refuseRecord, recordDescriptors);
20
20
  }
21
- exports.own = own;
21
+ exports.recordOwn = recordOwn;
22
22
  function names(value, maximum = 128, path = false) {
23
- return list(value, maximum).map((item) => name(item, path));
23
+ return recordList(value, maximum).map((item) => recordName(item, path));
24
24
  }
25
25
  exports.names = names;
26
- function name(value, path = false) {
26
+ function recordName(value, path = false) {
27
27
  return (0, admission_js_1.boundedName)(value, 1024, refuseRecord, path);
28
28
  }
29
- exports.name = name;
30
- function list(value, maximum) {
29
+ exports.recordName = recordName;
30
+ function recordList(value, maximum) {
31
31
  return (0, admission_js_1.boundedList)(value, maximum, (item) => item, {
32
32
  refuse: refuseRecord,
33
33
  overflow: 'node-limit',
@@ -35,9 +35,9 @@ function list(value, maximum) {
35
35
  descriptors: recordDescriptors,
36
36
  });
37
37
  }
38
- exports.list = list;
38
+ exports.recordList = recordList;
39
39
  function addressOf(value) {
40
- const logRunId = name(own(value, 'logRunId')), drillPath = names(own(value, 'drillPath'), 16);
40
+ const logRunId = recordName(recordOwn(value, 'logRunId')), drillPath = names(recordOwn(value, 'drillPath'), 16);
41
41
  if (logRunId.length + drillPath.reduce((n, s) => n + s.length, 0) > 1536)
42
42
  throw new RecordRefusal();
43
43
  return Object.freeze({ logRunId, drillPath: Object.freeze(drillPath) });
@@ -71,7 +71,7 @@ function dataCopy(value, budget) {
71
71
  if (!Array.isArray(v) && p !== Object.prototype && p !== null)
72
72
  throw new RecordRefusal();
73
73
  if (Array.isArray(v)) {
74
- const length = own(v, 'length');
74
+ const length = recordOwn(v, 'length');
75
75
  if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
76
76
  throw new RecordRefusal();
77
77
  spend(budget, length);
@@ -96,7 +96,7 @@ function dataCopy(value, budget) {
96
96
  for (const key of keys) {
97
97
  if (key.length > 1024)
98
98
  throw new RecordRefusal('node-limit');
99
- const v = own(from, key);
99
+ const v = recordOwn(from, key);
100
100
  check(v);
101
101
  let copy = v;
102
102
  if (!leaf(v)) {
@@ -113,16 +113,16 @@ function dataCopy(value, budget) {
113
113
  }
114
114
  exports.dataCopy = dataCopy;
115
115
  function bundleOf(value, idx, budget) {
116
- const runtimeStageId = name(own(value, 'runtimeStageId')), stageId = name(own(value, 'stageId'));
117
- const trace = list(own(value, 'trace'), 128).map((_, i) => {
118
- const t = own(own(value, 'trace'), String(i)), path = name(own(t, 'path'), true), verb = own(t, 'verb');
116
+ const runtimeStageId = recordName(recordOwn(value, 'runtimeStageId')), stageId = recordName(recordOwn(value, 'stageId'));
117
+ const trace = recordList(recordOwn(value, 'trace'), 128).map((_, i) => {
118
+ const t = recordOwn(recordOwn(value, 'trace'), String(i)), path = recordName(recordOwn(t, 'path'), true), verb = recordOwn(t, 'verb');
119
119
  if (!['set', 'merge', 'append', 'delete'].includes(verb))
120
120
  throw new RecordRefusal();
121
- const readKeys = own(t, 'readKeys');
121
+ const readKeys = recordOwn(t, 'readKeys');
122
122
  return { path, verb: verb, ...(readKeys === undefined ? {} : { readKeys: names(readKeys, 128, true) }) };
123
123
  });
124
124
  spend(budget, trace.length + trace.reduce((n, t) => n + (t.readKeys?.length ?? 0), 0) + 1);
125
- const overwrite = dataCopy(own(value, 'overwrite'), budget), updates = dataCopy(own(value, 'updates'), budget);
125
+ const overwrite = dataCopy(recordOwn(value, 'overwrite'), budget), updates = dataCopy(recordOwn(value, 'updates'), budget);
126
126
  if (!overwrite ||
127
127
  typeof overwrite !== 'object' ||
128
128
  Array.isArray(overwrite) ||
@@ -130,9 +130,9 @@ function bundleOf(value, idx, budget) {
130
130
  typeof updates !== 'object' ||
131
131
  Array.isArray(updates))
132
132
  throw new RecordRefusal();
133
- const redactedPaths = names(own(value, 'redactedPaths') ?? [], 128, true);
134
- const untracked = own(value, 'untrackedSources'), phase = own(value, 'phase');
135
- spend(budget, redactedPaths.length + (untracked === undefined ? 0 : list(untracked, 128).length));
133
+ const redactedPaths = names(recordOwn(value, 'redactedPaths') ?? [], 128, true);
134
+ const untracked = recordOwn(value, 'untrackedSources'), phase = recordOwn(value, 'phase');
135
+ spend(budget, redactedPaths.length + (untracked === undefined ? 0 : recordList(untracked, 128).length));
136
136
  return {
137
137
  idx,
138
138
  stage: stageId,
@@ -179,7 +179,7 @@ function mapOf(value, limit, read, budget) {
179
179
  throw new RecordRefusal('node-limit');
180
180
  if (budget)
181
181
  spend(budget, keys.length);
182
- return new Map(keys.map((k) => [name(k), read(own(value, k))]));
182
+ return new Map(keys.map((k) => [recordName(k), read(recordOwn(value, k))]));
183
183
  }
184
184
  exports.mapOf = mapOf;
185
185
  /** Observe native promises by intrinsic without assimilating a data object's then accessor. */
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Session = void 0;
4
4
  const validation_js_1 = require("./validation.js");
5
+ const queryMemo_js_1 = require("./queryMemo.js");
5
6
  const defaults = { maxNodes: 100, maxDepth: 20, maxEdges: 1000, maxCalls: 1000, timeoutMs: 1000 };
6
7
  const ceilings = { maxNodes: 10000, maxDepth: 1000, maxEdges: 100000, maxCalls: 100000, timeoutMs: 30000 };
7
8
  /** One deadline, memo table and work budget per public query, never per graph or store. */
@@ -24,7 +25,7 @@ class Session {
24
25
  (0, validation_js_1.plain)(options);
25
26
  const limits = { ...defaults };
26
27
  for (const key of Object.keys(defaults)) {
27
- const value = (0, validation_js_1.own)(options, key);
28
+ const value = (0, validation_js_1.graphOwn)(options, key);
28
29
  if (value !== undefined) {
29
30
  if (typeof value !== 'number' ||
30
31
  !Number.isSafeInteger(value) ||
@@ -35,13 +36,13 @@ class Session {
35
36
  }
36
37
  }
37
38
  this.limits = Object.freeze(limits);
38
- const rank = (0, validation_js_1.own)(options, 'rankRoots');
39
+ const rank = (0, validation_js_1.graphOwn)(options, 'rankRoots');
39
40
  if (rank !== undefined && typeof rank !== 'function')
40
41
  throw new TypeError();
41
- const impactRank = (0, validation_js_1.own)(options, 'rankImpact');
42
+ const impactRank = (0, validation_js_1.graphOwn)(options, 'rankImpact');
42
43
  if (impactRank !== undefined && typeof impactRank !== 'function')
43
44
  throw new TypeError();
44
- const signal = (0, validation_js_1.own)(options, 'signal');
45
+ const signal = (0, validation_js_1.graphOwn)(options, 'signal');
45
46
  if (signal !== undefined && !(signal instanceof AbortSignal))
46
47
  throw new TypeError();
47
48
  this.external = signal;
@@ -74,8 +75,10 @@ class Session {
74
75
  this.timedOut = true;
75
76
  this.controller.abort();
76
77
  }, this.limits.timeoutMs);
78
+ (0, queryMemo_js_1.beginQueryMemo)(this.context, this.limits.maxNodes);
77
79
  }
78
80
  dispose() {
81
+ (0, queryMemo_js_1.endQueryMemo)(this.context);
79
82
  clearTimeout(this.timer);
80
83
  this.external?.removeEventListener('abort', this.onAbort);
81
84
  }
@@ -88,7 +91,7 @@ class Session {
88
91
  return this.controller.signal.aborted ? (0, validation_js_1.gap)(this.timedOut ? 'timeout' : 'cancelled', id) : undefined;
89
92
  }
90
93
  admit(id) {
91
- (0, validation_js_1.name)(id);
94
+ (0, validation_js_1.graphName)(id);
92
95
  if (this.nodes.has(id))
93
96
  return undefined;
94
97
  if (this.nodes.size >= this.limits.maxNodes)
@@ -9,26 +9,32 @@ function createStoredRecordGraph(host, options = {}) {
9
9
  const limits = (0, recordAdapter_js_1.recordOptions)(options);
10
10
  return (0, recordAdapter_js_1.createLazyRecordGraph)((address, context) => (0, recordValidation_js_1.projectLoaded)(() => host.loadLog(address, context), (loaded) => {
11
11
  const max = limits.maxCommits, budget = { left: limits.maxFields };
12
- const raw = (0, recordValidation_js_1.list)((0, recordValidation_js_1.own)(loaded, 'entries'), max * 4 + 16), entries = [];
12
+ const raw = (0, recordValidation_js_1.recordList)((0, recordValidation_js_1.recordOwn)(loaded, 'entries'), max * 4 + 16), entries = [];
13
13
  for (let i = 0; i < raw.length; i++) {
14
14
  if (context.signal.aborted)
15
15
  throw new recordValidation_js_1.RecordRefusal('cancelled');
16
- const entry = (0, recordValidation_js_1.own)(raw, String(i)), a = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.own)(entry, 'address'));
16
+ const entry = (0, recordValidation_js_1.recordOwn)(raw, String(i)), a = (0, recordValidation_js_1.addressOf)((0, recordValidation_js_1.recordOwn)(entry, 'address'));
17
17
  if ((0, recordValidation_js_1.addressKey)(a) !== (0, recordValidation_js_1.addressKey)(address))
18
18
  throw new recordValidation_js_1.RecordRefusal();
19
- const kind = (0, recordValidation_js_1.own)(entry, 'kind'), at = (0, recordValidation_js_1.own)(entry, 'at');
19
+ const kind = (0, recordValidation_js_1.recordOwn)(entry, 'kind'), at = (0, recordValidation_js_1.recordOwn)(entry, 'at');
20
20
  if (typeof at !== 'number' || !Number.isFinite(at))
21
21
  throw new recordValidation_js_1.RecordRefusal();
22
22
  if (kind === 'commit') {
23
- const b = (0, recordValidation_js_1.own)(entry, 'bundle'), idx = (0, recordValidation_js_1.own)(b, 'idx');
23
+ const b = (0, recordValidation_js_1.recordOwn)(entry, 'bundle'), idx = (0, recordValidation_js_1.recordOwn)(b, 'idx');
24
24
  if (!Number.isSafeInteger(idx) || idx < 0 || idx >= max)
25
25
  throw new recordValidation_js_1.RecordRefusal('node-limit');
26
26
  entries.push({ kind, address: a, at, bundle: (0, recordValidation_js_1.bundleOf)(b, idx, budget) });
27
27
  }
28
28
  else if (kind === 'opened')
29
- entries.push({ kind, address: a, at, initialState: (0, recordValidation_js_1.dataCopy)((0, recordValidation_js_1.own)(entry, 'initialState'), budget) });
29
+ entries.push({ kind, address: a, at, initialState: (0, recordValidation_js_1.dataCopy)((0, recordValidation_js_1.recordOwn)(entry, 'initialState'), budget) });
30
30
  else if (kind === 'closed')
31
- entries.push({ kind, address: a, at, outcome: (0, recordValidation_js_1.own)(entry, 'outcome'), commits: (0, recordValidation_js_1.own)(entry, 'commits') });
31
+ entries.push({
32
+ kind,
33
+ address: a,
34
+ at,
35
+ outcome: (0, recordValidation_js_1.recordOwn)(entry, 'outcome'),
36
+ commits: (0, recordValidation_js_1.recordOwn)(entry, 'commits'),
37
+ });
32
38
  else if (kind === 'note') {
33
39
  /* opaque note bodies never enter dependency projection */
34
40
  }
@@ -49,9 +55,9 @@ function createStoredRecordGraph(host, options = {}) {
49
55
  scope: {
50
56
  address,
51
57
  commitLog: log.commitLog,
52
- reads: (0, recordValidation_js_1.own)(loaded, 'reads'),
53
- controlDeps: (0, recordValidation_js_1.own)(loaded, 'controlDeps'),
54
- attention: (0, recordValidation_js_1.own)(loaded, 'attention'),
58
+ reads: (0, recordValidation_js_1.recordOwn)(loaded, 'reads'),
59
+ controlDeps: (0, recordValidation_js_1.recordOwn)(loaded, 'controlDeps'),
60
+ attention: (0, recordValidation_js_1.recordOwn)(loaded, 'attention'),
55
61
  complete: log.complete,
56
62
  },
57
63
  gaps: record.unread.length || log.gaps.length ? ['not-collected'] : [],