@vizejs/marquette 0.299.1 → 0.303.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ubugeeei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -99,18 +99,39 @@ deployment tooling can bind a `tests` check to retained, immutable facts:
99
99
  import { defineTestRunEvidence } from "@vizejs/marquette/test-run";
100
100
  import { validateTestRunEvidence } from "@vizejs/marquette/test-run/validate";
101
101
  import { testRunAdmissionId } from "@vizejs/marquette/test-run/canonical";
102
- import { admitTestRun } from "@vizejs/marquette/test-run/admission";
102
+ import { admitTestRun, decideTestRunAdmission } from "@vizejs/marquette/test-run/admission";
103
+ import { verifyTestRunCheck } from "@vizejs/marquette/test-run/check";
104
+ import { verifyTestRunTransition } from "@vizejs/marquette/test-run/transition";
103
105
 
104
106
  const diagnostics = validateTestRunEvidence(evidence);
105
107
  const admissionId = await testRunAdmissionId(evidence); // test-run:<sha256>
106
108
  const rejections = await admitTestRun(evidence, candidate, admissionId, now);
109
+ const decision = await decideTestRunAdmission(evidence, candidate, admissionId, now);
110
+ if (!decision.allowed) {
111
+ console.error(decision.denialCodes); // e.g. ["record-expired"]
112
+ }
113
+ const release = await verifyTestRunCheck(retainedCheck, candidate, evidence, now);
114
+ const journal = await verifyTestRunTransition(nextTransition, chainTip);
107
115
  ```
108
116
 
109
117
  Validation shares its `VIZE_MARQUETTE_1xx` codes, paths, and ordering with the
110
118
  native implementation, and the canonical entry produces byte-identical
111
119
  serialization and SHA-256 fingerprints, proven by the shared fixtures in
112
- `tests/fixtures/test-run-evidence/`. The published record schema is available
113
- from `@vizejs/marquette/test-run/schema`.
120
+ `tests/fixtures/test-run-evidence/`. Admission decisions carry the stable,
121
+ append-only denial-code vocabulary shared by every backend family; the same
122
+ fixtures pin every decision so a JavaScript, Rust, Go, or JVM gate denies for
123
+ identical machine-readable causes. The check entry replaces every generic
124
+ test-result reference in release evidence: a retained `vize.test-run.check`
125
+ record may only name the exact `test-run:<sha256>` admission id, bind the six
126
+ candidate facts, and record an observer independent from the runner. The
127
+ transition entry makes each release decision and the complete accepted
128
+ anti-replay state one durable atomic record, chained by canonical SHA-256
129
+ fingerprints; hosts persist it with a write-then-atomic-rename and verify the
130
+ recovered tip before deciding anything new. The published record schema is
131
+ available from `@vizejs/marquette/test-run/schema`, the decision contract from
132
+ `@vizejs/marquette/test-run/admission/schema`, the tests-check contract from
133
+ `@vizejs/marquette/test-run/check/schema`, and the transition contract from
134
+ `@vizejs/marquette/test-run/transition/schema`.
114
135
 
115
136
  ## Guarantees
116
137
 
@@ -0,0 +1,167 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://vizejs.dev/schemas/marquette/application-contract.schema.json",
4
+ "title": "Vize Application Marquette",
5
+ "description": "Versioned language-neutral application target, environment, backend, protocol, and route graph.",
6
+ "$ref": "#/$defs/contract",
7
+ "$defs": {
8
+ "identifier": {
9
+ "type": "string",
10
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
11
+ },
12
+ "target": {
13
+ "enum": ["web", "native", "desktop", "terminal"]
14
+ },
15
+ "runtime": {
16
+ "enum": [
17
+ "browser",
18
+ "javascript",
19
+ "rust",
20
+ "go",
21
+ "jvm",
22
+ "native",
23
+ "desktop",
24
+ "terminal",
25
+ "external"
26
+ ]
27
+ },
28
+ "capabilityDefinition": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["id", "description"],
32
+ "properties": {
33
+ "id": { "$ref": "#/$defs/identifier" },
34
+ "description": { "type": "string", "minLength": 1 },
35
+ "version": { "type": "integer", "minimum": 1, "default": 1 }
36
+ }
37
+ },
38
+ "environment": {
39
+ "type": "object",
40
+ "additionalProperties": false,
41
+ "required": ["id", "target", "consumer", "runtime"],
42
+ "properties": {
43
+ "id": { "$ref": "#/$defs/identifier" },
44
+ "target": { "$ref": "#/$defs/target" },
45
+ "consumer": { "enum": ["client", "server"] },
46
+ "runtime": { "$ref": "#/$defs/runtime" },
47
+ "entry": { "type": "string", "minLength": 1 },
48
+ "dependsOn": {
49
+ "type": "array",
50
+ "items": { "$ref": "#/$defs/identifier" },
51
+ "uniqueItems": true,
52
+ "default": []
53
+ },
54
+ "capabilities": {
55
+ "type": "array",
56
+ "items": { "$ref": "#/$defs/identifier" },
57
+ "uniqueItems": true,
58
+ "default": []
59
+ }
60
+ }
61
+ },
62
+ "backend": {
63
+ "type": "object",
64
+ "additionalProperties": false,
65
+ "required": ["id", "family"],
66
+ "properties": {
67
+ "id": { "$ref": "#/$defs/identifier" },
68
+ "family": { "enum": ["javascript", "rust", "go", "jvm", "external"] },
69
+ "environment": { "$ref": "#/$defs/identifier" },
70
+ "capabilities": {
71
+ "type": "array",
72
+ "items": { "$ref": "#/$defs/identifier" },
73
+ "uniqueItems": true,
74
+ "default": []
75
+ }
76
+ }
77
+ },
78
+ "protocol": {
79
+ "type": "object",
80
+ "additionalProperties": false,
81
+ "required": ["id", "family", "backend"],
82
+ "properties": {
83
+ "id": { "$ref": "#/$defs/identifier" },
84
+ "family": { "enum": ["schema-query", "typed-rpc", "binary-rpc"] },
85
+ "backend": { "$ref": "#/$defs/identifier" },
86
+ "capabilities": {
87
+ "type": "array",
88
+ "items": { "$ref": "#/$defs/identifier" },
89
+ "uniqueItems": true,
90
+ "default": []
91
+ }
92
+ }
93
+ },
94
+ "route": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "required": ["id", "path", "environment", "rendering"],
98
+ "properties": {
99
+ "id": { "$ref": "#/$defs/identifier" },
100
+ "path": { "type": "string", "pattern": "^/" },
101
+ "environment": { "$ref": "#/$defs/identifier" },
102
+ "rendering": {
103
+ "enum": [
104
+ "client",
105
+ "static",
106
+ "server",
107
+ "stream",
108
+ "partial",
109
+ "hybrid",
110
+ "native",
111
+ "desktop",
112
+ "terminal"
113
+ ]
114
+ },
115
+ "backend": { "$ref": "#/$defs/identifier" },
116
+ "protocol": { "$ref": "#/$defs/identifier" },
117
+ "capabilities": {
118
+ "type": "array",
119
+ "items": { "$ref": "#/$defs/identifier" },
120
+ "uniqueItems": true,
121
+ "default": []
122
+ }
123
+ }
124
+ },
125
+ "contract": {
126
+ "type": "object",
127
+ "additionalProperties": false,
128
+ "required": ["application"],
129
+ "properties": {
130
+ "formatVersion": { "const": 1, "default": 1 },
131
+ "application": { "$ref": "#/$defs/identifier" },
132
+ "targets": {
133
+ "type": "array",
134
+ "items": { "$ref": "#/$defs/target" },
135
+ "uniqueItems": true,
136
+ "default": []
137
+ },
138
+ "capabilities": {
139
+ "type": "object",
140
+ "propertyNames": { "$ref": "#/$defs/identifier" },
141
+ "additionalProperties": { "$ref": "#/$defs/capabilityDefinition" },
142
+ "default": {}
143
+ },
144
+ "environments": {
145
+ "type": "array",
146
+ "items": { "$ref": "#/$defs/environment" },
147
+ "default": []
148
+ },
149
+ "backends": {
150
+ "type": "array",
151
+ "items": { "$ref": "#/$defs/backend" },
152
+ "default": []
153
+ },
154
+ "protocols": {
155
+ "type": "array",
156
+ "items": { "$ref": "#/$defs/protocol" },
157
+ "default": []
158
+ },
159
+ "routes": {
160
+ "type": "array",
161
+ "items": { "$ref": "#/$defs/route" },
162
+ "default": []
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }
@@ -1,6 +1,6 @@
1
1
  import { i as TestRunEvidence } from "./test-run-model-DkllmEsY.mjs";
2
2
  import { MarquetteDiagnostic } from "./validate.mjs";
3
- import { TEST_RUN_ADMISSION_PREFIX, parseTestRunAdmissionId } from "./test-run-canonical.mjs";
3
+ import { r as parseTestRunAdmissionId, t as TEST_RUN_ADMISSION_PREFIX } from "./test-run-canonical-CB-KzZxk.mjs";
4
4
 
5
5
  //#region src/test-run-admission.d.ts
6
6
  /**
@@ -43,6 +43,62 @@ interface TestRunCandidate {
43
43
  * hand the parsed record here.
44
44
  */
45
45
  declare function admitTestRun(evidence: TestRunEvidence, candidate: TestRunCandidate, admissionId: string, now: string): Promise<MarquetteDiagnostic[]>;
46
+ /**
47
+ * Every denial code, in the stable lexicographic decision order.
48
+ *
49
+ * The vocabulary is shared by every backend family: a JavaScript, Rust, Go,
50
+ * or JVM host must derive the same codes from the same diagnostics, as
51
+ * pinned by the shared `tests/fixtures/test-run-evidence` decision fixtures.
52
+ * Codes are append-only: they are never renamed, renumbered, reused, or
53
+ * removed, and a new rejection cause always ships with a new code.
54
+ */
55
+ declare const TEST_RUN_DENIAL_CODES: readonly ["admission-id-malformed", "admission-id-mismatch", "admission-time-malformed", "candidate-application-mismatch", "candidate-artifact-fingerprint-mismatch", "candidate-contract-fingerprint-mismatch", "candidate-environment-mismatch", "candidate-release-mismatch", "candidate-source-revision-mismatch", "check-candidate-mismatch", "check-invalid", "check-observer-not-independent", "record-expired", "record-invalid", "skipped-tests-recorded", "transition-chain-broken", "transition-invalid", "transition-replayed", "transition-state-mismatch", "verification-not-accepted"];
56
+ /** Stable machine-readable cause class of one admission denial. */
57
+ type TestRunDenialCode = (typeof TEST_RUN_DENIAL_CODES)[number];
58
+ /**
59
+ * Structured allow-or-deny admission decision for one exact candidate.
60
+ *
61
+ * The decision carries the machine-readable cause classes next to the exact
62
+ * diagnostics, so a deployment gate in any language can act on one bounded
63
+ * vocabulary while operators keep the full explanation. Serialization
64
+ * follows the shared `test-run-admission` schema; decisions are outputs, so
65
+ * a gate must never trust a decision it did not compute itself.
66
+ */
67
+ interface TestRunAdmissionDecision {
68
+ /** Whether the record admits the candidate; true only with no diagnostics. */
69
+ readonly allowed: boolean;
70
+ /** Deduplicated denial causes sorted lexicographically; empty when allowed. */
71
+ readonly denialCodes: readonly TestRunDenialCode[];
72
+ /** Complete diagnostics in the stable path, code, message order. */
73
+ readonly diagnostics: readonly MarquetteDiagnostic[];
74
+ }
75
+ /**
76
+ * Returns the stable denial code one admission diagnostic maps to.
77
+ *
78
+ * The mapping is total and identical in every host family: admission codes
79
+ * `VIZE_MARQUETTE_141` through `VIZE_MARQUETTE_148` map to their exact
80
+ * cause, `VIZE_MARQUETTE_144` distinguishes the mismatched candidate binding
81
+ * by its diagnostic path, `VIZE_MARQUETTE_149` through `VIZE_MARQUETTE_151`
82
+ * map to their tests-check cause, `VIZE_MARQUETTE_156` through
83
+ * `VIZE_MARQUETTE_159` map to their transition cause, every other
84
+ * diagnostic at a `check.` path is a `check-invalid` tests-check validation
85
+ * failure, every other diagnostic at a `transition.` path is a
86
+ * `transition-invalid` transition validation failure, and every remaining
87
+ * diagnostic is a `record-invalid` record-validation failure.
88
+ */
89
+ declare function testRunDenialCode(diagnostic: MarquetteDiagnostic): TestRunDenialCode;
90
+ /**
91
+ * Decides one candidate and returns the structured admission decision.
92
+ *
93
+ * The decision wraps {@link admitTestRun}: `diagnostics` is exactly its
94
+ * result, `denialCodes` maps every diagnostic through
95
+ * {@link testRunDenialCode} and then deduplicates and sorts the codes
96
+ * lexicographically, and `allowed` is true only when both are empty. Codes,
97
+ * ordering, and diagnostics are identical to the native implementation, as
98
+ * pinned by the shared decision fixtures. Inputs carry the same obligations
99
+ * as {@link admitTestRun}.
100
+ */
101
+ declare function decideTestRunAdmission(evidence: TestRunEvidence, candidate: TestRunCandidate, admissionId: string, now: string): Promise<TestRunAdmissionDecision>;
46
102
  //#endregion
47
- export { TEST_RUN_ADMISSION_PREFIX, TestRunCandidate, admitTestRun, parseTestRunAdmissionId };
103
+ export { TEST_RUN_ADMISSION_PREFIX, TEST_RUN_DENIAL_CODES, TestRunAdmissionDecision, TestRunCandidate, TestRunDenialCode, admitTestRun, decideTestRunAdmission, parseTestRunAdmissionId, testRunDenialCode };
48
104
  //# sourceMappingURL=test-run-admission.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-run-admission.d.mts","names":[],"sources":["../src/test-run-admission.ts"],"mappings":";;;;;;;AAcA;;;;UAAiB,gBAAA;EAIN;EAAA,SAFA,WAAA;EAMA;EAAA,SAJA,WAAA;EAQA;EAAA,SANA,mBAAA;EAMmB;EAAA,SAJnB,cAAA;EA0BuB;EAAA,SAxBvB,OAAA;EAyBC;EAAA,SAvBD,mBAAA;AAAA;;;;;;;;;;;;;;;;;;;;iBAsBW,YAAA,CACpB,QAAA,EAAU,eAAA,EACV,SAAA,EAAW,gBAAA,EACX,WAAA,UACA,GAAA,WACC,OAAA,CAAQ,mBAAA"}
1
+ {"version":3,"file":"test-run-admission.d.mts","names":[],"sources":["../src/test-run-admission.ts"],"mappings":";;;;;;;AAcA;;;;UAAiB,gBAAA;EAIN;EAAA,SAFA,WAAA;EAMA;EAAA,SAJA,WAAA;EAQA;EAAA,SANA,mBAAA;EAMmB;EAAA,SAJnB,cAAA;EA0BuB;EAAA,SAxBvB,OAAA;EAyBC;EAAA,SAvBD,mBAAA;AAAA;;;;;;;;;;;;;;AA+HX;;;;;AAwBA;iBAjIsB,YAAA,CACpB,QAAA,EAAU,eAAA,EACV,SAAA,EAAW,gBAAA,EACX,WAAA,UACA,GAAA,WACC,OAAA,CAAQ,mBAAA;;;;AAuIX;;;;;;cAnCa,qBAAA;;KAwBD,iBAAA,WAA4B,qBAAA;;;AA2CxC;;;;;;;UAhCiB,wBAAA;EAgCoE;EAAA,SA9B1E,OAAA;EAqFiC;EAAA,SAnFjC,WAAA,WAAsB,iBAAA;EAoFrB;EAAA,SAlFD,WAAA,WAAsB,mBAAA;AAAA;;;;;;;;;;;;;;;iBA0BjB,iBAAA,CAAkB,UAAA,EAAY,mBAAA,GAAsB,iBAAA;;;;;;;;;;;;iBAuD9C,sBAAA,CACpB,QAAA,EAAU,eAAA,EACV,SAAA,EAAW,gBAAA,EACX,WAAA,UACA,GAAA,WACC,OAAA,CAAQ,wBAAA"}
@@ -1,4 +1,4 @@
1
- import { a as error, o as isStrictTimestamp, t as validateTestRunEvidence } from "./test-run-validate-XF0vyoWI.mjs";
1
+ import { d as isStrictTimestamp, t as validateTestRunEvidence, u as error } from "./test-run-validate-C_KR031E.mjs";
2
2
  import { TEST_RUN_ADMISSION_PREFIX, parseTestRunAdmissionId, testRunFingerprint } from "./test-run-canonical.mjs";
3
3
  //#region src/test-run-admission.ts
4
4
  /**
@@ -66,7 +66,105 @@ async function admitTestRun(evidence, candidate, admissionId, now) {
66
66
  diagnostics.sort((left, right) => left.path !== right.path ? left.path < right.path ? -1 : 1 : left.code !== right.code ? left.code < right.code ? -1 : 1 : left.message < right.message ? -1 : left.message > right.message ? 1 : 0);
67
67
  return diagnostics;
68
68
  }
69
+ /**
70
+ * Every denial code, in the stable lexicographic decision order.
71
+ *
72
+ * The vocabulary is shared by every backend family: a JavaScript, Rust, Go,
73
+ * or JVM host must derive the same codes from the same diagnostics, as
74
+ * pinned by the shared `tests/fixtures/test-run-evidence` decision fixtures.
75
+ * Codes are append-only: they are never renamed, renumbered, reused, or
76
+ * removed, and a new rejection cause always ships with a new code.
77
+ */
78
+ const TEST_RUN_DENIAL_CODES = [
79
+ "admission-id-malformed",
80
+ "admission-id-mismatch",
81
+ "admission-time-malformed",
82
+ "candidate-application-mismatch",
83
+ "candidate-artifact-fingerprint-mismatch",
84
+ "candidate-contract-fingerprint-mismatch",
85
+ "candidate-environment-mismatch",
86
+ "candidate-release-mismatch",
87
+ "candidate-source-revision-mismatch",
88
+ "check-candidate-mismatch",
89
+ "check-invalid",
90
+ "check-observer-not-independent",
91
+ "record-expired",
92
+ "record-invalid",
93
+ "skipped-tests-recorded",
94
+ "transition-chain-broken",
95
+ "transition-invalid",
96
+ "transition-replayed",
97
+ "transition-state-mismatch",
98
+ "verification-not-accepted"
99
+ ];
100
+ const CANDIDATE_MISMATCH_CODES = new Map([
101
+ ["application", "candidate-application-mismatch"],
102
+ ["artifact.fingerprint", "candidate-artifact-fingerprint-mismatch"],
103
+ ["contractFingerprint", "candidate-contract-fingerprint-mismatch"],
104
+ ["environment", "candidate-environment-mismatch"],
105
+ ["release", "candidate-release-mismatch"],
106
+ ["sourceRevision", "candidate-source-revision-mismatch"]
107
+ ]);
108
+ /**
109
+ * Returns the stable denial code one admission diagnostic maps to.
110
+ *
111
+ * The mapping is total and identical in every host family: admission codes
112
+ * `VIZE_MARQUETTE_141` through `VIZE_MARQUETTE_148` map to their exact
113
+ * cause, `VIZE_MARQUETTE_144` distinguishes the mismatched candidate binding
114
+ * by its diagnostic path, `VIZE_MARQUETTE_149` through `VIZE_MARQUETTE_151`
115
+ * map to their tests-check cause, `VIZE_MARQUETTE_156` through
116
+ * `VIZE_MARQUETTE_159` map to their transition cause, every other
117
+ * diagnostic at a `check.` path is a `check-invalid` tests-check validation
118
+ * failure, every other diagnostic at a `transition.` path is a
119
+ * `transition-invalid` transition validation failure, and every remaining
120
+ * diagnostic is a `record-invalid` record-validation failure.
121
+ */
122
+ function testRunDenialCode(diagnostic) {
123
+ switch (diagnostic.code) {
124
+ case "VIZE_MARQUETTE_141": return "admission-id-malformed";
125
+ case "VIZE_MARQUETTE_142": return "admission-id-mismatch";
126
+ case "VIZE_MARQUETTE_144": {
127
+ const mismatch = CANDIDATE_MISMATCH_CODES.get(diagnostic.path);
128
+ if (mismatch !== void 0) return mismatch;
129
+ break;
130
+ }
131
+ case "VIZE_MARQUETTE_145": return "record-expired";
132
+ case "VIZE_MARQUETTE_146": return "verification-not-accepted";
133
+ case "VIZE_MARQUETTE_147": return "skipped-tests-recorded";
134
+ case "VIZE_MARQUETTE_148": return "admission-time-malformed";
135
+ case "VIZE_MARQUETTE_149": return "check-candidate-mismatch";
136
+ case "VIZE_MARQUETTE_150": return "check-invalid";
137
+ case "VIZE_MARQUETTE_151": return "check-observer-not-independent";
138
+ case "VIZE_MARQUETTE_156": return "transition-state-mismatch";
139
+ case "VIZE_MARQUETTE_157": return "transition-chain-broken";
140
+ case "VIZE_MARQUETTE_158": return "transition-replayed";
141
+ case "VIZE_MARQUETTE_159": return "transition-state-mismatch";
142
+ default: break;
143
+ }
144
+ if (diagnostic.path.startsWith("check.")) return "check-invalid";
145
+ return diagnostic.path.startsWith("transition.") ? "transition-invalid" : "record-invalid";
146
+ }
147
+ /**
148
+ * Decides one candidate and returns the structured admission decision.
149
+ *
150
+ * The decision wraps {@link admitTestRun}: `diagnostics` is exactly its
151
+ * result, `denialCodes` maps every diagnostic through
152
+ * {@link testRunDenialCode} and then deduplicates and sorts the codes
153
+ * lexicographically, and `allowed` is true only when both are empty. Codes,
154
+ * ordering, and diagnostics are identical to the native implementation, as
155
+ * pinned by the shared decision fixtures. Inputs carry the same obligations
156
+ * as {@link admitTestRun}.
157
+ */
158
+ async function decideTestRunAdmission(evidence, candidate, admissionId, now) {
159
+ const diagnostics = await admitTestRun(evidence, candidate, admissionId, now);
160
+ const denialCodes = [...new Set(diagnostics.map(testRunDenialCode))].sort();
161
+ return {
162
+ allowed: diagnostics.length === 0,
163
+ denialCodes,
164
+ diagnostics
165
+ };
166
+ }
69
167
  //#endregion
70
- export { TEST_RUN_ADMISSION_PREFIX, admitTestRun, parseTestRunAdmissionId };
168
+ export { TEST_RUN_ADMISSION_PREFIX, TEST_RUN_DENIAL_CODES, admitTestRun, decideTestRunAdmission, parseTestRunAdmissionId, testRunDenialCode };
71
169
 
72
170
  //# sourceMappingURL=test-run-admission.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"test-run-admission.mjs","names":[],"sources":["../src/test-run-admission.ts"],"sourcesContent":["import type { TestRunEvidence } from \"./test-run-model.js\";\nimport type { MarquetteDiagnostic } from \"./validate.js\";\nimport { parseTestRunAdmissionId, testRunFingerprint } from \"./test-run-canonical.js\";\nimport { validateTestRunEvidence } from \"./test-run-validate.js\";\nimport { error, isStrictTimestamp } from \"./test-run-validate-rules.js\";\n\nexport { TEST_RUN_ADMISSION_PREFIX, parseTestRunAdmissionId } from \"./test-run-canonical.js\";\n\n/**\n * Exact release candidate a deployment gate wants evidence for.\n *\n * Every field must match the record exactly; admission never falls back to a\n * newer, older, or partially matching record.\n */\nexport interface TestRunCandidate {\n /** Application the gate is deploying. */\n readonly application: string;\n /** Deployment environment the gate is promoting into. */\n readonly environment: string;\n /** Lowercase SHA-256 fingerprint of the application contract. */\n readonly contractFingerprint: string;\n /** Exact source revision of the candidate. */\n readonly sourceRevision: string;\n /** Release the candidate belongs to. */\n readonly release: string;\n /** Lowercase SHA-256 fingerprint of the exact artifact being promoted. */\n readonly artifactFingerprint: string;\n}\n\n/**\n * Decides whether one record admits one exact candidate at one instant.\n *\n * An empty result admits the deployment. Any diagnostic rejects it: the\n * record must validate cleanly, its canonical fingerprint must be the one\n * named by `admissionId`, every candidate binding must match exactly, the\n * record must not be expired at `now`, the independent verification must\n * have accepted the run, and no skipped test may remain unaccounted for.\n *\n * Codes, paths, messages, and ordering are identical to the native\n * implementation, so both host families reach the same decision for the\n * same record.\n *\n * `now` must be a millisecond-precision UTC timestamp such as\n * `2026-01-01T00:00:00.000Z`; the fixed-width format keeps the expiry\n * comparison exact. Callers own retrieval: fetch the canonical bytes from an\n * immutable store within their own deadline, refuse oversized content, and\n * hand the parsed record here.\n */\nexport async function admitTestRun(\n evidence: TestRunEvidence,\n candidate: TestRunCandidate,\n admissionId: string,\n now: string,\n): Promise<MarquetteDiagnostic[]> {\n const diagnostics = validateTestRunEvidence(evidence);\n\n const nowIsExact = isStrictTimestamp(now);\n if (!nowIsExact) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_148\",\n \"admission.now\",\n \"admission time must be a millisecond-precision UTC instant\",\n ),\n );\n }\n\n const expected = parseTestRunAdmissionId(admissionId);\n if (expected === undefined) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_141\",\n \"admission.id\",\n \"admission id must be test-run: followed by 64 lowercase hexadecimal characters\",\n ),\n );\n } else if ((await testRunFingerprint(evidence)) !== expected) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_142\",\n \"admission.id\",\n \"admission id does not name this record's canonical fingerprint\",\n ),\n );\n }\n\n const bindings = [\n [evidence.application, candidate.application, \"application\"],\n [evidence.environment, candidate.environment, \"environment\"],\n [evidence.contractFingerprint, candidate.contractFingerprint, \"contractFingerprint\"],\n [evidence.sourceRevision, candidate.sourceRevision, \"sourceRevision\"],\n [evidence.release, candidate.release, \"release\"],\n [evidence.artifact.fingerprint, candidate.artifactFingerprint, \"artifact.fingerprint\"],\n ] as const;\n for (const [recorded, wanted, field] of bindings) {\n if (recorded !== wanted) {\n diagnostics.push(\n error(\"VIZE_MARQUETTE_144\", field, `record does not bind the candidate ${field}`),\n );\n }\n }\n\n if (nowIsExact && evidence.validUntil <= now) {\n diagnostics.push(\n error(\"VIZE_MARQUETTE_145\", \"validUntil\", \"record is expired at the admission time\"),\n );\n }\n if (evidence.verification.outcome !== \"accepted\") {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_146\",\n \"verification.outcome\",\n \"only an accepted verification can admit a deployment\",\n ),\n );\n }\n if (evidence.verification.skipped > 0) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_147\",\n \"verification.skipped\",\n \"skipped tests are not approved for deployment admission\",\n ),\n );\n }\n\n diagnostics.sort((left, right) =>\n left.path !== right.path\n ? left.path < right.path\n ? -1\n : 1\n : left.code !== right.code\n ? left.code < right.code\n ? -1\n : 1\n : left.message < right.message\n ? -1\n : left.message > right.message\n ? 1\n : 0,\n );\n return diagnostics;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgDA,eAAsB,aACpB,UACA,WACA,aACA,KACgC;CAChC,MAAM,cAAc,wBAAwB,SAAS;CAErD,MAAM,aAAa,kBAAkB,IAAI;CACzC,IAAI,CAAC,YACH,YAAY,KACV,MACE,sBACA,iBACA,6DACD,CACF;CAGH,MAAM,WAAW,wBAAwB,YAAY;CACrD,IAAI,aAAa,KAAA,GACf,YAAY,KACV,MACE,sBACA,gBACA,iFACD,CACF;MACI,IAAK,MAAM,mBAAmB,SAAS,KAAM,UAClD,YAAY,KACV,MACE,sBACA,gBACA,iEACD,CACF;CAGH,MAAM,WAAW;EACf;GAAC,SAAS;GAAa,UAAU;GAAa;GAAc;EAC5D;GAAC,SAAS;GAAa,UAAU;GAAa;GAAc;EAC5D;GAAC,SAAS;GAAqB,UAAU;GAAqB;GAAsB;EACpF;GAAC,SAAS;GAAgB,UAAU;GAAgB;GAAiB;EACrE;GAAC,SAAS;GAAS,UAAU;GAAS;GAAU;EAChD;GAAC,SAAS,SAAS;GAAa,UAAU;GAAqB;GAAuB;EACvF;CACD,KAAK,MAAM,CAAC,UAAU,QAAQ,UAAU,UACtC,IAAI,aAAa,QACf,YAAY,KACV,MAAM,sBAAsB,OAAO,sCAAsC,QAAQ,CAClF;CAIL,IAAI,cAAc,SAAS,cAAc,KACvC,YAAY,KACV,MAAM,sBAAsB,cAAc,0CAA0C,CACrF;CAEH,IAAI,SAAS,aAAa,YAAY,YACpC,YAAY,KACV,MACE,sBACA,wBACA,uDACD,CACF;CAEH,IAAI,SAAS,aAAa,UAAU,GAClC,YAAY,KACV,MACE,sBACA,wBACA,0DACD,CACF;CAGH,YAAY,MAAM,MAAM,UACtB,KAAK,SAAS,MAAM,OAChB,KAAK,OAAO,MAAM,OAChB,KACA,IACF,KAAK,SAAS,MAAM,OAClB,KAAK,OAAO,MAAM,OAChB,KACA,IACF,KAAK,UAAU,MAAM,UACnB,KACA,KAAK,UAAU,MAAM,UACnB,IACA,EACX;CACD,OAAO"}
1
+ {"version":3,"file":"test-run-admission.mjs","names":[],"sources":["../src/test-run-admission.ts"],"sourcesContent":["import type { TestRunEvidence } from \"./test-run-model.js\";\nimport type { MarquetteDiagnostic } from \"./validate.js\";\nimport { parseTestRunAdmissionId, testRunFingerprint } from \"./test-run-canonical.js\";\nimport { validateTestRunEvidence } from \"./test-run-validate.js\";\nimport { error, isStrictTimestamp } from \"./test-run-validate-rules.js\";\n\nexport { TEST_RUN_ADMISSION_PREFIX, parseTestRunAdmissionId } from \"./test-run-canonical.js\";\n\n/**\n * Exact release candidate a deployment gate wants evidence for.\n *\n * Every field must match the record exactly; admission never falls back to a\n * newer, older, or partially matching record.\n */\nexport interface TestRunCandidate {\n /** Application the gate is deploying. */\n readonly application: string;\n /** Deployment environment the gate is promoting into. */\n readonly environment: string;\n /** Lowercase SHA-256 fingerprint of the application contract. */\n readonly contractFingerprint: string;\n /** Exact source revision of the candidate. */\n readonly sourceRevision: string;\n /** Release the candidate belongs to. */\n readonly release: string;\n /** Lowercase SHA-256 fingerprint of the exact artifact being promoted. */\n readonly artifactFingerprint: string;\n}\n\n/**\n * Decides whether one record admits one exact candidate at one instant.\n *\n * An empty result admits the deployment. Any diagnostic rejects it: the\n * record must validate cleanly, its canonical fingerprint must be the one\n * named by `admissionId`, every candidate binding must match exactly, the\n * record must not be expired at `now`, the independent verification must\n * have accepted the run, and no skipped test may remain unaccounted for.\n *\n * Codes, paths, messages, and ordering are identical to the native\n * implementation, so both host families reach the same decision for the\n * same record.\n *\n * `now` must be a millisecond-precision UTC timestamp such as\n * `2026-01-01T00:00:00.000Z`; the fixed-width format keeps the expiry\n * comparison exact. Callers own retrieval: fetch the canonical bytes from an\n * immutable store within their own deadline, refuse oversized content, and\n * hand the parsed record here.\n */\nexport async function admitTestRun(\n evidence: TestRunEvidence,\n candidate: TestRunCandidate,\n admissionId: string,\n now: string,\n): Promise<MarquetteDiagnostic[]> {\n const diagnostics = validateTestRunEvidence(evidence);\n\n const nowIsExact = isStrictTimestamp(now);\n if (!nowIsExact) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_148\",\n \"admission.now\",\n \"admission time must be a millisecond-precision UTC instant\",\n ),\n );\n }\n\n const expected = parseTestRunAdmissionId(admissionId);\n if (expected === undefined) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_141\",\n \"admission.id\",\n \"admission id must be test-run: followed by 64 lowercase hexadecimal characters\",\n ),\n );\n } else if ((await testRunFingerprint(evidence)) !== expected) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_142\",\n \"admission.id\",\n \"admission id does not name this record's canonical fingerprint\",\n ),\n );\n }\n\n const bindings = [\n [evidence.application, candidate.application, \"application\"],\n [evidence.environment, candidate.environment, \"environment\"],\n [evidence.contractFingerprint, candidate.contractFingerprint, \"contractFingerprint\"],\n [evidence.sourceRevision, candidate.sourceRevision, \"sourceRevision\"],\n [evidence.release, candidate.release, \"release\"],\n [evidence.artifact.fingerprint, candidate.artifactFingerprint, \"artifact.fingerprint\"],\n ] as const;\n for (const [recorded, wanted, field] of bindings) {\n if (recorded !== wanted) {\n diagnostics.push(\n error(\"VIZE_MARQUETTE_144\", field, `record does not bind the candidate ${field}`),\n );\n }\n }\n\n if (nowIsExact && evidence.validUntil <= now) {\n diagnostics.push(\n error(\"VIZE_MARQUETTE_145\", \"validUntil\", \"record is expired at the admission time\"),\n );\n }\n if (evidence.verification.outcome !== \"accepted\") {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_146\",\n \"verification.outcome\",\n \"only an accepted verification can admit a deployment\",\n ),\n );\n }\n if (evidence.verification.skipped > 0) {\n diagnostics.push(\n error(\n \"VIZE_MARQUETTE_147\",\n \"verification.skipped\",\n \"skipped tests are not approved for deployment admission\",\n ),\n );\n }\n\n diagnostics.sort((left, right) =>\n left.path !== right.path\n ? left.path < right.path\n ? -1\n : 1\n : left.code !== right.code\n ? left.code < right.code\n ? -1\n : 1\n : left.message < right.message\n ? -1\n : left.message > right.message\n ? 1\n : 0,\n );\n return diagnostics;\n}\n\n/**\n * Every denial code, in the stable lexicographic decision order.\n *\n * The vocabulary is shared by every backend family: a JavaScript, Rust, Go,\n * or JVM host must derive the same codes from the same diagnostics, as\n * pinned by the shared `tests/fixtures/test-run-evidence` decision fixtures.\n * Codes are append-only: they are never renamed, renumbered, reused, or\n * removed, and a new rejection cause always ships with a new code.\n */\nexport const TEST_RUN_DENIAL_CODES = [\n \"admission-id-malformed\",\n \"admission-id-mismatch\",\n \"admission-time-malformed\",\n \"candidate-application-mismatch\",\n \"candidate-artifact-fingerprint-mismatch\",\n \"candidate-contract-fingerprint-mismatch\",\n \"candidate-environment-mismatch\",\n \"candidate-release-mismatch\",\n \"candidate-source-revision-mismatch\",\n \"check-candidate-mismatch\",\n \"check-invalid\",\n \"check-observer-not-independent\",\n \"record-expired\",\n \"record-invalid\",\n \"skipped-tests-recorded\",\n \"transition-chain-broken\",\n \"transition-invalid\",\n \"transition-replayed\",\n \"transition-state-mismatch\",\n \"verification-not-accepted\",\n] as const;\n\n/** Stable machine-readable cause class of one admission denial. */\nexport type TestRunDenialCode = (typeof TEST_RUN_DENIAL_CODES)[number];\n\n/**\n * Structured allow-or-deny admission decision for one exact candidate.\n *\n * The decision carries the machine-readable cause classes next to the exact\n * diagnostics, so a deployment gate in any language can act on one bounded\n * vocabulary while operators keep the full explanation. Serialization\n * follows the shared `test-run-admission` schema; decisions are outputs, so\n * a gate must never trust a decision it did not compute itself.\n */\nexport interface TestRunAdmissionDecision {\n /** Whether the record admits the candidate; true only with no diagnostics. */\n readonly allowed: boolean;\n /** Deduplicated denial causes sorted lexicographically; empty when allowed. */\n readonly denialCodes: readonly TestRunDenialCode[];\n /** Complete diagnostics in the stable path, code, message order. */\n readonly diagnostics: readonly MarquetteDiagnostic[];\n}\n\nconst CANDIDATE_MISMATCH_CODES: ReadonlyMap<string, TestRunDenialCode> = new Map([\n [\"application\", \"candidate-application-mismatch\"],\n [\"artifact.fingerprint\", \"candidate-artifact-fingerprint-mismatch\"],\n [\"contractFingerprint\", \"candidate-contract-fingerprint-mismatch\"],\n [\"environment\", \"candidate-environment-mismatch\"],\n [\"release\", \"candidate-release-mismatch\"],\n [\"sourceRevision\", \"candidate-source-revision-mismatch\"],\n]);\n\n/**\n * Returns the stable denial code one admission diagnostic maps to.\n *\n * The mapping is total and identical in every host family: admission codes\n * `VIZE_MARQUETTE_141` through `VIZE_MARQUETTE_148` map to their exact\n * cause, `VIZE_MARQUETTE_144` distinguishes the mismatched candidate binding\n * by its diagnostic path, `VIZE_MARQUETTE_149` through `VIZE_MARQUETTE_151`\n * map to their tests-check cause, `VIZE_MARQUETTE_156` through\n * `VIZE_MARQUETTE_159` map to their transition cause, every other\n * diagnostic at a `check.` path is a `check-invalid` tests-check validation\n * failure, every other diagnostic at a `transition.` path is a\n * `transition-invalid` transition validation failure, and every remaining\n * diagnostic is a `record-invalid` record-validation failure.\n */\nexport function testRunDenialCode(diagnostic: MarquetteDiagnostic): TestRunDenialCode {\n switch (diagnostic.code) {\n case \"VIZE_MARQUETTE_141\":\n return \"admission-id-malformed\";\n case \"VIZE_MARQUETTE_142\":\n return \"admission-id-mismatch\";\n case \"VIZE_MARQUETTE_144\": {\n const mismatch = CANDIDATE_MISMATCH_CODES.get(diagnostic.path);\n if (mismatch !== undefined) {\n return mismatch;\n }\n break;\n }\n case \"VIZE_MARQUETTE_145\":\n return \"record-expired\";\n case \"VIZE_MARQUETTE_146\":\n return \"verification-not-accepted\";\n case \"VIZE_MARQUETTE_147\":\n return \"skipped-tests-recorded\";\n case \"VIZE_MARQUETTE_148\":\n return \"admission-time-malformed\";\n case \"VIZE_MARQUETTE_149\":\n return \"check-candidate-mismatch\";\n case \"VIZE_MARQUETTE_150\":\n return \"check-invalid\";\n case \"VIZE_MARQUETTE_151\":\n return \"check-observer-not-independent\";\n case \"VIZE_MARQUETTE_156\":\n return \"transition-state-mismatch\";\n case \"VIZE_MARQUETTE_157\":\n return \"transition-chain-broken\";\n case \"VIZE_MARQUETTE_158\":\n return \"transition-replayed\";\n case \"VIZE_MARQUETTE_159\":\n return \"transition-state-mismatch\";\n default:\n break;\n }\n if (diagnostic.path.startsWith(\"check.\")) {\n return \"check-invalid\";\n }\n return diagnostic.path.startsWith(\"transition.\") ? \"transition-invalid\" : \"record-invalid\";\n}\n\n/**\n * Decides one candidate and returns the structured admission decision.\n *\n * The decision wraps {@link admitTestRun}: `diagnostics` is exactly its\n * result, `denialCodes` maps every diagnostic through\n * {@link testRunDenialCode} and then deduplicates and sorts the codes\n * lexicographically, and `allowed` is true only when both are empty. Codes,\n * ordering, and diagnostics are identical to the native implementation, as\n * pinned by the shared decision fixtures. Inputs carry the same obligations\n * as {@link admitTestRun}.\n */\nexport async function decideTestRunAdmission(\n evidence: TestRunEvidence,\n candidate: TestRunCandidate,\n admissionId: string,\n now: string,\n): Promise<TestRunAdmissionDecision> {\n const diagnostics = await admitTestRun(evidence, candidate, admissionId, now);\n const denialCodes = [...new Set(diagnostics.map(testRunDenialCode))].sort();\n return { allowed: diagnostics.length === 0, denialCodes, diagnostics };\n}\n"],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://vizejs.dev/schemas/marquette/test-run-admission.schema.json",
4
+ "title": "Vize Test Run Admission Decision",
5
+ "description": "Language-neutral allow-or-deny decision that one test-run evidence record produces for one exact release candidate at one instant. Every backend family (JavaScript, Rust, Go, JVM) must produce byte-equivalent decisions for the same evidence, candidate, admission id, and admission time; the shared tests/fixtures/test-run-evidence admission-decision fixtures are the conformance source of truth for new host implementations.",
6
+ "$ref": "#/$defs/decision",
7
+ "$defs": {
8
+ "denialCode": {
9
+ "description": "Stable machine-readable cause class of one admission denial. The vocabulary is append-only: codes are never renamed, renumbered, reused, or removed, and every new distinguishable rejection cause ships with a new code added to this enum in lexicographic position. Hosts must map every diagnostic to exactly one code: VIZE_MARQUETTE_141 to admission-id-malformed; VIZE_MARQUETTE_142 to admission-id-mismatch; VIZE_MARQUETTE_144 to the candidate-*-mismatch code named by its diagnostic path (application, artifact.fingerprint, contractFingerprint, environment, release, sourceRevision); VIZE_MARQUETTE_145 to record-expired; VIZE_MARQUETTE_146 to verification-not-accepted; VIZE_MARQUETTE_147 to skipped-tests-recorded; VIZE_MARQUETTE_148 to admission-time-malformed; VIZE_MARQUETTE_149 to check-candidate-mismatch; VIZE_MARQUETTE_150 to check-invalid; VIZE_MARQUETTE_151 to check-observer-not-independent; VIZE_MARQUETTE_156 to transition-state-mismatch; VIZE_MARQUETTE_157 to transition-chain-broken; VIZE_MARQUETTE_158 to transition-replayed; VIZE_MARQUETTE_159 to transition-state-mismatch; every other diagnostic whose path starts with check. to check-invalid; every other diagnostic whose path starts with transition. to transition-invalid; and every remaining diagnostic, including every record-validation code, to record-invalid.",
10
+ "enum": [
11
+ "admission-id-malformed",
12
+ "admission-id-mismatch",
13
+ "admission-time-malformed",
14
+ "candidate-application-mismatch",
15
+ "candidate-artifact-fingerprint-mismatch",
16
+ "candidate-contract-fingerprint-mismatch",
17
+ "candidate-environment-mismatch",
18
+ "candidate-release-mismatch",
19
+ "candidate-source-revision-mismatch",
20
+ "check-candidate-mismatch",
21
+ "check-invalid",
22
+ "check-observer-not-independent",
23
+ "record-expired",
24
+ "record-invalid",
25
+ "skipped-tests-recorded",
26
+ "transition-chain-broken",
27
+ "transition-invalid",
28
+ "transition-replayed",
29
+ "transition-state-mismatch",
30
+ "verification-not-accepted"
31
+ ]
32
+ },
33
+ "diagnostic": {
34
+ "description": "One stable, source-addressable diagnostic explaining a denial cause. Codes, severities, paths, messages, and ordering are identical across host families.",
35
+ "type": "object",
36
+ "additionalProperties": false,
37
+ "required": ["code", "severity", "path", "message"],
38
+ "properties": {
39
+ "code": {
40
+ "description": "Stable machine-readable diagnostic code.",
41
+ "type": "string",
42
+ "pattern": "^VIZE_MARQUETTE_[0-9]{3}$"
43
+ },
44
+ "severity": {
45
+ "description": "Diagnostic severity; any diagnostic denies admission.",
46
+ "enum": ["error", "warning"]
47
+ },
48
+ "path": {
49
+ "description": "JSON-style path into the record or the admission input.",
50
+ "type": "string",
51
+ "minLength": 1
52
+ },
53
+ "message": {
54
+ "description": "Human-readable explanation and next action.",
55
+ "type": "string",
56
+ "minLength": 1
57
+ }
58
+ }
59
+ },
60
+ "decision": {
61
+ "description": "Structured admission decision. allowed is true only when denialCodes and diagnostics are both empty. denialCodes maps every diagnostic to its denial code, deduplicated and sorted lexicographically by Unicode code point. diagnostics keeps the stable path, code, message order shared by every implementation.",
62
+ "type": "object",
63
+ "additionalProperties": false,
64
+ "required": ["allowed", "denialCodes", "diagnostics"],
65
+ "properties": {
66
+ "allowed": {
67
+ "description": "Whether the record admits the candidate.",
68
+ "type": "boolean"
69
+ },
70
+ "denialCodes": {
71
+ "description": "Deduplicated denial causes in lexicographic order; empty when allowed.",
72
+ "type": "array",
73
+ "uniqueItems": true,
74
+ "items": { "$ref": "#/$defs/denialCode" }
75
+ },
76
+ "diagnostics": {
77
+ "description": "Complete denial diagnostics; empty when allowed.",
78
+ "type": "array",
79
+ "items": { "$ref": "#/$defs/diagnostic" }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,35 @@
1
+ import { i as TestRunEvidence } from "./test-run-model-DkllmEsY.mjs";
2
+
3
+ //#region src/test-run-canonical.d.ts
4
+ /** Prefix of every test-run deployment admission id. */
5
+ declare const TEST_RUN_ADMISSION_PREFIX = "test-run:";
6
+ /**
7
+ * Serializes a test-run evidence record canonically.
8
+ *
9
+ * Property order matches the record schema, targets sort by id, suites sort
10
+ * by id then shard index, and selection identifiers sort lexicographically,
11
+ * so equivalent records produce byte-identical JSON in every language. Call
12
+ * validation before trusting the record; canonicalization does not make an
13
+ * invalid record valid.
14
+ */
15
+ declare function canonicalTestRunJson(evidence: TestRunEvidence): string;
16
+ /**
17
+ * Returns the lowercase SHA-256 fingerprint of the canonical record.
18
+ *
19
+ * The fingerprint is the exact value admitted as `test-run:<sha256>` by
20
+ * deployment gates. Uses the Web Crypto API available in every supported
21
+ * runtime.
22
+ */
23
+ declare function testRunFingerprint(evidence: TestRunEvidence): Promise<string>;
24
+ /** Returns the `test-run:<sha256>` admission id for one record. */
25
+ declare function testRunAdmissionId(evidence: TestRunEvidence): Promise<string>;
26
+ /**
27
+ * Returns the fingerprint named by a `test-run:<sha256>` admission id.
28
+ *
29
+ * Returns `undefined` unless the prefix, length, and lowercase hexadecimal
30
+ * grammar are all exact.
31
+ */
32
+ declare function parseTestRunAdmissionId(id: string): string | undefined;
33
+ //#endregion
34
+ export { testRunFingerprint as a, testRunAdmissionId as i, canonicalTestRunJson as n, parseTestRunAdmissionId as r, TEST_RUN_ADMISSION_PREFIX as t };
35
+ //# sourceMappingURL=test-run-canonical-CB-KzZxk.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-run-canonical-CB-KzZxk.d.mts","names":[],"sources":["../src/test-run-canonical.ts"],"mappings":";;;;cAQa,yBAAA;AAAb;;;;;AAwCA;;;;AAxCA,iBAwCgB,oBAAA,CAAqB,QAAA,EAAU,eAAA;AA6D/C;;;;;;;AAAA,iBAAsB,kBAAA,CAAmB,QAAA,EAAU,eAAA,GAAkB,OAAA;;iBAW/C,kBAAA,CAAmB,QAAA,EAAU,eAAA,GAAkB,OAAA;;;;;;;iBAUrD,uBAAA,CAAwB,EAAA"}
@@ -1,35 +1,2 @@
1
- import { i as TestRunEvidence } from "./test-run-model-DkllmEsY.mjs";
2
-
3
- //#region src/test-run-canonical.d.ts
4
- /** Prefix of every test-run deployment admission id. */
5
- declare const TEST_RUN_ADMISSION_PREFIX = "test-run:";
6
- /**
7
- * Serializes a test-run evidence record canonically.
8
- *
9
- * Property order matches the record schema, targets sort by id, suites sort
10
- * by id then shard index, and selection identifiers sort lexicographically,
11
- * so equivalent records produce byte-identical JSON in every language. Call
12
- * validation before trusting the record; canonicalization does not make an
13
- * invalid record valid.
14
- */
15
- declare function canonicalTestRunJson(evidence: TestRunEvidence): string;
16
- /**
17
- * Returns the lowercase SHA-256 fingerprint of the canonical record.
18
- *
19
- * The fingerprint is the exact value admitted as `test-run:<sha256>` by
20
- * deployment gates. Uses the Web Crypto API available in every supported
21
- * runtime.
22
- */
23
- declare function testRunFingerprint(evidence: TestRunEvidence): Promise<string>;
24
- /** Returns the `test-run:<sha256>` admission id for one record. */
25
- declare function testRunAdmissionId(evidence: TestRunEvidence): Promise<string>;
26
- /**
27
- * Returns the fingerprint named by a `test-run:<sha256>` admission id.
28
- *
29
- * Returns `undefined` unless the prefix, length, and lowercase hexadecimal
30
- * grammar are all exact.
31
- */
32
- declare function parseTestRunAdmissionId(id: string): string | undefined;
33
- //#endregion
34
- export { TEST_RUN_ADMISSION_PREFIX, canonicalTestRunJson, parseTestRunAdmissionId, testRunAdmissionId, testRunFingerprint };
35
- //# sourceMappingURL=test-run-canonical.d.mts.map
1
+ import { a as testRunFingerprint, i as testRunAdmissionId, n as canonicalTestRunJson, r as parseTestRunAdmissionId, t as TEST_RUN_ADMISSION_PREFIX } from "./test-run-canonical-CB-KzZxk.mjs";
2
+ export { TEST_RUN_ADMISSION_PREFIX, canonicalTestRunJson, parseTestRunAdmissionId, testRunAdmissionId, testRunFingerprint };