eval-quality 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +355 -0
- package/corpus/dev/README.md +36 -0
- package/corpus/dev/compile-seal-example/brief.json +1 -0
- package/corpus/dev/compile-seal-example/contract.json +1 -0
- package/corpus/dev/contracts/absent-collection-locations.json +1 -0
- package/corpus/dev/contracts/absent-sibling-groups.json +1 -0
- package/corpus/dev/contracts/absent-success-indicator.json +1 -0
- package/corpus/dev/contracts/empty-channel-roles.json +1 -0
- package/corpus/dev/contracts/empty-collection-locations.json +1 -0
- package/corpus/dev/contracts/empty-request-shapes.json +1 -0
- package/corpus/dev/contracts/empty-sibling-groups.json +1 -0
- package/corpus/dev/contracts/no-collection-quantifier.json +1 -0
- package/corpus/dev/contracts/no-operation-inventory.json +1 -0
- package/corpus/dev/contracts/no-read-back-relation.json +1 -0
- package/corpus/dev/contracts/no-state-change-marker.json +1 -0
- package/corpus/dev/contracts/no-type-violating-step.json +1 -0
- package/corpus/dev/contracts/per-key-split-oracles.json +1 -0
- package/corpus/dev/contracts/satisfied-declarations.json +1 -0
- package/corpus/dev/contracts/single-required-response-key.json +1 -0
- package/corpus/dev/contracts/split-indicator-oracle.json +1 -0
- package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -0
- package/corpus/dev/contracts/unnamed-reference-set.json +1 -0
- package/corpus/dev/contracts/wrong-cardinality-form.json +1 -0
- package/corpus/dev/index.json +1 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/local-corpus-adapter.d.ts +7 -0
- package/dist/adapters/local-corpus-adapter.js +78 -0
- package/dist/adapters/node-file-system-adapter.d.ts +7 -0
- package/dist/adapters/node-file-system-adapter.js +39 -0
- package/dist/adapters/port-boundary.d.ts +18 -0
- package/dist/adapters/port-boundary.js +83 -0
- package/dist/adapters/system-clock-adapter.d.ts +10 -0
- package/dist/adapters/system-clock-adapter.js +18 -0
- package/dist/application/compile.d.ts +4 -0
- package/dist/application/compile.js +24 -0
- package/dist/application/diagnostics.d.ts +22 -0
- package/dist/application/diagnostics.js +18 -0
- package/dist/application/index.d.ts +23 -0
- package/dist/application/index.js +17 -0
- package/dist/application/invoke-port.d.ts +2 -0
- package/dist/application/invoke-port.js +45 -0
- package/dist/application/preflight.d.ts +27 -0
- package/dist/application/preflight.js +131 -0
- package/dist/application/seal.d.ts +4 -0
- package/dist/application/seal.js +28 -0
- package/dist/application/serialize.d.ts +6 -0
- package/dist/application/serialize.js +9 -0
- package/dist/cli/arguments.d.ts +28 -0
- package/dist/cli/arguments.js +167 -0
- package/dist/cli/exit-codes.d.ts +36 -0
- package/dist/cli/exit-codes.js +39 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +143 -0
- package/dist/cli/render.d.ts +26 -0
- package/dist/cli/render.js +53 -0
- package/dist/cli/run.d.ts +41 -0
- package/dist/cli/run.js +203 -0
- package/dist/core/canonical/canonicalize.d.ts +1 -0
- package/dist/core/canonical/canonicalize.js +113 -0
- package/dist/core/canonical/digest.d.ts +7 -0
- package/dist/core/canonical/digest.js +81 -0
- package/dist/core/canonical/scan-json.d.ts +1 -0
- package/dist/core/canonical/scan-json.js +298 -0
- package/dist/core/canonical/value-domain.d.ts +4 -0
- package/dist/core/canonical/value-domain.js +113 -0
- package/dist/core/compile/compile.d.ts +24 -0
- package/dist/core/compile/compile.js +67 -0
- package/dist/core/compile/declarations.d.ts +5 -0
- package/dist/core/compile/declarations.js +22 -0
- package/dist/core/compile/expression-legality.d.ts +14 -0
- package/dist/core/compile/expression-legality.js +346 -0
- package/dist/core/compile/forbidden-inputs.d.ts +5 -0
- package/dist/core/compile/forbidden-inputs.js +19 -0
- package/dist/core/compile/interface-inventory.d.ts +10 -0
- package/dist/core/compile/interface-inventory.js +55 -0
- package/dist/core/compile/oracle-alignment.d.ts +14 -0
- package/dist/core/compile/oracle-alignment.js +93 -0
- package/dist/core/compile/reachability.d.ts +17 -0
- package/dist/core/compile/reachability.js +177 -0
- package/dist/core/compile/rubrics.d.ts +55 -0
- package/dist/core/compile/rubrics.js +198 -0
- package/dist/core/compile/scripting-bound.d.ts +5 -0
- package/dist/core/compile/scripting-bound.js +151 -0
- package/dist/core/compile/sensitivity-witness.d.ts +73 -0
- package/dist/core/compile/sensitivity-witness.js +232 -0
- package/dist/core/compile/waivers.d.ts +3 -0
- package/dist/core/compile/waivers.js +21 -0
- package/dist/core/coverage/coverage.d.ts +18 -0
- package/dist/core/coverage/coverage.js +47 -0
- package/dist/core/coverage/relevance.d.ts +75 -0
- package/dist/core/coverage/relevance.js +186 -0
- package/dist/core/coverage/rules.d.ts +7 -0
- package/dist/core/coverage/rules.js +18 -0
- package/dist/core/coverage/satisfaction.d.ts +107 -0
- package/dist/core/coverage/satisfaction.js +415 -0
- package/dist/core/coverage/table.d.ts +26 -0
- package/dist/core/coverage/table.js +222 -0
- package/dist/core/declared-inputs.d.ts +16 -0
- package/dist/core/declared-inputs.js +18 -0
- package/dist/core/evaluate/evidence-resolution.d.ts +54 -0
- package/dist/core/evaluate/evidence-resolution.js +153 -0
- package/dist/core/evaluate/operators.d.ts +87 -0
- package/dist/core/evaluate/operators.js +350 -0
- package/dist/core/evaluate/resolution.d.ts +40 -0
- package/dist/core/evaluate/resolution.js +336 -0
- package/dist/core/evaluate/resolved-value.d.ts +9 -0
- package/dist/core/evaluate/resolved-value.js +6 -0
- package/dist/core/failure-codes.d.ts +18 -0
- package/dist/core/failure-codes.js +50 -0
- package/dist/core/lineage/chain.d.ts +49 -0
- package/dist/core/lineage/chain.js +210 -0
- package/dist/core/lineage/freeze.d.ts +12 -0
- package/dist/core/lineage/freeze.js +35 -0
- package/dist/core/lineage/stage-table.d.ts +43 -0
- package/dist/core/lineage/stage-table.js +106 -0
- package/dist/core/preflight/plan.d.ts +67 -0
- package/dist/core/preflight/plan.js +313 -0
- package/dist/core/preflight/projection.d.ts +40 -0
- package/dist/core/preflight/projection.js +96 -0
- package/dist/core/preflight/reduce.d.ts +8 -0
- package/dist/core/preflight/reduce.js +180 -0
- package/dist/core/preflight/witness-evidence.d.ts +42 -0
- package/dist/core/preflight/witness-evidence.js +88 -0
- package/dist/core/probe/target-policy.d.ts +63 -0
- package/dist/core/probe/target-policy.js +328 -0
- package/dist/core/schemas/artifact-reference.d.ts +19 -0
- package/dist/core/schemas/artifact-reference.js +30 -0
- package/dist/core/schemas/artifact.d.ts +1153 -0
- package/dist/core/schemas/artifact.js +84 -0
- package/dist/core/schemas/constraint-ledger.d.ts +57 -0
- package/dist/core/schemas/constraint-ledger.js +143 -0
- package/dist/core/schemas/eval-contract.d.ts +402 -0
- package/dist/core/schemas/eval-contract.js +147 -0
- package/dist/core/schemas/evaluator-configuration.d.ts +37 -0
- package/dist/core/schemas/evaluator-configuration.js +43 -0
- package/dist/core/schemas/evidence-artifact.d.ts +471 -0
- package/dist/core/schemas/evidence-artifact.js +232 -0
- package/dist/core/schemas/expression.d.ts +197 -0
- package/dist/core/schemas/expression.js +284 -0
- package/dist/core/schemas/faults.d.ts +9 -0
- package/dist/core/schemas/faults.js +32 -0
- package/dist/core/schemas/interface.d.ts +417 -0
- package/dist/core/schemas/interface.js +115 -0
- package/dist/core/schemas/isolation-manifest.d.ts +136 -0
- package/dist/core/schemas/isolation-manifest.js +92 -0
- package/dist/core/schemas/lineage.d.ts +21 -0
- package/dist/core/schemas/lineage.js +28 -0
- package/dist/core/schemas/oracle.d.ts +72 -0
- package/dist/core/schemas/oracle.js +35 -0
- package/dist/core/schemas/plan.d.ts +115 -0
- package/dist/core/schemas/plan.js +58 -0
- package/dist/core/schemas/pointer.d.ts +63 -0
- package/dist/core/schemas/pointer.js +94 -0
- package/dist/core/schemas/port-messages.d.ts +103 -0
- package/dist/core/schemas/port-messages.js +90 -0
- package/dist/core/schemas/preflight-verdict.d.ts +60 -0
- package/dist/core/schemas/preflight-verdict.js +38 -0
- package/dist/core/schemas/primitives.d.ts +78 -0
- package/dist/core/schemas/primitives.js +121 -0
- package/dist/core/schemas/private-artifact-manifest.d.ts +56 -0
- package/dist/core/schemas/private-artifact-manifest.js +46 -0
- package/dist/core/schemas/probe-body.d.ts +25 -0
- package/dist/core/schemas/probe-body.js +23 -0
- package/dist/core/schemas/probe-policy.d.ts +76 -0
- package/dist/core/schemas/probe-policy.js +33 -0
- package/dist/core/schemas/probe.d.ts +189 -0
- package/dist/core/schemas/probe.js +82 -0
- package/dist/core/schemas/publish.d.ts +30 -0
- package/dist/core/schemas/publish.js +135 -0
- package/dist/core/schemas/reference-set.d.ts +18 -0
- package/dist/core/schemas/reference-set.js +27 -0
- package/dist/core/schemas/rubric.d.ts +62 -0
- package/dist/core/schemas/rubric.js +68 -0
- package/dist/core/schemas/scoring-policy.d.ts +28 -0
- package/dist/core/schemas/scoring-policy.js +51 -0
- package/dist/core/schemas/sealed-evaluator-brief.d.ts +80 -0
- package/dist/core/schemas/sealed-evaluator-brief.js +59 -0
- package/dist/core/schemas/sealed-run-record.d.ts +382 -0
- package/dist/core/schemas/sealed-run-record.js +215 -0
- package/dist/core/schemas/sensitivity-witness.d.ts +138 -0
- package/dist/core/schemas/sensitivity-witness.js +86 -0
- package/dist/core/schemas/verdict.d.ts +25 -0
- package/dist/core/schemas/verdict.js +20 -0
- package/dist/core/schemas/waiver.d.ts +17 -0
- package/dist/core/schemas/waiver.js +24 -0
- package/dist/core/seal/derived-reference.d.ts +36 -0
- package/dist/core/seal/derived-reference.js +383 -0
- package/dist/core/seal/direction-prose.d.ts +13 -0
- package/dist/core/seal/direction-prose.js +120 -0
- package/dist/core/seal/plan-index.d.ts +63 -0
- package/dist/core/seal/plan-index.js +155 -0
- package/dist/core/seal/scripting-audit.d.ts +15 -0
- package/dist/core/seal/scripting-audit.js +51 -0
- package/dist/core/seal/seal.d.ts +18 -0
- package/dist/core/seal/seal.js +155 -0
- package/dist/core/stage-contracts.d.ts +30 -0
- package/dist/core/stage-contracts.js +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +22 -0
- package/dist/ports/clock-port.d.ts +13 -0
- package/dist/ports/clock-port.js +7 -0
- package/dist/ports/corpus-port.d.ts +16 -0
- package/dist/ports/corpus-port.js +7 -0
- package/dist/ports/environment-probe-port.d.ts +76 -0
- package/dist/ports/environment-probe-port.js +32 -0
- package/dist/ports/file-system-port.d.ts +27 -0
- package/dist/ports/file-system-port.js +11 -0
- package/dist/ports/port.d.ts +33 -0
- package/dist/ports/port.js +14 -0
- package/dist/testing/conformance.d.ts +88 -0
- package/dist/testing/conformance.js +281 -0
- package/dist/testing/index.d.ts +26 -0
- package/dist/testing/index.js +18 -0
- package/dist/testing/probe-conformance.d.ts +45 -0
- package/dist/testing/probe-conformance.js +186 -0
- package/package.json +130 -0
- package/schemas/artifact-reference.schema.json +64 -0
- package/schemas/eval-contract.schema.json +2145 -0
- package/schemas/evaluator-configuration.schema.json +199 -0
- package/schemas/evidence-artifact.schema.json +1229 -0
- package/schemas/isolation-manifest.schema.json +394 -0
- package/schemas/preflight-verdict.schema.json +114 -0
- package/schemas/private-artifact-manifest.schema.json +103 -0
- package/schemas/probe.schema.json +1151 -0
- package/schemas/rubric.schema.json +148 -0
- package/schemas/scoring-policy.schema.json +90 -0
- package/schemas/sealed-evaluator-brief.schema.json +268 -0
- package/schemas/sealed-run-record.schema.json +875 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { SCALAR_CHANNELS, TAIL_BEARING_CHANNELS, TRANSPORT_CHANNELS, TRANSPORT_ROOTED_CHANNEL, } from '../schemas/pointer.js';
|
|
2
|
+
import { IDENTIFIER_CHARSET_SOURCE } from '../schemas/primitives.js';
|
|
3
|
+
// An RFC 6901 reference token, respelled here because pointer.ts keeps its
|
|
4
|
+
// own TOKEN/TAIL fragments private. IDENTIFIER_CHARSET_SOURCE and the channel
|
|
5
|
+
// partition below are project vocabulary, so those are imported rather than
|
|
6
|
+
// respelled.
|
|
7
|
+
const TOKEN_SOURCE = '(?:[^/~]|~[01])*';
|
|
8
|
+
const TAIL_SOURCE = `(?:/${TOKEN_SOURCE})*`;
|
|
9
|
+
const alternation = (members) => members.join('|');
|
|
10
|
+
// Mirrors `pointer.ts`'s own `INTERACTION_POINTER_PATTERN` three-branch
|
|
11
|
+
// partition rather than a flatter grammar: a flatter version once silently
|
|
12
|
+
// accepted `/interactions/poll/response-status/oops` (a schema reject) by
|
|
13
|
+
// discarding the bogus trailing segment instead of rejecting the pointer.
|
|
14
|
+
// Named capture groups replace positional indices, avoiding a fragile
|
|
15
|
+
// dependency on `IDENTIFIER_CHARSET_SOURCE` staying free of its own capturing
|
|
16
|
+
// groups.
|
|
17
|
+
const EVIDENCE_TARGET_PATTERN = new RegExp(`^/interactions/(?<stepId>${IDENTIFIER_CHARSET_SOURCE})/(?:(?<tailBearingChannel>${alternation(TAIL_BEARING_CHANNELS)})(?<tailBearingTail>${TAIL_SOURCE})|(?<scalarChannel>${alternation(SCALAR_CHANNELS)})|${TRANSPORT_ROOTED_CHANNEL}/(?<transportChannel>${alternation(TRANSPORT_CHANNELS)})(?<callInputsTail>${TAIL_SOURCE}))$`);
|
|
18
|
+
const isEvidenceChannel = (value) => TAIL_BEARING_CHANNELS.includes(value) ||
|
|
19
|
+
SCALAR_CHANNELS.includes(value);
|
|
20
|
+
const isTransportChannel = (value) => TRANSPORT_CHANNELS.includes(value);
|
|
21
|
+
/**
|
|
22
|
+
* Exported so `core/evaluate/evidence-resolution.ts` decodes pointer tails
|
|
23
|
+
* with these same two functions, avoiding a second private copy (the drift
|
|
24
|
+
* `IDENTIFIER_CHARSET_SOURCE`'s own precedent warns against).
|
|
25
|
+
*/
|
|
26
|
+
export const decodeToken = (token) => token.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
27
|
+
export const decodeTail = (tailSource) => tailSource === '' ? [] : tailSource.slice(1).split('/').map(decodeToken);
|
|
28
|
+
/**
|
|
29
|
+
* Parses one `InteractionPointer` string (`INTERACTION_POINTER_PATTERN` in
|
|
30
|
+
* `pointer.ts`) into its step id, channel, transport channel, and tail, using
|
|
31
|
+
* the schema's own channel partition so this accepts exactly what
|
|
32
|
+
* `InteractionPointer.safeParse` accepts. A should-never-happen precondition
|
|
33
|
+
* violation throws `TypeError`, per `digest.ts`'s precedent.
|
|
34
|
+
*/
|
|
35
|
+
export function parseEvidenceTarget(pointer) {
|
|
36
|
+
const groups = EVIDENCE_TARGET_PATTERN.exec(pointer)?.groups;
|
|
37
|
+
if (groups === undefined || groups.stepId === undefined) {
|
|
38
|
+
throw new TypeError(`not an interaction-rooted evidence pointer of a recognized channel: ${pointer}`);
|
|
39
|
+
}
|
|
40
|
+
const stepId = groups.stepId;
|
|
41
|
+
if (groups.scalarChannel !== undefined) {
|
|
42
|
+
if (!isEvidenceChannel(groups.scalarChannel)) {
|
|
43
|
+
// Unreachable: SCALAR_CHANNELS is exactly what this group can match.
|
|
44
|
+
throw new TypeError(`unrecognized evidence channel in pointer: ${pointer}`);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
stepId,
|
|
48
|
+
channel: groups.scalarChannel,
|
|
49
|
+
transportChannel: null,
|
|
50
|
+
tail: [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (groups.tailBearingChannel !== undefined) {
|
|
54
|
+
if (!isEvidenceChannel(groups.tailBearingChannel)) {
|
|
55
|
+
// Unreachable: TAIL_BEARING_CHANNELS is exactly what this group can match.
|
|
56
|
+
throw new TypeError(`unrecognized evidence channel in pointer: ${pointer}`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
stepId,
|
|
60
|
+
channel: groups.tailBearingChannel,
|
|
61
|
+
transportChannel: null,
|
|
62
|
+
tail: decodeTail(groups.tailBearingTail ?? ''),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (groups.transportChannel !== undefined) {
|
|
66
|
+
if (!isTransportChannel(groups.transportChannel)) {
|
|
67
|
+
// Unreachable: TRANSPORT_CHANNELS is exactly what this group can match.
|
|
68
|
+
throw new TypeError(`call-inputs evidence target names no transport channel: ${pointer}`);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
stepId,
|
|
72
|
+
channel: 'call-inputs',
|
|
73
|
+
transportChannel: groups.transportChannel,
|
|
74
|
+
tail: decodeTail(groups.callInputsTail ?? ''),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Unreachable: the pattern's three branches are exhaustive once stepId matched.
|
|
78
|
+
throw new TypeError(`not an interaction-rooted evidence pointer of a recognized channel: ${pointer}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Builds the index once over the whole plan and interface set. Neither
|
|
82
|
+
* schema enforces `stepId`/`operationId` uniqueness. Strict callers keep the
|
|
83
|
+
* default throw instead of resolving by array order. Standalone structural
|
|
84
|
+
* checks can select `unresolved`, which removes every ambiguous identifier
|
|
85
|
+
* from lookup while preserving all unambiguous entries.
|
|
86
|
+
*/
|
|
87
|
+
export function buildPlanIndex(interactionPlan, permittedInterfaces, options = {}) {
|
|
88
|
+
const duplicateIds = options.duplicateIds ?? 'throw';
|
|
89
|
+
const steps = new Map();
|
|
90
|
+
const duplicateStepIds = new Set();
|
|
91
|
+
const stepsByOperation = new Map();
|
|
92
|
+
for (const step of interactionPlan) {
|
|
93
|
+
if (steps.has(step.stepId) || duplicateStepIds.has(step.stepId)) {
|
|
94
|
+
if (duplicateIds === 'throw') {
|
|
95
|
+
throw new TypeError(`duplicate interaction step id: ${step.stepId}`);
|
|
96
|
+
}
|
|
97
|
+
steps.delete(step.stepId);
|
|
98
|
+
duplicateStepIds.add(step.stepId);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
steps.set(step.stepId, step);
|
|
102
|
+
}
|
|
103
|
+
const group = stepsByOperation.get(step.operationId);
|
|
104
|
+
if (group === undefined) {
|
|
105
|
+
stepsByOperation.set(step.operationId, [step]);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
group.push(step);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const operations = new Map();
|
|
112
|
+
const duplicateOperationIds = new Set();
|
|
113
|
+
for (const iface of permittedInterfaces) {
|
|
114
|
+
for (const operation of iface.operations) {
|
|
115
|
+
if (operations.has(operation.operationId) ||
|
|
116
|
+
duplicateOperationIds.has(operation.operationId)) {
|
|
117
|
+
if (duplicateIds === 'throw') {
|
|
118
|
+
throw new TypeError(`duplicate operation id across permitted interfaces: ${operation.operationId}`);
|
|
119
|
+
}
|
|
120
|
+
operations.delete(operation.operationId);
|
|
121
|
+
duplicateOperationIds.add(operation.operationId);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
operations.set(operation.operationId, operation);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
stepOf: (stepId) => steps.get(stepId),
|
|
130
|
+
operationOf: (operationId) => operations.get(operationId),
|
|
131
|
+
stepsUsing: (operationId) => stepsByOperation.get(operationId) ?? [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Resolves a step id through the index or throws. Split from `stepOf` so the
|
|
136
|
+
* index itself stays a plain lookup (`| undefined`, per
|
|
137
|
+
* `noUncheckedIndexedAccess`) while callers get one function instead of
|
|
138
|
+
* repeating the `undefined` check. A precondition violation, not a
|
|
139
|
+
* `RuntimeFault`.
|
|
140
|
+
*/
|
|
141
|
+
export function resolveStep(index, stepId) {
|
|
142
|
+
const step = index.stepOf(stepId);
|
|
143
|
+
if (step === undefined) {
|
|
144
|
+
throw new TypeError(`evidence target names a step the interaction plan does not declare: ${stepId}`);
|
|
145
|
+
}
|
|
146
|
+
return step;
|
|
147
|
+
}
|
|
148
|
+
/** Resolves an operation id through the index or throws. See `resolveStep`. */
|
|
149
|
+
export function resolveOperation(index, operationId) {
|
|
150
|
+
const operation = index.operationOf(operationId);
|
|
151
|
+
if (operation === undefined) {
|
|
152
|
+
throw new TypeError(`step names an operation the permitted interfaces do not declare: ${operationId}`);
|
|
153
|
+
}
|
|
154
|
+
return operation;
|
|
155
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SealedEvaluatorBrief } from '../schemas/sealed-evaluator-brief.ts';
|
|
2
|
+
/**
|
|
3
|
+
* `probeStepBound: null` skips the audit (the codebase's null-means-absent
|
|
4
|
+
* convention); a declared `0` is legal and strict, permitting no marker.
|
|
5
|
+
*
|
|
6
|
+
* Checked per direction, never summed across the brief, so an unrelated
|
|
7
|
+
* direction's own count never tightens an already-declared bound.
|
|
8
|
+
*
|
|
9
|
+
* Scoped to `brief.directions[].text` only, leaving `behaviors`,
|
|
10
|
+
* `scopedResources`, and `safetyLimits` unscanned: AD-16 runs this audit
|
|
11
|
+
* after generation over what `seal` generated, and AD-38 names AD-3's
|
|
12
|
+
* generated direction as that output. The other three are carried through
|
|
13
|
+
* from the contract.
|
|
14
|
+
*/
|
|
15
|
+
export declare function auditBriefScripting(brief: SealedEvaluatorBrief): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The post-generation scripting audit (AD-16, `brief-exceeds-scripting-bound`).
|
|
3
|
+
* The declaration-side graph predicate over the interaction plan
|
|
4
|
+
* (`core/compile/scripting-bound.ts`) can't see free text an author wrote
|
|
5
|
+
* directly onto a direction's `scope`/`negativeDomain`. This audit is the
|
|
6
|
+
* other half: it counts sequencing/transition vocabulary in each direction's
|
|
7
|
+
* rendered `text`. The templates in `direction-prose.ts` compose no ordering
|
|
8
|
+
* word of their own, so a match arrives from the author's `scope` or
|
|
9
|
+
* `negativeDomain`, or from an `operationId` that `derived-reference.ts`
|
|
10
|
+
* humanizes into one (`next-page` renders "the next page endpoint").
|
|
11
|
+
*/
|
|
12
|
+
import { StructuralFailure } from '../failure-codes.js';
|
|
13
|
+
const AD5_CODE = 'brief-exceeds-scripting-bound';
|
|
14
|
+
// Matches the ordering vocabulary forbidden in generator-composed text,
|
|
15
|
+
// minus bare ordinals (bare "first" also appears as a data-position
|
|
16
|
+
// adjective in accepted author prose), plus a numbered- or lettered-list
|
|
17
|
+
// marker (`1.`, `2)`, `a)`). `afterward`/`subsequent` match their inflected
|
|
18
|
+
// forms too, since a bare-word boundary can't catch one word inside another
|
|
19
|
+
// and each inflection is a real evasion path.
|
|
20
|
+
//
|
|
21
|
+
// The list-marker branch anchors to actual list context (string start,
|
|
22
|
+
// after a newline, or after a sentence-ending mark) rather than any
|
|
23
|
+
// mid-sentence digit-punctuation-space. Its trailing boundary rejects a
|
|
24
|
+
// following digit rather than requiring whitespace, so "1.Send the request"
|
|
25
|
+
// still opens a list item while "12.5" reads as a decimal fraction. The
|
|
26
|
+
// marker is an unbounded digit run or a single letter, so `a)`/`b)` count
|
|
27
|
+
// alongside `1.`/`2)`.
|
|
28
|
+
const SEQUENCE_MARKER_PATTERN = /\b(?:then|before|after|subsequent(?:ly)?|next|finally|afterward(?:s)?)\b|(?<=^\s*|\n\s*|[.!?]\s*)(?:\d+|[a-z])[.)](?!\d)/gi;
|
|
29
|
+
/**
|
|
30
|
+
* `probeStepBound: null` skips the audit (the codebase's null-means-absent
|
|
31
|
+
* convention); a declared `0` is legal and strict, permitting no marker.
|
|
32
|
+
*
|
|
33
|
+
* Checked per direction, never summed across the brief, so an unrelated
|
|
34
|
+
* direction's own count never tightens an already-declared bound.
|
|
35
|
+
*
|
|
36
|
+
* Scoped to `brief.directions[].text` only, leaving `behaviors`,
|
|
37
|
+
* `scopedResources`, and `safetyLimits` unscanned: AD-16 runs this audit
|
|
38
|
+
* after generation over what `seal` generated, and AD-38 names AD-3's
|
|
39
|
+
* generated direction as that output. The other three are carried through
|
|
40
|
+
* from the contract.
|
|
41
|
+
*/
|
|
42
|
+
export function auditBriefScripting(brief) {
|
|
43
|
+
if (brief.probeStepBound === null)
|
|
44
|
+
return;
|
|
45
|
+
for (const direction of brief.directions) {
|
|
46
|
+
const count = direction.text.match(SEQUENCE_MARKER_PATTERN)?.length ?? 0;
|
|
47
|
+
if (count > brief.probeStepBound) {
|
|
48
|
+
throw new StructuralFailure(AD5_CODE, `SealedEvaluatorBrief.directions[oracleId=${direction.oracleId}].text`, `${count} enumerated-probe-step marker(s) exceed the declared bound of ${brief.probeStepBound}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EvalContract } from '../schemas/eval-contract.ts';
|
|
2
|
+
import { SealedEvaluatorBrief } from '../schemas/sealed-evaluator-brief.ts';
|
|
3
|
+
export declare function seal(contract: EvalContract): SealedEvaluatorBrief;
|
|
4
|
+
/**
|
|
5
|
+
* The runtime backstop behind AD-16's exclusion guarantee. TypeScript's
|
|
6
|
+
* compile-time excess-property check protects only `seal()`'s current
|
|
7
|
+
* return literal; a future non-literal construction path (an `as` cast, a
|
|
8
|
+
* spread, an incremental build) would otherwise have no backstop. Reads only
|
|
9
|
+
* the `safeParse` result shape, so `core/schemas` stays the sole Zod
|
|
10
|
+
* boundary and a rejection becomes a `TypeError` (this file's
|
|
11
|
+
* precondition-violation convention) with no `ZodError` import to test
|
|
12
|
+
* against.
|
|
13
|
+
*
|
|
14
|
+
* Scoped to `seal()`, the one function in `core/` minting a package-boundary
|
|
15
|
+
* artifact today. Exported so a regression test can drive the rejection path
|
|
16
|
+
* directly.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateAssembledBrief(brief: unknown): SealedEvaluatorBrief;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `seal`: walks a compiled `EvalContract`'s oracles to assemble the
|
|
3
|
+
* `SealedEvaluatorBrief` AD-16 describes, making its isolation boundary
|
|
4
|
+
* structural rather than conventional. Pure per AD-1/AD-2: no filesystem,
|
|
5
|
+
* network, clock, randomness, model call, or evaluator execution. Reuses
|
|
6
|
+
* `buildPlanIndex`/`renderDirectionText` for the generated prose and
|
|
7
|
+
* `digestArtifact` for `contractDigest`; never reimplements rendering or
|
|
8
|
+
* hashing locally. Before returning, `validateAssembledBrief` gives AD-16's
|
|
9
|
+
* exclusion guarantee a runtime backstop; see that function for why.
|
|
10
|
+
*/
|
|
11
|
+
import { digestArtifact } from '../canonical/digest.js';
|
|
12
|
+
import { freezeArtifact } from '../lineage/freeze.js';
|
|
13
|
+
import { SealedEvaluatorBrief } from '../schemas/sealed-evaluator-brief.js';
|
|
14
|
+
import { renderDirectionText } from './direction-prose.js';
|
|
15
|
+
import { buildPlanIndex } from './plan-index.js';
|
|
16
|
+
// `seal` digests the contract whole, so one stable label serves every call
|
|
17
|
+
// regardless of which contract is being sealed.
|
|
18
|
+
const CONTRACT_ARTIFACT_PATH = 'EvalContract';
|
|
19
|
+
/**
|
|
20
|
+
* Sorts by a natural identifying string key, throwing `TypeError` on a
|
|
21
|
+
* duplicate key rather than emitting an order-dependent result. The schema
|
|
22
|
+
* enforces no uniqueness on `oracle.id`, `permittedInterface.logicalId`, or
|
|
23
|
+
* `scopedResource.reference`, so a duplicate is a real possibility and
|
|
24
|
+
* sort-stability alone would otherwise silently break byte-identity under
|
|
25
|
+
* contract-step reordering. This is the same precondition-violation
|
|
26
|
+
* convention `plan-index.ts`'s duplicate-`stepId`/`operationId` guard uses.
|
|
27
|
+
*/
|
|
28
|
+
function sortedByKey(items, keyOf, keyLabel) {
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
for (const item of items) {
|
|
31
|
+
const key = keyOf(item);
|
|
32
|
+
if (seen.has(key)) {
|
|
33
|
+
throw new TypeError(`duplicate ${keyLabel} in sealed brief input: ${key}`);
|
|
34
|
+
}
|
|
35
|
+
seen.add(key);
|
|
36
|
+
}
|
|
37
|
+
return [...items].sort((a, b) => {
|
|
38
|
+
const keyA = keyOf(a);
|
|
39
|
+
const keyB = keyOf(b);
|
|
40
|
+
return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
export function seal(contract) {
|
|
44
|
+
const index = buildPlanIndex(contract.interactionPlan, contract.permittedInterfaces);
|
|
45
|
+
// A `null` direction reaching here is a precondition violation: a
|
|
46
|
+
// compiled contract's oracles must carry a non-null direction by the
|
|
47
|
+
// time `seal` reads them. Throw, never filter or skip.
|
|
48
|
+
const directions = contract.oracles.map((oracle) => {
|
|
49
|
+
if (oracle.direction === null) {
|
|
50
|
+
throw new TypeError(`oracle ${oracle.id} reached seal() with a null direction`);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
oracleId: oracle.id,
|
|
54
|
+
text: renderDirectionText(oracle.direction, index),
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// A per-element projection, not a carry-through: `PermittedInterface` has
|
|
58
|
+
// an `operations` field `BriefInterface` does not, so shipping it here
|
|
59
|
+
// would hand the evaluator the action inventory AD-39 keeps from it.
|
|
60
|
+
const permittedInterfaces = contract.permittedInterfaces.map((iface) => ({
|
|
61
|
+
logicalId: iface.logicalId,
|
|
62
|
+
kind: iface.kind,
|
|
63
|
+
}));
|
|
64
|
+
// `null` on the contract means "no scoped resources declared"; `seal`
|
|
65
|
+
// always resolves an answer, so it carries through as `[]`, matching the
|
|
66
|
+
// brief field's non-nullable schema.
|
|
67
|
+
const scopedResources = contract.scopedResources ?? [];
|
|
68
|
+
// Explicitly typed, not just inferred, so TypeScript's excess-property
|
|
69
|
+
// check still runs against this literal: assigning an object literal to
|
|
70
|
+
// an explicitly-typed binding triggers the same check as returning it
|
|
71
|
+
// from a typed function.
|
|
72
|
+
const brief = {
|
|
73
|
+
// `seal` owns these two fields per AD-24/AD-29: this call mints a
|
|
74
|
+
// fresh artifact, never a revision of a prior brief. `seal` is pure
|
|
75
|
+
// and stateless with no "prior brief" argument (AD-12), so the only
|
|
76
|
+
// honest artifact is a lineage root: `parentDigest` null,
|
|
77
|
+
// `revisionCount` 0, independent of the contract's own lineage.
|
|
78
|
+
// `schemaVersion` is the brief schema's current version.
|
|
79
|
+
schemaVersion: 1,
|
|
80
|
+
parentDigest: null,
|
|
81
|
+
revisionCount: 0,
|
|
82
|
+
// A plain digest of the literal input: two differently-ordered
|
|
83
|
+
// contracts necessarily digest differently, by construction. This
|
|
84
|
+
// field sits outside the byte-identical-under-reordering guarantee the
|
|
85
|
+
// rest of the brief carries, since it tracks the literal contract that
|
|
86
|
+
// was sealed.
|
|
87
|
+
contractDigest: digestArtifact(contract, CONTRACT_ARTIFACT_PATH),
|
|
88
|
+
// Carried through in contract order, unsorted: its own schema doc
|
|
89
|
+
// calls it "carried through unchanged," unlike the arrays below.
|
|
90
|
+
// Copied rather than aliased, like every field here, since the brief
|
|
91
|
+
// must not keep sharing structure with the input, or a caller
|
|
92
|
+
// mutating `contract.behaviors` after `seal()` returns would
|
|
93
|
+
// silently mutate the "sealed" brief too.
|
|
94
|
+
behaviors: [...contract.behaviors],
|
|
95
|
+
directions: sortedByKey(directions, (d) => d.oracleId, 'oracleId'),
|
|
96
|
+
permittedInterfaces: sortedByKey(permittedInterfaces, (i) => i.logicalId, 'permittedInterfaces logicalId'),
|
|
97
|
+
scopedResources: sortedByKey(scopedResources, (r) => r.reference, 'scopedResources reference'),
|
|
98
|
+
// Copied rather than aliased, for the same reason as `behaviors` above.
|
|
99
|
+
budgets: { ...contract.budgets },
|
|
100
|
+
// Sorted lexicographically; sort-key duplicates are impossible here
|
|
101
|
+
// since equal strings are interchangeable, so no duplicate guard.
|
|
102
|
+
safetyLimits: [...contract.safetyLimits].sort(),
|
|
103
|
+
probeStepBound: contract.probeStepBound,
|
|
104
|
+
};
|
|
105
|
+
// The parse returns Zod's own deep clone, so the freeze lands on the
|
|
106
|
+
// brief the caller receives and leaves the contract it was built from alone.
|
|
107
|
+
return freezeArtifact(validateAssembledBrief(brief));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The runtime backstop behind AD-16's exclusion guarantee. TypeScript's
|
|
111
|
+
* compile-time excess-property check protects only `seal()`'s current
|
|
112
|
+
* return literal; a future non-literal construction path (an `as` cast, a
|
|
113
|
+
* spread, an incremental build) would otherwise have no backstop. Reads only
|
|
114
|
+
* the `safeParse` result shape, so `core/schemas` stays the sole Zod
|
|
115
|
+
* boundary and a rejection becomes a `TypeError` (this file's
|
|
116
|
+
* precondition-violation convention) with no `ZodError` import to test
|
|
117
|
+
* against.
|
|
118
|
+
*
|
|
119
|
+
* Scoped to `seal()`, the one function in `core/` minting a package-boundary
|
|
120
|
+
* artifact today. Exported so a regression test can drive the rejection path
|
|
121
|
+
* directly.
|
|
122
|
+
*/
|
|
123
|
+
export function validateAssembledBrief(brief) {
|
|
124
|
+
const result = SealedEvaluatorBrief.safeParse(brief);
|
|
125
|
+
if (result.success)
|
|
126
|
+
return result.data;
|
|
127
|
+
const issueCount = result.error.issues.length;
|
|
128
|
+
const firstIssue = result.error.issues[0];
|
|
129
|
+
const firstPath = firstIssue ? dotPath(firstIssue.path) : '';
|
|
130
|
+
throw new TypeError(`seal() assembled a brief that failed SealedEvaluatorBrief validation: ${issueCount} issue${issueCount === 1 ? '' : 's'}, first at "${firstPath === '' ? '(root)' : firstPath}"`, { cause: result.error });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Formats a Zod issue path for the message above, mirroring zod's own
|
|
134
|
+
* `core.toDotPath` branch by branch without importing it: a word-shaped
|
|
135
|
+
* segment joins with `.`; a numeric, symbol, or non-identifier segment is
|
|
136
|
+
* bracketed. The mirror holds even at the edges, so a segment that is
|
|
137
|
+
* word-shaped but starts with a digit stays unbracketed here exactly as zod
|
|
138
|
+
* leaves it.
|
|
139
|
+
*/
|
|
140
|
+
function dotPath(path) {
|
|
141
|
+
const segments = [];
|
|
142
|
+
for (const segment of path) {
|
|
143
|
+
if (typeof segment === 'number')
|
|
144
|
+
segments.push(`[${segment}]`);
|
|
145
|
+
else if (typeof segment === 'symbol' || /[^\w$]/.test(segment)) {
|
|
146
|
+
segments.push(`[${JSON.stringify(String(segment))}]`);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
if (segments.length > 0)
|
|
150
|
+
segments.push('.');
|
|
151
|
+
segments.push(segment);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return segments.join('');
|
|
155
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AD-34's stage-shape vocabulary. Two conformance types pin the exact shapes
|
|
3
|
+
* of `compile` and `seal`; two generic types record the conditional
|
|
4
|
+
* plan/reduce pair, which `preflight` implements.
|
|
5
|
+
*
|
|
6
|
+
* AD-24's six-stage input/output/owner/lineage table lives in
|
|
7
|
+
* `core/lineage/stage-table.ts`. This file holds the stage *shapes* TypeScript
|
|
8
|
+
* checks an implementation against; that one holds the *table* AD-24 fixes.
|
|
9
|
+
* Neither imports the other.
|
|
10
|
+
*/
|
|
11
|
+
import type { EvalContract } from './schemas/eval-contract.ts';
|
|
12
|
+
import type { SealedEvaluatorBrief } from './schemas/sealed-evaluator-brief.ts';
|
|
13
|
+
/** The core compile stage's one runtime option. Core behavior never depends on an implicit configuration source (AD-1), so this is required; `application/compile.ts` is the only caller that supplies a default. */
|
|
14
|
+
export type CompileOptions = {
|
|
15
|
+
readonly strict: boolean;
|
|
16
|
+
};
|
|
17
|
+
/** `core/compile/compile.ts`'s exact conformance shape. */
|
|
18
|
+
export type CompileStage = (contract: EvalContract, options: CompileOptions) => EvalContract;
|
|
19
|
+
/** `core/seal/seal.ts`'s exact conformance shape. */
|
|
20
|
+
export type SealStage = (contract: EvalContract) => SealedEvaluatorBrief;
|
|
21
|
+
/**
|
|
22
|
+
* A stage's pure planning half: artifacts in, a request description out.
|
|
23
|
+
* AD-34 makes this pair conditional on a stage needing external observation.
|
|
24
|
+
* Compile and seal need none, so neither implements this; pre-flight does, and
|
|
25
|
+
* `core/preflight/plan.ts` and `core/preflight/reduce.ts` are the pair that
|
|
26
|
+
* satisfies these two types.
|
|
27
|
+
*/
|
|
28
|
+
export type PlanStage<InputArtifact, RequestDescription> = (input: InputArtifact) => RequestDescription;
|
|
29
|
+
/** A stage's pure reducing half: the plan plus the observations a port produced, reduced to the next artifact. */
|
|
30
|
+
export type ReduceStage<RequestDescription, Observation, OutputArtifact> = (plan: RequestDescription, observations: Observation) => OutputArtifact;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './application/index.ts';
|
|
2
|
+
export type { ArtifactReference } from './core/schemas/artifact-reference.ts';
|
|
3
|
+
export type { EvalContract } from './core/schemas/eval-contract.ts';
|
|
4
|
+
export type { EvaluatorConfiguration } from './core/schemas/evaluator-configuration.ts';
|
|
5
|
+
export type { EvidenceArtifact } from './core/schemas/evidence-artifact.ts';
|
|
6
|
+
export type { IsolationManifest } from './core/schemas/isolation-manifest.ts';
|
|
7
|
+
export type { PreflightCheck, PreflightVerdict, } from './core/schemas/preflight-verdict.ts';
|
|
8
|
+
export type { PrivateArtifactManifest } from './core/schemas/private-artifact-manifest.ts';
|
|
9
|
+
export type { Probe } from './core/schemas/probe.ts';
|
|
10
|
+
export type { Rubric } from './core/schemas/rubric.ts';
|
|
11
|
+
export type { ScoringPolicy } from './core/schemas/scoring-policy.ts';
|
|
12
|
+
export type { SealedEvaluatorBrief } from './core/schemas/sealed-evaluator-brief.ts';
|
|
13
|
+
export type { SealedRunRecord } from './core/schemas/sealed-run-record.ts';
|
|
14
|
+
export type { FixtureReset, ManifestationWitness, SensitivityWitness, SensitivityWitnessLeg, WitnessChannel, WitnessInputs, } from './core/schemas/sensitivity-witness.ts';
|
|
15
|
+
export declare const VERSION = "0.1.0";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// eval-quality: compile disciplined eval contracts and score known-defect detection.
|
|
2
|
+
//
|
|
3
|
+
// Barrel export. Modules land here along the artifact pipeline:
|
|
4
|
+
// compile: validate Behavioral Evaluation Contracts and discipline coverage
|
|
5
|
+
// seal: emit deterministic evaluator briefs
|
|
6
|
+
// ingest: validate caller-produced run records and isolation manifests
|
|
7
|
+
// preflight: compile the contract's witnesses into probe requests, then
|
|
8
|
+
// reduce the observations the environment-probe port returned
|
|
9
|
+
// score: derive per-oracle outcomes and contract-strength vectors
|
|
10
|
+
// emit: produce versioned evidence artifacts
|
|
11
|
+
//
|
|
12
|
+
// The package executes nothing: it never runs an agent, judge, or system under test.
|
|
13
|
+
//
|
|
14
|
+
// The dependency matrix grants this file two edges and no others: `root ->
|
|
15
|
+
// application` and `root -> core-schemas`. So the layer barrel
|
|
16
|
+
// `application/index.ts` is how everything else under `core/` is reached,
|
|
17
|
+
// while the artifact types below come straight off `core/schemas` on the
|
|
18
|
+
// second edge. The port vocabulary stays at the `eval-quality/conformance`
|
|
19
|
+
// subpath, where AD-37 puts the conformance definition an adapter author
|
|
20
|
+
// reads; the reference adapters stay at `eval-quality/adapters`.
|
|
21
|
+
export * from './application/index.js';
|
|
22
|
+
export const VERSION = '0.1.0';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** AD-1 forbids a clock read under `core/`, so a timestamp arrives through this port. */
|
|
2
|
+
import { ClockReadRequest, ClockReadResponse } from '../core/schemas/port-messages.ts';
|
|
3
|
+
import type { PortMethod } from './port.ts';
|
|
4
|
+
export type ClockPort = {
|
|
5
|
+
readonly read: PortMethod<ClockReadRequest, ClockReadResponse>;
|
|
6
|
+
};
|
|
7
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
8
|
+
export declare const clockReadParsers: {
|
|
9
|
+
readonly request: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
10
|
+
readonly response: import("zod").ZodObject<{
|
|
11
|
+
now: import("zod").ZodISODateTime;
|
|
12
|
+
}, import("zod/v4/core").$strict>;
|
|
13
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** AD-1 forbids a clock read under `core/`, so a timestamp arrives through this port. */
|
|
2
|
+
import { ClockReadRequest, ClockReadResponse, } from '../core/schemas/port-messages.js';
|
|
3
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
4
|
+
export const clockReadParsers = {
|
|
5
|
+
request: ClockReadRequest,
|
|
6
|
+
response: ClockReadResponse,
|
|
7
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** AD-8's corpus-provider port: an opaque reference in, resolved bytes out. */
|
|
2
|
+
import { CorpusResolveRequest, CorpusResolveResponse } from '../core/schemas/port-messages.ts';
|
|
3
|
+
import type { PortMethod } from './port.ts';
|
|
4
|
+
export type CorpusPort = {
|
|
5
|
+
readonly resolve: PortMethod<CorpusResolveRequest, CorpusResolveResponse>;
|
|
6
|
+
};
|
|
7
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
8
|
+
export declare const corpusResolveParsers: {
|
|
9
|
+
readonly request: import("zod").ZodObject<{
|
|
10
|
+
privateRef: import("zod").ZodString;
|
|
11
|
+
}, import("zod/v4/core").$strict>;
|
|
12
|
+
readonly response: import("zod").ZodObject<{
|
|
13
|
+
privateRef: import("zod").ZodString;
|
|
14
|
+
bytes: import("zod").ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>;
|
|
15
|
+
}, import("zod/v4/core").$strict>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** AD-8's corpus-provider port: an opaque reference in, resolved bytes out. */
|
|
2
|
+
import { CorpusResolveRequest, CorpusResolveResponse, } from '../core/schemas/port-messages.js';
|
|
3
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
4
|
+
export const corpusResolveParsers = {
|
|
5
|
+
request: CorpusResolveRequest,
|
|
6
|
+
response: CorpusResolveResponse,
|
|
7
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AD-35's environment-probe port: a logical interface identifier in, one
|
|
3
|
+
* observation out. The request never names a URL, host, or port. Mapping the
|
|
4
|
+
* identifier to an authorized target is the adapter's job, from configuration
|
|
5
|
+
* outside the contract.
|
|
6
|
+
*
|
|
7
|
+
* Four rules an implementation MUST follow. Prose here because `ports/` holds
|
|
8
|
+
* no logic; `src/testing/probe-conformance.ts` is the executable half.
|
|
9
|
+
*
|
|
10
|
+
* 1. Apply the policy before any network call, and again to every redirect
|
|
11
|
+
* target.
|
|
12
|
+
* 2. Issue the request against the address the policy validated
|
|
13
|
+
* (`canonicalAddress`), keep the original host in the `Host` header, and
|
|
14
|
+
* verify TLS against that host. Never re-resolve a hostname after
|
|
15
|
+
* validation: re-resolving between the check and the connection is the
|
|
16
|
+
* classic way past an allowlist like this one. Where a host resolves to
|
|
17
|
+
* several addresses, validate each and connect only to a validated one.
|
|
18
|
+
* 3. A policy denial throws `forbidden-target`; a cap throws
|
|
19
|
+
* `budget-exhausted`; an abort throws `aborted`; a transport failure throws
|
|
20
|
+
* `port-failure`.
|
|
21
|
+
* 4. Every response the server returns is an observation, at any status. A 4xx
|
|
22
|
+
* or 5xx resolves to a schema-valid `ProbeObservation`, since AD-10's
|
|
23
|
+
* "every declared seeded fault being observed to fire" reads the status as
|
|
24
|
+
* payload. Throw on a non-2xx and a seeded fault goes invisible, which
|
|
25
|
+
* makes the whole pre-flight vacuous.
|
|
26
|
+
*/
|
|
27
|
+
import { ProbeObservation, ProbeRequest } from '../core/schemas/port-messages.ts';
|
|
28
|
+
import type { PortMethod } from './port.ts';
|
|
29
|
+
export type EnvironmentProbePort = {
|
|
30
|
+
readonly probe: PortMethod<ProbeRequest, ProbeObservation>;
|
|
31
|
+
};
|
|
32
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
33
|
+
export declare const probeParsers: {
|
|
34
|
+
readonly request: import("zod").ZodObject<{
|
|
35
|
+
probeId: import("zod").ZodString;
|
|
36
|
+
interfaceId: import("zod").ZodString;
|
|
37
|
+
operationId: import("zod").ZodString;
|
|
38
|
+
method: import("zod").ZodEnum<{
|
|
39
|
+
DELETE: "DELETE";
|
|
40
|
+
GET: "GET";
|
|
41
|
+
HEAD: "HEAD";
|
|
42
|
+
OPTIONS: "OPTIONS";
|
|
43
|
+
PATCH: "PATCH";
|
|
44
|
+
POST: "POST";
|
|
45
|
+
PUT: "PUT";
|
|
46
|
+
}>;
|
|
47
|
+
pathTemplate: import("zod").ZodString;
|
|
48
|
+
channels: import("zod").ZodObject<{
|
|
49
|
+
path: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>>;
|
|
50
|
+
query: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>>;
|
|
51
|
+
header: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>;
|
|
52
|
+
body: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
53
|
+
kind: import("zod").ZodLiteral<"json">;
|
|
54
|
+
value: import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>;
|
|
55
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
56
|
+
kind: import("zod").ZodLiteral<"absent">;
|
|
57
|
+
}, import("zod/v4/core").$strict>], "kind">;
|
|
58
|
+
}, import("zod/v4/core").$strict>;
|
|
59
|
+
}, import("zod/v4/core").$strict>;
|
|
60
|
+
readonly response: import("zod").ZodObject<{
|
|
61
|
+
probeId: import("zod").ZodString;
|
|
62
|
+
interfaceId: import("zod").ZodString;
|
|
63
|
+
operationId: import("zod").ZodString;
|
|
64
|
+
status: import("zod").ZodInt;
|
|
65
|
+
headers: import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>;
|
|
66
|
+
body: import("zod").ZodDiscriminatedUnion<[import("zod").ZodObject<{
|
|
67
|
+
kind: import("zod").ZodLiteral<"json">;
|
|
68
|
+
value: import("zod").ZodType<import("../core/schemas/primitives.ts").JsonValue, unknown, import("zod/v4/core").$ZodTypeInternals<import("../core/schemas/primitives.ts").JsonValue, unknown>>;
|
|
69
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
70
|
+
kind: import("zod").ZodLiteral<"text">;
|
|
71
|
+
value: import("zod").ZodString;
|
|
72
|
+
}, import("zod/v4/core").$strict>, import("zod").ZodObject<{
|
|
73
|
+
kind: import("zod").ZodLiteral<"absent">;
|
|
74
|
+
}, import("zod/v4/core").$strict>], "kind">;
|
|
75
|
+
}, import("zod/v4/core").$strict>;
|
|
76
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AD-35's environment-probe port: a logical interface identifier in, one
|
|
3
|
+
* observation out. The request never names a URL, host, or port. Mapping the
|
|
4
|
+
* identifier to an authorized target is the adapter's job, from configuration
|
|
5
|
+
* outside the contract.
|
|
6
|
+
*
|
|
7
|
+
* Four rules an implementation MUST follow. Prose here because `ports/` holds
|
|
8
|
+
* no logic; `src/testing/probe-conformance.ts` is the executable half.
|
|
9
|
+
*
|
|
10
|
+
* 1. Apply the policy before any network call, and again to every redirect
|
|
11
|
+
* target.
|
|
12
|
+
* 2. Issue the request against the address the policy validated
|
|
13
|
+
* (`canonicalAddress`), keep the original host in the `Host` header, and
|
|
14
|
+
* verify TLS against that host. Never re-resolve a hostname after
|
|
15
|
+
* validation: re-resolving between the check and the connection is the
|
|
16
|
+
* classic way past an allowlist like this one. Where a host resolves to
|
|
17
|
+
* several addresses, validate each and connect only to a validated one.
|
|
18
|
+
* 3. A policy denial throws `forbidden-target`; a cap throws
|
|
19
|
+
* `budget-exhausted`; an abort throws `aborted`; a transport failure throws
|
|
20
|
+
* `port-failure`.
|
|
21
|
+
* 4. Every response the server returns is an observation, at any status. A 4xx
|
|
22
|
+
* or 5xx resolves to a schema-valid `ProbeObservation`, since AD-10's
|
|
23
|
+
* "every declared seeded fault being observed to fire" reads the status as
|
|
24
|
+
* payload. Throw on a non-2xx and a seeded fault goes invisible, which
|
|
25
|
+
* makes the whole pre-flight vacuous.
|
|
26
|
+
*/
|
|
27
|
+
import { ProbeObservation, ProbeRequest, } from '../core/schemas/port-messages.js';
|
|
28
|
+
/** the boundary parsers `application/` and the conformance suite validate with. */
|
|
29
|
+
export const probeParsers = {
|
|
30
|
+
request: ProbeRequest,
|
|
31
|
+
response: ProbeObservation,
|
|
32
|
+
};
|