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
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uniqueGaps = exports.gap = exports.nodeIds = exports.adjacency = exports.gaps = exports.attention = exports.refs = exports.list = exports.name = exports.plain = exports.own = exports.observePromise = exports.AdmissionError = void 0;
4
- const admission_js_1 = require("./admission.js");
3
+ exports.uniqueGaps = exports.gap = exports.nodeIds = exports.adjacency = exports.gaps = exports.attention = exports.refs = exports.graphList = exports.graphName = exports.plain = exports.graphOwn = exports.observePromise = exports.AdmissionError = void 0;
4
+ const admission_js_1 = require("../evidence/admission.js");
5
+ const codes_js_1 = require("../evidence/codes.js");
5
6
  /** Graph-port refusals carry their code through Session; loader refusals are handled at the record boundary. */
6
7
  class AdmissionError extends admission_js_1.EvidenceRefusal {
7
8
  code;
@@ -32,20 +33,20 @@ function observePromise(raw, accept, reject) {
32
33
  exports.observePromise = observePromise;
33
34
  const refuseGraph = (code) => new AdmissionError(code);
34
35
  const graphDescriptors = { translateTrapErrors: false, requireOwnValue: false };
35
- function own(value, key) {
36
+ function graphOwn(value, key) {
36
37
  return (0, admission_js_1.ownData)(value, key, refuseGraph, graphDescriptors);
37
38
  }
38
- exports.own = own;
39
+ exports.graphOwn = graphOwn;
39
40
  function plain(value) {
40
41
  if (!value || typeof value !== 'object' || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
41
42
  throw new AdmissionError();
42
43
  }
43
44
  exports.plain = plain;
44
- function name(value, maximum = 2048) {
45
+ function graphName(value, maximum = 2048) {
45
46
  return (0, admission_js_1.boundedName)(value, maximum, refuseGraph);
46
47
  }
47
- exports.name = name;
48
- function list(value, maximum, read, overflow = 'invalid-data') {
48
+ exports.graphName = graphName;
49
+ function graphList(value, maximum, read, overflow = 'invalid-data') {
49
50
  return (0, admission_js_1.boundedList)(value, maximum, read, {
50
51
  refuse: refuseGraph,
51
52
  overflow,
@@ -53,7 +54,7 @@ function list(value, maximum, read, overflow = 'invalid-data') {
53
54
  descriptors: graphDescriptors,
54
55
  });
55
56
  }
56
- exports.list = list;
57
+ exports.graphList = graphList;
57
58
  const reasons = new Set([
58
59
  'ERROR_RECORDED',
59
60
  'UNKNOWN_EFFECT_RECORDED',
@@ -65,36 +66,18 @@ const reasons = new Set([
65
66
  'OUTLIER_RECORDED',
66
67
  'BUSINESS_RULE_MATCHED',
67
68
  ]);
68
- const codes = new Set([
69
- 'not-collected',
70
- 'untracked-input',
71
- 'redacted',
72
- 'conservative',
73
- 'scope-boundary',
74
- 'invalid-data',
75
- 'unavailable',
76
- 'timeout',
77
- 'cancelled',
78
- 'cycle',
79
- 'node-limit',
80
- 'depth-limit',
81
- 'edge-limit',
82
- 'call-limit',
83
- 'truncated',
84
- 'strategy-failed',
85
- ]);
86
- const refs = (value) => list(value, 16, (item) => name(item, 512));
69
+ const refs = (value) => graphList(value, 16, (item) => graphName(item, 512));
87
70
  exports.refs = refs;
88
71
  function attention(value) {
89
- return list(value, 32, (item) => {
72
+ return graphList(value, 32, (item) => {
90
73
  plain(item);
91
- const kind = own(item, 'kind'), reason = own(item, 'reason');
74
+ const kind = graphOwn(item, 'kind'), reason = graphOwn(item, 'reason');
92
75
  if (typeof kind !== 'string' ||
93
76
  !/^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(kind) ||
94
77
  typeof reason !== 'string' ||
95
78
  !reasons.has(reason))
96
79
  throw new AdmissionError();
97
- const evidence = (0, exports.refs)(own(item, 'evidence'));
80
+ const evidence = (0, exports.refs)(graphOwn(item, 'evidence'));
98
81
  if (kind !== 'not-collected' && evidence.length === 0)
99
82
  throw new AdmissionError();
100
83
  return Object.freeze({ kind, reason: reason, evidence });
@@ -102,38 +85,38 @@ function attention(value) {
102
85
  }
103
86
  exports.attention = attention;
104
87
  function gaps(value) {
105
- return list(value, 32, (item) => {
88
+ return graphList(value, 32, (item) => {
106
89
  plain(item);
107
- const code = own(item, 'code'), nodeId = own(item, 'nodeId');
108
- if (typeof code !== 'string' || !codes.has(code))
90
+ const code = graphOwn(item, 'code'), nodeId = graphOwn(item, 'nodeId');
91
+ if (!(0, codes_js_1.isGapCode)(code))
109
92
  throw new AdmissionError();
110
93
  return Object.freeze({
111
94
  code: code,
112
- ...(nodeId === undefined ? {} : { nodeId: name(nodeId) }),
113
- evidence: (0, exports.refs)(own(item, 'evidence')),
95
+ ...(nodeId === undefined ? {} : { nodeId: graphName(nodeId) }),
96
+ evidence: (0, exports.refs)(graphOwn(item, 'evidence')),
114
97
  });
115
98
  });
116
99
  }
117
100
  exports.gaps = gaps;
118
101
  function adjacency(value, maximum) {
119
102
  plain(value);
120
- const complete = own(value, 'complete');
103
+ const complete = graphOwn(value, 'complete');
121
104
  if (typeof complete !== 'boolean')
122
105
  throw new AdmissionError();
123
- const edges = list(own(value, 'edges'), maximum, (item) => {
106
+ const edges = graphList(graphOwn(value, 'edges'), maximum, (item) => {
124
107
  plain(item);
125
- const nodeId = name(own(item, 'nodeId')), kind = own(item, 'kind'), attribution = own(item, 'attribution');
108
+ const nodeId = graphName(graphOwn(item, 'nodeId')), kind = graphOwn(item, 'kind'), attribution = graphOwn(item, 'attribution');
126
109
  if ((kind !== 'data' && kind !== 'control') ||
127
110
  (attribution !== 'per-write' && attribution !== 'stage' && attribution !== 'recorded-control') ||
128
111
  (kind === 'control' && attribution !== 'recorded-control') ||
129
112
  (kind === 'data' && attribution === 'recorded-control'))
130
113
  throw new AdmissionError();
131
- return Object.freeze({ nodeId, kind, attribution, evidence: (0, exports.refs)(own(item, 'evidence')) });
114
+ return Object.freeze({ nodeId, kind, attribution, evidence: (0, exports.refs)(graphOwn(item, 'evidence')) });
132
115
  }, 'edge-limit');
133
116
  return Object.freeze({ edges, complete });
134
117
  }
135
118
  exports.adjacency = adjacency;
136
- const nodeIds = (value, max) => list(value, max, (item) => name(item), 'node-limit');
119
+ const nodeIds = (value, max) => graphList(value, max, (item) => graphName(item), 'node-limit');
137
120
  exports.nodeIds = nodeIds;
138
121
  const gap = (code, nodeId) => Object.freeze({ code, ...(nodeId === undefined ? {} : { nodeId }), evidence: Object.freeze([]) });
139
122
  exports.gap = gap;
@@ -45,11 +45,24 @@ exports.boundedName = boundedName;
45
45
  /** Bound iteration before reading entries, without invoking element accessors. */
46
46
  function boundedList(value, maximum, read, options) {
47
47
  const { refuse, overflow, freeze, descriptors } = options;
48
- if (!Array.isArray(value))
48
+ let array;
49
+ if (options.translateArrayErrors) {
50
+ try {
51
+ array = Array.isArray(value);
52
+ }
53
+ catch {
54
+ throw refuse();
55
+ }
56
+ }
57
+ else
58
+ array = Array.isArray(value);
59
+ if (!array)
49
60
  throw refuse();
50
61
  const length = ownData(value, 'length', refuse, descriptors);
51
62
  if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
52
63
  throw refuse();
64
+ if (options.expectedLength !== undefined && length !== options.expectedLength)
65
+ throw refuse();
53
66
  if (length > maximum)
54
67
  throw refuse(overflow);
55
68
  const result = [];
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRequirementReason = exports.isGapCode = exports.GAP_CODES = void 0;
4
+ /** One vocabulary; true marks a domain evidence reason, false a trace/admission gap only. */
5
+ exports.GAP_CODES = Object.freeze({
6
+ 'not-collected': true,
7
+ 'untracked-input': false,
8
+ redacted: true,
9
+ conservative: false,
10
+ 'scope-boundary': false,
11
+ 'invalid-data': true,
12
+ unavailable: true,
13
+ timeout: true,
14
+ cancelled: false,
15
+ cycle: false,
16
+ 'node-limit': false,
17
+ 'depth-limit': false,
18
+ 'edge-limit': false,
19
+ 'call-limit': false,
20
+ truncated: false,
21
+ 'strategy-failed': false,
22
+ 'not-checked': true,
23
+ 'no-match': true,
24
+ ambiguous: true,
25
+ stale: true,
26
+ incompatible: true,
27
+ unsupported: true,
28
+ 'not-permitted': true,
29
+ });
30
+ const isGapCode = (value) => typeof value === 'string' && Object.hasOwn(exports.GAP_CODES, value);
31
+ exports.isGapCode = isGapCode;
32
+ const isRequirementReason = (value) => (0, exports.isGapCode)(value) && exports.GAP_CODES[value];
33
+ exports.isRequirementReason = isRequirementReason;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readRequirementResults = exports.RequirementValidationError = exports.REQUIREMENT_RESULT_LIMITS = void 0;
4
+ const admission_js_1 = require("./admission.js");
5
+ const codes_js_1 = require("./codes.js");
6
+ /** Fixed per-call ceilings; characters are UTF-16 code units, not serialized transport bytes. */
7
+ exports.REQUIREMENT_RESULT_LIMITS = Object.freeze({
8
+ results: 512,
9
+ checks: 16,
10
+ affects: 32,
11
+ refs: 16,
12
+ name: 512,
13
+ fields: 32768,
14
+ characters: 1048576,
15
+ });
16
+ /** No input, field value or originating exception is retained on a refusal. */
17
+ class RequirementValidationError extends admission_js_1.EvidenceRefusal {
18
+ constructor(code = 'invalid-data') {
19
+ super(code, 'REQUIREMENT_RESULTS_INVALID');
20
+ }
21
+ }
22
+ exports.RequirementValidationError = RequirementValidationError;
23
+ const refuse = (code) => new RequirementValidationError(code);
24
+ const descriptors = { translateTrapErrors: true, requireOwnValue: true };
25
+ const own = (value, key) => (0, admission_js_1.ownData)(value, key, refuse, descriptors);
26
+ const resultKeys = new Set([
27
+ 'id',
28
+ 'requirementRef',
29
+ 'findingRef',
30
+ 'windowRef',
31
+ 'affects',
32
+ 'state',
33
+ 'reason',
34
+ 'detail',
35
+ 'evidenceRefs',
36
+ 'checks',
37
+ 'actionRefs',
38
+ 'validTimeRef',
39
+ 'learnedTimeRef',
40
+ ]);
41
+ const checkKeys = new Set(['checkRef', 'disposition', 'reason', 'detail', 'evidenceRefs', 'attemptRefs']);
42
+ const dispositions = new Set([
43
+ 'checked-pass',
44
+ 'checked-fail',
45
+ 'unreachable',
46
+ 'not-applicable',
47
+ ]);
48
+ /** Closed objects expose no unknown payloads. Never invoke data accessors, iterators or toJSON. */
49
+ function object(value, keys, budget) {
50
+ if (!value || typeof value !== 'object')
51
+ throw refuse();
52
+ let prototype;
53
+ let fields;
54
+ try {
55
+ prototype = Object.getPrototypeOf(value);
56
+ fields = Reflect.ownKeys(value);
57
+ }
58
+ catch {
59
+ throw refuse();
60
+ }
61
+ if (prototype !== Object.prototype && prototype !== null)
62
+ throw refuse();
63
+ if (fields.length > keys.size || fields.some((field) => typeof field !== 'string' || !keys.has(field)))
64
+ throw refuse();
65
+ (0, admission_js_1.spendFields)(budget, fields.length, refuse);
66
+ // Including optional own fields: an own accessor is never treated as an absent field.
67
+ for (const field of fields)
68
+ own(value, field);
69
+ }
70
+ function list(value, maximum, read, budget) {
71
+ try {
72
+ if (!Array.isArray(value))
73
+ throw refuse();
74
+ }
75
+ catch {
76
+ throw refuse();
77
+ }
78
+ const length = own(value, 'length');
79
+ if (typeof length !== 'number' || !Number.isSafeInteger(length) || length < 0)
80
+ throw refuse();
81
+ if (length > maximum)
82
+ throw refuse('node-limit');
83
+ let prototype;
84
+ let keys;
85
+ try {
86
+ prototype = Object.getPrototypeOf(value);
87
+ keys = Reflect.ownKeys(value);
88
+ }
89
+ catch {
90
+ throw refuse();
91
+ }
92
+ if (prototype !== Array.prototype)
93
+ throw refuse();
94
+ if (keys.length !== length + 1 ||
95
+ keys.some((key) => key !== 'length' && (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key) || Number(key) >= length)))
96
+ throw refuse();
97
+ (0, admission_js_1.spendFields)(budget, length + 1, refuse);
98
+ return (0, admission_js_1.boundedList)(value, maximum, read, {
99
+ refuse,
100
+ overflow: 'node-limit',
101
+ freeze: true,
102
+ descriptors,
103
+ expectedLength: length,
104
+ translateArrayErrors: true,
105
+ });
106
+ }
107
+ function name(value, budget) {
108
+ const result = (0, admission_js_1.boundedName)(value, exports.REQUIREMENT_RESULT_LIMITS.name, refuse);
109
+ if (/\s/u.test(result))
110
+ throw refuse();
111
+ budget.characters -= result.length;
112
+ if (budget.characters < 0)
113
+ throw refuse('node-limit');
114
+ return result;
115
+ }
116
+ function unique(items, key) {
117
+ if (new Set(items.map(key)).size !== items.length)
118
+ throw refuse();
119
+ return items;
120
+ }
121
+ function refs(value, budget, maximum = exports.REQUIREMENT_RESULT_LIMITS.refs) {
122
+ return unique(list(value, maximum, (item) => name(item, budget), budget), (item) => item);
123
+ }
124
+ function reason(value) {
125
+ if (!(0, codes_js_1.isRequirementReason)(value))
126
+ throw refuse();
127
+ return value;
128
+ }
129
+ function optionalName(value, key, budget) {
130
+ const raw = own(value, key);
131
+ return raw === undefined ? undefined : name(raw, budget);
132
+ }
133
+ function detail(value, budget) {
134
+ const id = optionalName(value, 'detail', budget);
135
+ if (id !== undefined && !/^[A-Za-z][A-Za-z0-9_.-]*:.+$/.test(id))
136
+ throw refuse();
137
+ return id;
138
+ }
139
+ function check(value, budget) {
140
+ object(value, checkKeys, budget);
141
+ const checkRef = name(own(value, 'checkRef'), budget), disposition = own(value, 'disposition');
142
+ if (typeof disposition !== 'string' || !dispositions.has(disposition))
143
+ throw refuse();
144
+ const rawReason = own(value, 'reason'), detailId = detail(value, budget);
145
+ return Object.freeze({
146
+ checkRef,
147
+ disposition: disposition,
148
+ ...(rawReason === undefined ? {} : { reason: reason(rawReason) }),
149
+ ...(detailId === undefined ? {} : { detail: detailId }),
150
+ evidenceRefs: refs(own(value, 'evidenceRefs'), budget),
151
+ attemptRefs: refs(own(value, 'attemptRefs'), budget),
152
+ });
153
+ }
154
+ function result(value, budget) {
155
+ object(value, resultKeys, budget);
156
+ const id = name(own(value, 'id'), budget), requirementRef = name(own(value, 'requirementRef'), budget), findingRef = name(own(value, 'findingRef'), budget), windowRef = name(own(value, 'windowRef'), budget), state = own(value, 'state'), rawReason = own(value, 'reason');
157
+ if (state !== 'satisfied' && state !== 'unresolved')
158
+ throw refuse();
159
+ if (state === 'satisfied' && rawReason !== undefined)
160
+ throw refuse();
161
+ const affects = refs(own(value, 'affects'), budget, exports.REQUIREMENT_RESULT_LIMITS.affects);
162
+ if (!affects.length)
163
+ throw refuse();
164
+ const evidenceRefs = refs(own(value, 'evidenceRefs'), budget), checks = unique(list(own(value, 'checks'), exports.REQUIREMENT_RESULT_LIMITS.checks, (item) => check(item, budget), budget), (item) => item.checkRef), actionRefs = refs(own(value, 'actionRefs'), budget), detailId = detail(value, budget), validTimeRef = optionalName(value, 'validTimeRef', budget), learnedTimeRef = optionalName(value, 'learnedTimeRef', budget);
165
+ const binding = {
166
+ id,
167
+ requirementRef,
168
+ findingRef,
169
+ windowRef,
170
+ affects,
171
+ evidenceRefs,
172
+ checks,
173
+ actionRefs,
174
+ ...(detailId === undefined ? {} : { detail: detailId }),
175
+ ...(validTimeRef === undefined ? {} : { validTimeRef }),
176
+ ...(learnedTimeRef === undefined ? {} : { learnedTimeRef }),
177
+ };
178
+ return Object.freeze(state === 'unresolved' ? { ...binding, state, reason: reason(rawReason) } : { ...binding, state });
179
+ }
180
+ /**
181
+ * Atomically project detached, frozen reference-only records. This is structural admission only.
182
+ * The host must authenticate producers, resolve authorized artifacts, verify current query/run/scope and
183
+ * domain validity, and enforce every unresolved affects reference before rendering any factual claim.
184
+ * Identifier grammar does not classify secrets; producers must supply non-secret identifiers only.
185
+ */
186
+ function readRequirementResults(value) {
187
+ const budget = { left: exports.REQUIREMENT_RESULT_LIMITS.fields, characters: exports.REQUIREMENT_RESULT_LIMITS.characters };
188
+ return unique(list(value, exports.REQUIREMENT_RESULT_LIMITS.results, (item) => result(item, budget), budget), (item) => item.id);
189
+ }
190
+ exports.readRequirementResults = readRequirementResults;
@@ -30,3 +30,7 @@ export { deepEqual } from './lib/memory/equality.js';
30
30
  export { serveRecord } from './lib/capture/freeze.js';
31
31
  /** Record attention types are shared with producers; the optional cause reader has its own door. */
32
32
  export type { Attention, AttentionKind } from './lib/cause/types.js';
33
+ /** Reference-only requirement records: structural admission never grants authority or verifies domain truth. */
34
+ export type { RequirementReason } from './lib/evidence/codes.js';
35
+ export type { RequirementCheck, RequirementCheckDisposition, RequirementResult, } from './lib/evidence/requirementTypes.js';
36
+ export { readRequirementResults, RequirementValidationError, REQUIREMENT_RESULT_LIMITS, } from './lib/evidence/requirements.js';
@@ -0,0 +1,18 @@
1
+ import type { GraphContext } from './types.js';
2
+ /** Share bounded derived work within one query without retaining it in the graph's storage cache. */
3
+ declare class QueryMemo {
4
+ private readonly maximumEntries;
5
+ private readonly owners;
6
+ private entries;
7
+ private closed;
8
+ constructor(maximumEntries: number);
9
+ remember<T>(owner: object, key: unknown, create: () => T): T;
10
+ close(): void;
11
+ }
12
+ /** Reserve one resolution and one inspection per admitted node, shared across all adapter owners. */
13
+ export declare function beginQueryMemo(context: GraphContext, maximumNodes: number): void;
14
+ /** Direct graph calls have no managed query lifetime and deliberately remain uncached. */
15
+ export declare function queryMemo(context: GraphContext): QueryMemo | undefined;
16
+ /** Clear synchronously without aborting an otherwise successful query's public signal. */
17
+ export declare function endQueryMemo(context: GraphContext): void;
18
+ export {};
@@ -1,4 +1,4 @@
1
- import type { ResolvedRecordNode } from './recordTypes.js';
2
- import type { Adjacency, Gap } from './types.js';
1
+ import type { RecordInspection, ResolvedRecordNode } from './recordTypes.js';
2
+ import type { Adjacency } from './types.js';
3
3
  /** Share parent-side coverage checks before appending data then control children in their established order. */
4
- export declare function childrenForRecordNode(node: ResolvedRecordNode, maximumEdges: number, extraGapCodes: readonly Gap['code'][] | undefined): Adjacency;
4
+ export declare function childrenForRecordNode(node: ResolvedRecordNode, maximumEdges: number, inspection: RecordInspection): Adjacency;
@@ -1,5 +1,5 @@
1
1
  import type { CommitBundle } from '../memory/types.js';
2
- import type { AddRecordGap, PreparedRecordScope, RecordIdentity, RecordLoadFailure, ResolvedRecordNode } from './recordTypes.js';
2
+ import type { AddRecordGap, PreparedRecordScope, RecordIdentity, ResolvedRecordNode } from './recordTypes.js';
3
3
  import type { Attention, Gap } from './types.js';
4
4
  /** Preserve first-observed coverage order while collapsing repeated codes from different evidence paths. */
5
5
  export declare function recordGapCollector(): {
@@ -9,7 +9,7 @@ export declare function recordGapCollector(): {
9
9
  /** Failed loading exposes a fixed category, never the host error or an apparently complete empty graph. */
10
10
  export declare function gapForRecordFailure(code: Gap['code']): readonly Gap[];
11
11
  /** Return captured mark references without treating an omitted attention map as collected evidence. */
12
- export declare function attentionForRecordNode(node: ResolvedRecordNode | RecordLoadFailure): readonly Attention[];
12
+ export declare function attentionForRecordNode(node: ResolvedRecordNode): readonly Attention[];
13
13
  /** Emit host and capture gaps before query-derived gaps so existing evidence order stays stable. */
14
14
  export declare function collectScopeCoverage(scope: PreparedRecordScope, bundle: CommitBundle, extraGapCodes: readonly Gap['code'][] | undefined, addGap: AddRecordGap): void;
15
15
  /** A read-only identity has no new value life; unqualified executions retain written-key encounter order. */
@@ -0,0 +1,9 @@
1
+ import type { RecordLoadFailure, RecordScopeLoader, ResolvedRecordNode } from './recordTypes.js';
2
+ import type { GraphContext, NodeId } from './types.js';
3
+ /** Both dependency directions share the same admitted node and canonical inspection within a query. */
4
+ export declare function createRecordQuery(loader: RecordScopeLoader, maximumEdges: number): {
5
+ resolve(nodeId: NodeId, context: GraphContext): Promise<RecordLoadFailure | ResolvedRecordNode>;
6
+ inspect(node: ResolvedRecordNode, context: GraphContext): import("./recordTypes.js").RecordInspection;
7
+ };
8
+ /** Every port maps the same fixed loading failure while projecting only admitted nodes. */
9
+ export declare function whenResolved<T>(node: ResolvedRecordNode | RecordLoadFailure, onNode: (node: ResolvedRecordNode) => T, onFailure: (failure: RecordLoadFailure) => T): T;
@@ -3,17 +3,17 @@ import type { LogAddress } from '../memory/eventPosition.js';
3
3
  import type { CommitBundle } from '../memory/types.js';
4
4
  import type { GapCode } from './types.js';
5
5
  import { attention as marksOf } from './validation.js';
6
- import { EvidenceRefusal } from './admission.js';
6
+ import { EvidenceRefusal } from '../evidence/admission.js';
7
7
  export { marksOf };
8
8
  /** Loader refusals stay distinct from graph-port refusals so a failed host load keeps its original classification. */
9
9
  export declare class RecordRefusal extends EvidenceRefusal {
10
10
  readonly code: GapCode;
11
11
  constructor(code?: GapCode);
12
12
  }
13
- export declare function own(value: unknown, key: string): unknown;
13
+ export declare function recordOwn(value: unknown, key: string): unknown;
14
14
  export declare function names(value: unknown, maximum?: number, path?: boolean): string[];
15
- export declare function name(value: unknown, path?: boolean): string;
16
- export declare function list(value: unknown, maximum: number): readonly unknown[];
15
+ export declare function recordName(value: unknown, path?: boolean): string;
16
+ export declare function recordList(value: unknown, maximum: number): readonly unknown[];
17
17
  export declare function addressOf(value: unknown): LogAddress;
18
18
  export declare function spend(budget: {
19
19
  left: number;
@@ -1,3 +1,5 @@
1
+ import type { GapCode } from '../evidence/codes.js';
2
+ export type { GapCode } from '../evidence/codes.js';
1
3
  /** Names and evidence references only. No state values, messages, credentials or business payloads. */
2
4
  export type NodeId = string;
3
5
  export type AttentionKind = 'error' | 'unknown-effect' | 'gave-up' | 'timeout' | 'retried' | 'quality-drop' | 'not-collected' | 'outlier' | (string & {});
@@ -8,7 +10,6 @@ export interface Attention {
8
10
  readonly evidence: readonly string[];
9
11
  }
10
12
  export type Confidence = 'complete' | 'incomplete';
11
- export type GapCode = 'not-collected' | 'untracked-input' | 'redacted' | 'conservative' | 'scope-boundary' | 'invalid-data' | 'unavailable' | 'timeout' | 'cancelled' | 'cycle' | 'node-limit' | 'depth-limit' | 'edge-limit' | 'call-limit' | 'truncated' | 'strategy-failed';
12
13
  export interface Gap {
13
14
  readonly code: GapCode;
14
15
  readonly nodeId?: NodeId;
@@ -1,5 +1,5 @@
1
1
  import type { Adjacency, Attention, Gap, GapCode, NodeId } from './types.js';
2
- import { EvidenceRefusal } from './admission.js';
2
+ import { EvidenceRefusal } from '../evidence/admission.js';
3
3
  /** Graph-port refusals carry their code through Session; loader refusals are handled at the record boundary. */
4
4
  export declare class AdmissionError extends EvidenceRefusal {
5
5
  readonly code: GapCode;
@@ -11,10 +11,10 @@ export declare class AdmissionError extends EvidenceRefusal {
11
11
  * Exotic wrappers remain the trusted host's responsibility, including rejection handling.
12
12
  */
13
13
  export declare function observePromise(raw: unknown, accept: (raw: unknown) => void, reject: (reason: unknown) => void): boolean;
14
- export declare function own(value: unknown, key: string): unknown;
14
+ export declare function graphOwn(value: unknown, key: string): unknown;
15
15
  export declare function plain(value: unknown): void;
16
- export declare function name(value: unknown, maximum?: number): string;
17
- export declare function list<T>(value: unknown, maximum: number, read: (item: unknown) => T, overflow?: GapCode): readonly T[];
16
+ export declare function graphName(value: unknown, maximum?: number): string;
17
+ export declare function graphList<T>(value: unknown, maximum: number, read: (item: unknown) => T, overflow?: GapCode): readonly T[];
18
18
  export declare const refs: (value: unknown) => readonly string[];
19
19
  export declare function attention(value: unknown): readonly Attention[];
20
20
  export declare function gaps(value: unknown): readonly Gap[];
@@ -1,4 +1,4 @@
1
- import type { GapCode } from './types.js';
1
+ import type { GapCode } from './codes.js';
2
2
  /** One refusal representation; subclasses preserve the graph-port and record-loader boundaries. */
3
3
  export declare class EvidenceRefusal extends Error {
4
4
  readonly code: GapCode;
@@ -19,6 +19,10 @@ export declare function boundedList<T>(value: unknown, maximum: number, read: (i
19
19
  readonly overflow: GapCode;
20
20
  readonly freeze: boolean;
21
21
  readonly descriptors: DescriptorPolicy;
22
+ /** Optional prior shape inspection must refer to the same admitted length. */
23
+ readonly expectedLength?: number;
24
+ /** New boundaries may normalize revoked-array errors without changing existing reader policy. */
25
+ readonly translateArrayErrors?: boolean;
22
26
  }): readonly T[];
23
27
  /** Charge retained fields against the same mutable allowance across admission helpers. */
24
28
  export declare function spendFields(budget: {
@@ -0,0 +1,33 @@
1
+ /** One vocabulary; true marks a domain evidence reason, false a trace/admission gap only. */
2
+ export declare const GAP_CODES: Readonly<{
3
+ readonly 'not-collected': true;
4
+ readonly 'untracked-input': false;
5
+ readonly redacted: true;
6
+ readonly conservative: false;
7
+ readonly 'scope-boundary': false;
8
+ readonly 'invalid-data': true;
9
+ readonly unavailable: true;
10
+ readonly timeout: true;
11
+ readonly cancelled: false;
12
+ readonly cycle: false;
13
+ readonly 'node-limit': false;
14
+ readonly 'depth-limit': false;
15
+ readonly 'edge-limit': false;
16
+ readonly 'call-limit': false;
17
+ readonly truncated: false;
18
+ readonly 'strategy-failed': false;
19
+ readonly 'not-checked': true;
20
+ readonly 'no-match': true;
21
+ readonly ambiguous: true;
22
+ readonly stale: true;
23
+ readonly incompatible: true;
24
+ readonly unsupported: true;
25
+ readonly 'not-permitted': true;
26
+ }>;
27
+ export type GapCode = keyof typeof GAP_CODES;
28
+ /** Producer-asserted evidence reasons, excluding traversal and admission bounds. */
29
+ export type RequirementReason = {
30
+ [Code in GapCode]: (typeof GAP_CODES)[Code] extends true ? Code : never;
31
+ }[GapCode];
32
+ export declare const isGapCode: (value: unknown) => value is "not-collected" | "untracked-input" | "redacted" | "conservative" | "scope-boundary" | "invalid-data" | "unavailable" | "timeout" | "cancelled" | "cycle" | "node-limit" | "depth-limit" | "edge-limit" | "call-limit" | "truncated" | "strategy-failed" | "not-checked" | "no-match" | "ambiguous" | "stale" | "incompatible" | "unsupported" | "not-permitted";
33
+ export declare const isRequirementReason: (value: unknown) => value is RequirementReason;
@@ -0,0 +1,46 @@
1
+ import type { RequirementReason } from './codes.js';
2
+ /**
3
+ * Existing check wire words; a disposition records a producer assertion, not authorization.
4
+ * `unreachable` means the check could not run; its reason identifies why.
5
+ */
6
+ export type RequirementCheckDisposition = 'checked-pass' | 'checked-fail' | 'unreachable' | 'not-applicable';
7
+ /** References to a real check and its retained evidence. No synthetic attempt is required or invented. */
8
+ export interface RequirementCheck {
9
+ readonly checkRef: string;
10
+ readonly disposition: RequirementCheckDisposition;
11
+ readonly reason?: RequirementReason;
12
+ /** A namespaced adapter detail ID, never a message, subject or payload. */
13
+ readonly detail?: string;
14
+ readonly evidenceRefs: readonly string[];
15
+ readonly attemptRefs: readonly string[];
16
+ }
17
+ interface RequirementBinding {
18
+ /** This result's identity, not the enclosing artifact reference minted by storage. */
19
+ readonly id: string;
20
+ /** Reference to the requirement definition or policy. */
21
+ readonly requirementRef: string;
22
+ readonly findingRef: string;
23
+ readonly windowRef: string;
24
+ readonly affects: readonly string[];
25
+ readonly evidenceRefs: readonly string[];
26
+ readonly checks: readonly RequirementCheck[];
27
+ /** References into a host-owned closed action registry; never executable tool names or arguments. */
28
+ readonly actionRefs: readonly string[];
29
+ /** A namespaced adapter detail ID, never a message, subject or payload. */
30
+ readonly detail?: string;
31
+ /** Source validity and learned time are separate opaque references; no freshness inference is made. */
32
+ readonly validTimeRef?: string;
33
+ readonly learnedTimeRef?: string;
34
+ }
35
+ /**
36
+ * A producer assertion. Structural admission does not verify its source, scope, bindings, validity or truth.
37
+ * Hosts must verify those facts and must not let a satisfied record override an unresolved affected claim.
38
+ */
39
+ export type RequirementResult = RequirementBinding & ({
40
+ readonly state: 'satisfied';
41
+ readonly reason?: never;
42
+ } | {
43
+ readonly state: 'unresolved';
44
+ readonly reason: RequirementReason;
45
+ });
46
+ export {};
@@ -0,0 +1,24 @@
1
+ import { EvidenceRefusal } from './admission.js';
2
+ import { type GapCode } from './codes.js';
3
+ import type { RequirementResult } from './requirementTypes.js';
4
+ /** Fixed per-call ceilings; characters are UTF-16 code units, not serialized transport bytes. */
5
+ export declare const REQUIREMENT_RESULT_LIMITS: Readonly<{
6
+ results: 512;
7
+ checks: 16;
8
+ affects: 32;
9
+ refs: 16;
10
+ name: 512;
11
+ fields: 32768;
12
+ characters: 1048576;
13
+ }>;
14
+ /** No input, field value or originating exception is retained on a refusal. */
15
+ export declare class RequirementValidationError extends EvidenceRefusal {
16
+ constructor(code?: GapCode);
17
+ }
18
+ /**
19
+ * Atomically project detached, frozen reference-only records. This is structural admission only.
20
+ * The host must authenticate producers, resolve authorized artifacts, verify current query/run/scope and
21
+ * domain validity, and enforce every unresolved affects reference before rendering any factual claim.
22
+ * Identifier grammar does not classify secrets; producers must supply non-secret identifiers only.
23
+ */
24
+ export declare function readRequirementResults(value: unknown): readonly RequirementResult[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foottrace",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "type": "commonjs",
5
5
  "description": "Execution records, replay, time travel and honest attribution \u2014 independent of the engine that produced them",
6
6
  "license": "MIT",