@dogfood-lab/schemas 1.3.1 → 1.4.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/README.md +1 -1
- package/dist/enums.d.ts +53 -0
- package/dist/enums.d.ts.map +1 -0
- package/dist/enums.js +63 -0
- package/dist/enums.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -3
- package/dist/index.js.map +1 -1
- package/dist/schema-versions.d.ts +45 -0
- package/dist/schema-versions.d.ts.map +1 -0
- package/dist/schema-versions.js +38 -0
- package/dist/schema-versions.js.map +1 -0
- package/package.json +2 -1
- package/src/json/agent-output.schema.json +130 -0
- package/src/json/policy.schema.json +53 -0
- package/src/json/scenario.schema.json +11 -0
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ import recordSchema from '@dogfood-lab/schemas/json/dogfood-record.schema.json'
|
|
|
70
70
|
| | Constraint |
|
|
71
71
|
|---|---|
|
|
72
72
|
| JSON Schema dialect | 2020-12 |
|
|
73
|
-
| Node | ≥
|
|
73
|
+
| Node | ≥ 22 |
|
|
74
74
|
| `$id` form | `https://github.com/dogfood-lab/testing-os/packages/schemas/src/json/<name>.schema.json` |
|
|
75
75
|
|
|
76
76
|
`$id` is a contract field. Changes that consumers should treat as contract changes bump the monorepo's lockstep version.
|
package/dist/enums.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract enums — the single source of truth for the three FULL-SET enums
|
|
3
|
+
* that the contract JSON schemas declare identically across multiple files.
|
|
4
|
+
*
|
|
5
|
+
* F1-CONTRACTS-002 (Wave 4, MED). Three full-set enums are hand-maintained as
|
|
6
|
+
* identical literal arrays across the contract schema JSON documents:
|
|
7
|
+
*
|
|
8
|
+
* - product_surface ["cli","desktop","web","api","mcp-server",
|
|
9
|
+
* "npm-package","plugin","library"] — 7 files
|
|
10
|
+
* - execution_mode ["bot","human","mixed"] — 7 files
|
|
11
|
+
* - evidence-kind ["log","screenshot","recording",
|
|
12
|
+
* "transcript","artifact","other"] — 4 files
|
|
13
|
+
*
|
|
14
|
+
* `stageC-cross-contract-enum-seal.test.ts` DETECTS drift between those JSON
|
|
15
|
+
* copies, but nothing EXPORTS the sets as importable values. A consumer that
|
|
16
|
+
* wants to render the surface picker, validate a CLI `--surface` flag, or
|
|
17
|
+
* iterate the evidence kinds had to hand-copy the array — a fresh drift source
|
|
18
|
+
* the seal cannot see.
|
|
19
|
+
*
|
|
20
|
+
* These constants are the value consumers import (NOT a hand-copied literal),
|
|
21
|
+
* mirroring `SUPPORTED_SCHEMA_VERSIONS` in `src/schema-versions.ts`:
|
|
22
|
+
* - downstream packages import the set instead of re-typing it;
|
|
23
|
+
* - the seal test asserts each JSON-schema enum EQUALS the matching constant,
|
|
24
|
+
* converting drift-detect into single-source ENFORCEMENT — a JSON enum that
|
|
25
|
+
* diverges from the constant here goes RED.
|
|
26
|
+
*
|
|
27
|
+
* SCOPE — FULL-SET enums only. `doctrine.transfer_scope` is a DELIBERATE
|
|
28
|
+
* 3-value subset (["surface_archetype","execution_mode","org_wide"]) of the
|
|
29
|
+
* 5-value `transfer_scope` carried by finding/recommendation/pattern, and is
|
|
30
|
+
* intentionally NOT exported here as a sealed full-set enum — the seal must
|
|
31
|
+
* leave it alone.
|
|
32
|
+
*
|
|
33
|
+
* `as const` keeps the literal element types and freezes member order, so the
|
|
34
|
+
* arrays double as `readonly` tuples for `typeof PRODUCT_SURFACES[number]`
|
|
35
|
+
* union derivation downstream.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* The full set of product surfaces a tested artifact can target. Order matches
|
|
39
|
+
* the contract JSON enums byte-for-byte (the seal asserts sorted-set identity,
|
|
40
|
+
* but consumers that render a picker get a stable, intentional order).
|
|
41
|
+
*/
|
|
42
|
+
export declare const PRODUCT_SURFACES: readonly ["cli", "desktop", "web", "api", "mcp-server", "npm-package", "plugin", "library"];
|
|
43
|
+
/** How the work under test was executed. */
|
|
44
|
+
export declare const EXECUTION_MODES: readonly ["bot", "human", "mixed"];
|
|
45
|
+
/** The kinds of evidence a record may carry. */
|
|
46
|
+
export declare const EVIDENCE_KINDS: readonly ["log", "screenshot", "recording", "transcript", "artifact", "other"];
|
|
47
|
+
/** Union of the eight product surfaces. */
|
|
48
|
+
export type ProductSurface = (typeof PRODUCT_SURFACES)[number];
|
|
49
|
+
/** Union of the three execution modes. */
|
|
50
|
+
export type ExecutionMode = (typeof EXECUTION_MODES)[number];
|
|
51
|
+
/** Union of the six evidence kinds. */
|
|
52
|
+
export type EvidenceKind = (typeof EVIDENCE_KINDS)[number];
|
|
53
|
+
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../src/enums.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6FASnB,CAAC;AAEX,4CAA4C;AAC5C,eAAO,MAAM,eAAe,oCAAqC,CAAC;AAElE,gDAAgD;AAChD,eAAO,MAAM,cAAc,gFAOjB,CAAC;AAEX,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC/D,0CAA0C;AAC1C,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAC7D,uCAAuC;AACvC,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/enums.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract enums — the single source of truth for the three FULL-SET enums
|
|
3
|
+
* that the contract JSON schemas declare identically across multiple files.
|
|
4
|
+
*
|
|
5
|
+
* F1-CONTRACTS-002 (Wave 4, MED). Three full-set enums are hand-maintained as
|
|
6
|
+
* identical literal arrays across the contract schema JSON documents:
|
|
7
|
+
*
|
|
8
|
+
* - product_surface ["cli","desktop","web","api","mcp-server",
|
|
9
|
+
* "npm-package","plugin","library"] — 7 files
|
|
10
|
+
* - execution_mode ["bot","human","mixed"] — 7 files
|
|
11
|
+
* - evidence-kind ["log","screenshot","recording",
|
|
12
|
+
* "transcript","artifact","other"] — 4 files
|
|
13
|
+
*
|
|
14
|
+
* `stageC-cross-contract-enum-seal.test.ts` DETECTS drift between those JSON
|
|
15
|
+
* copies, but nothing EXPORTS the sets as importable values. A consumer that
|
|
16
|
+
* wants to render the surface picker, validate a CLI `--surface` flag, or
|
|
17
|
+
* iterate the evidence kinds had to hand-copy the array — a fresh drift source
|
|
18
|
+
* the seal cannot see.
|
|
19
|
+
*
|
|
20
|
+
* These constants are the value consumers import (NOT a hand-copied literal),
|
|
21
|
+
* mirroring `SUPPORTED_SCHEMA_VERSIONS` in `src/schema-versions.ts`:
|
|
22
|
+
* - downstream packages import the set instead of re-typing it;
|
|
23
|
+
* - the seal test asserts each JSON-schema enum EQUALS the matching constant,
|
|
24
|
+
* converting drift-detect into single-source ENFORCEMENT — a JSON enum that
|
|
25
|
+
* diverges from the constant here goes RED.
|
|
26
|
+
*
|
|
27
|
+
* SCOPE — FULL-SET enums only. `doctrine.transfer_scope` is a DELIBERATE
|
|
28
|
+
* 3-value subset (["surface_archetype","execution_mode","org_wide"]) of the
|
|
29
|
+
* 5-value `transfer_scope` carried by finding/recommendation/pattern, and is
|
|
30
|
+
* intentionally NOT exported here as a sealed full-set enum — the seal must
|
|
31
|
+
* leave it alone.
|
|
32
|
+
*
|
|
33
|
+
* `as const` keeps the literal element types and freezes member order, so the
|
|
34
|
+
* arrays double as `readonly` tuples for `typeof PRODUCT_SURFACES[number]`
|
|
35
|
+
* union derivation downstream.
|
|
36
|
+
*/
|
|
37
|
+
/**
|
|
38
|
+
* The full set of product surfaces a tested artifact can target. Order matches
|
|
39
|
+
* the contract JSON enums byte-for-byte (the seal asserts sorted-set identity,
|
|
40
|
+
* but consumers that render a picker get a stable, intentional order).
|
|
41
|
+
*/
|
|
42
|
+
export const PRODUCT_SURFACES = [
|
|
43
|
+
'cli',
|
|
44
|
+
'desktop',
|
|
45
|
+
'web',
|
|
46
|
+
'api',
|
|
47
|
+
'mcp-server',
|
|
48
|
+
'npm-package',
|
|
49
|
+
'plugin',
|
|
50
|
+
'library',
|
|
51
|
+
];
|
|
52
|
+
/** How the work under test was executed. */
|
|
53
|
+
export const EXECUTION_MODES = ['bot', 'human', 'mixed'];
|
|
54
|
+
/** The kinds of evidence a record may carry. */
|
|
55
|
+
export const EVIDENCE_KINDS = [
|
|
56
|
+
'log',
|
|
57
|
+
'screenshot',
|
|
58
|
+
'recording',
|
|
59
|
+
'transcript',
|
|
60
|
+
'artifact',
|
|
61
|
+
'other',
|
|
62
|
+
];
|
|
63
|
+
//# sourceMappingURL=enums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../src/enums.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,KAAK;IACL,SAAS;IACT,KAAK;IACL,KAAK;IACL,YAAY;IACZ,aAAa;IACb,QAAQ;IACR,SAAS;CACD,CAAC;AAEX,4CAA4C;AAC5C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAU,CAAC;AAElE,gDAAgD;AAChD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK;IACL,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,UAAU;IACV,OAAO;CACC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -28,5 +28,19 @@ export declare const allSchemas: {
|
|
|
28
28
|
readonly scenario: JsonSchema;
|
|
29
29
|
};
|
|
30
30
|
export type SchemaName = keyof typeof allSchemas;
|
|
31
|
+
/**
|
|
32
|
+
* Test-only seam for d1-schemas-B002. Exposes the module-private {@link load}
|
|
33
|
+
* so the parse-error-context guard can be exercised against a corrupt fixture
|
|
34
|
+
* without touching the real bundled `src/json` tree. Mirrors the existing
|
|
35
|
+
* `_resetValidatorCacheForTests` / `_schemasModuleInstanceCount` test exports —
|
|
36
|
+
* underscore-prefixed, not part of the public API.
|
|
37
|
+
*
|
|
38
|
+
* @param filename schema basename, e.g. `dogfood-record.schema.json`
|
|
39
|
+
* @param dirOverride optional directory to read from instead of the bundled
|
|
40
|
+
* `jsonDir` (tests point this at a TEST_ROOT temp dir)
|
|
41
|
+
*/
|
|
42
|
+
export declare function _loadSchemaForTests(filename: string, dirOverride?: string): JsonSchema;
|
|
31
43
|
export { compileSchema, validatePayload, createAjv, _resetValidatorCacheForTests, _schemasModuleInstanceCount, type ValidationError, type ValidationResult, } from './validate.js';
|
|
44
|
+
export { SUPPORTED_SCHEMA_VERSIONS, type SupportedSchemaVersion, type SupportedSchemaContract, } from './schema-versions.js';
|
|
45
|
+
export { PRODUCT_SURFACES, EXECUTION_MODES, EVIDENCE_KINDS, type ProductSurface, type ExecutionMode, type EvidenceKind, } from './enums.js';
|
|
32
46
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6DA,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,EAAE,UAA+C,CAAC;AAC3E,eAAO,MAAM,sBAAsB,EAAE,UAA0D,CAAC;AAChG,eAAO,MAAM,aAAa,EAAE,UAAgD,CAAC;AAC7E,eAAO,MAAM,aAAa,EAAE,UAAgD,CAAC;AAC7E,eAAO,MAAM,oBAAoB,EAAE,UAAuD,CAAC;AAC3F,eAAO,MAAM,cAAc,EAAE,UAAiD,CAAC;AAC/E,eAAO,MAAM,YAAY,EAAE,UAAuC,CAAC;AACnE,eAAO,MAAM,cAAc,EAAE,UAAyC,CAAC;AAEvE,eAAO,MAAM,UAAU;;;;;;;;;CASb,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,UAAU,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAEtF;AAED,OAAO,EACL,aAAa,EACb,eAAe,EACf,SAAS,EACT,4BAA4B,EAC5B,2BAA2B,EAC3B,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,9 +18,37 @@ import { dirname, resolve } from 'node:path';
|
|
|
18
18
|
import { fileURLToPath } from 'node:url';
|
|
19
19
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const jsonDir = resolve(here, '../src/json');
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Load and parse a bundled JSON schema.
|
|
23
|
+
*
|
|
24
|
+
* d1-schemas-B002 — readFileSync + JSON.parse are wrapped so a corrupt or
|
|
25
|
+
* truncated package-bundled `src/json/*.schema.json` (a packaging defect that
|
|
26
|
+
* can ship in a tarball) throws a SELF-IDENTIFYING error at module-init instead
|
|
27
|
+
* of a bare `SyntaxError: Unexpected end of JSON input` that names no file. The
|
|
28
|
+
* rethrown message names the package and the offending filename so the consumer
|
|
29
|
+
* knows exactly which of the eight schemas to inspect/re-install — they do not
|
|
30
|
+
* have to bisect by hand. This is the only structured channel available at
|
|
31
|
+
* module-init (no CLI renderer / no logStage pipeline exists this early), so the
|
|
32
|
+
* helpful contract is "a thrown Error whose message carries the recovery handle."
|
|
33
|
+
*
|
|
34
|
+
* `dirOverride` exists only for the test seam (`_loadSchemaForTests`); production
|
|
35
|
+
* callers always read from the real bundled `jsonDir`.
|
|
36
|
+
*/
|
|
37
|
+
function load(filename, dirOverride) {
|
|
38
|
+
const path = resolve(dirOverride ?? jsonDir, filename);
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = readFileSync(path, 'utf8');
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
throw new Error(`@dogfood-lab/schemas: failed to read bundled schema ${filename} (at ${path}): ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
throw new Error(`@dogfood-lab/schemas: failed to parse bundled schema ${filename} (at ${path}) as JSON — the package artifact may be corrupt or truncated: ${e.message}`);
|
|
51
|
+
}
|
|
24
52
|
}
|
|
25
53
|
export const recordSchema = load('dogfood-record.schema.json');
|
|
26
54
|
export const recordSubmissionSchema = load('dogfood-record-submission.schema.json');
|
|
@@ -40,5 +68,21 @@ export const allSchemas = {
|
|
|
40
68
|
policy: policySchema,
|
|
41
69
|
scenario: scenarioSchema,
|
|
42
70
|
};
|
|
71
|
+
/**
|
|
72
|
+
* Test-only seam for d1-schemas-B002. Exposes the module-private {@link load}
|
|
73
|
+
* so the parse-error-context guard can be exercised against a corrupt fixture
|
|
74
|
+
* without touching the real bundled `src/json` tree. Mirrors the existing
|
|
75
|
+
* `_resetValidatorCacheForTests` / `_schemasModuleInstanceCount` test exports —
|
|
76
|
+
* underscore-prefixed, not part of the public API.
|
|
77
|
+
*
|
|
78
|
+
* @param filename schema basename, e.g. `dogfood-record.schema.json`
|
|
79
|
+
* @param dirOverride optional directory to read from instead of the bundled
|
|
80
|
+
* `jsonDir` (tests point this at a TEST_ROOT temp dir)
|
|
81
|
+
*/
|
|
82
|
+
export function _loadSchemaForTests(filename, dirOverride) {
|
|
83
|
+
return load(filename, dirOverride);
|
|
84
|
+
}
|
|
43
85
|
export { compileSchema, validatePayload, createAjv, _resetValidatorCacheForTests, _schemasModuleInstanceCount, } from './validate.js';
|
|
86
|
+
export { SUPPORTED_SCHEMA_VERSIONS, } from './schema-versions.js';
|
|
87
|
+
export { PRODUCT_SURFACES, EXECUTION_MODES, EVIDENCE_KINDS, } from './enums.js';
|
|
44
88
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAE7C,SAAS,IAAI,CAAC,QAAgB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AAE7C;;;;;;;;;;;;;;;GAeG;AACH,SAAS,IAAI,CAAC,QAAgB,EAAE,WAAoB;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,uDAAuD,QAAQ,QAAQ,IAAI,MACxE,CAAW,CAAC,OACf,EAAE,CACH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACvC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,wDAAwD,QAAQ,QAAQ,IAAI,iEACzE,CAAW,CAAC,OACf,EAAE,CACH,CAAC;IACJ,CAAC;AACH,CAAC;AAcD,MAAM,CAAC,MAAM,YAAY,GAAe,IAAI,CAAC,4BAA4B,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAe,IAAI,CAAC,uCAAuC,CAAC,CAAC;AAChG,MAAM,CAAC,MAAM,aAAa,GAAe,IAAI,CAAC,6BAA6B,CAAC,CAAC;AAC7E,MAAM,CAAC,MAAM,aAAa,GAAe,IAAI,CAAC,6BAA6B,CAAC,CAAC;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAe,IAAI,CAAC,oCAAoC,CAAC,CAAC;AAC3F,MAAM,CAAC,MAAM,cAAc,GAAe,IAAI,CAAC,8BAA8B,CAAC,CAAC;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAe,IAAI,CAAC,oBAAoB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,cAAc,GAAe,IAAI,CAAC,sBAAsB,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,YAAY;IACpB,gBAAgB,EAAE,sBAAsB;IACxC,OAAO,EAAE,aAAa;IACtB,OAAO,EAAE,aAAa;IACtB,cAAc,EAAE,oBAAoB;IACpC,QAAQ,EAAE,cAAc;IACxB,MAAM,EAAE,YAAY;IACpB,QAAQ,EAAE,cAAc;CAChB,CAAC;AAIX;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,WAAoB;IACxE,OAAO,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrC,CAAC;AAED,OAAO,EACL,aAAa,EACb,eAAe,EACf,SAAS,EACT,4BAA4B,EAC5B,2BAA2B,GAG5B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,yBAAyB,GAG1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,cAAc,GAIf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SUPPORTED_SCHEMA_VERSIONS — the single source of truth for which
|
|
3
|
+
* `schema_version` values this build of testing-os accepts.
|
|
4
|
+
*
|
|
5
|
+
* F1-CONTRACTS-001 (Wave 2, HIGH). Every contract schema declares
|
|
6
|
+
* `schema_version` as a pattern-only string (`^\d+\.\d+\.\d+$`) — it gates
|
|
7
|
+
* SHAPE, not VALUE. Nothing compared a declared `schema_version` against a
|
|
8
|
+
* supported set, so a submission declaring `schema_version: '2.0.0'` (or
|
|
9
|
+
* `99.0.0`) validated clean against the live 1.x schema whenever its shape
|
|
10
|
+
* happened to fit: a genuinely-incompatible future major was silently
|
|
11
|
+
* mis-validated instead of cleanly refused.
|
|
12
|
+
*
|
|
13
|
+
* This map is the value consumers import (NOT a hand-copied literal):
|
|
14
|
+
* - `packages/verify` imports it to drive the `schema_version` VALUE gate
|
|
15
|
+
* (`validators/schema-version.js`) and to stamp the persisted record's
|
|
16
|
+
* `schema_version` (`record.current`) instead of a hardcoded `'1.0.0'`.
|
|
17
|
+
*
|
|
18
|
+
* Per registered contract: the `current` version plus the accepted MAJOR
|
|
19
|
+
* range `[minMajor, maxMajor]`. The gate compares a payload's MAJOR against
|
|
20
|
+
* that range — patch/minor deltas inside the range PASS; a major above
|
|
21
|
+
* `maxMajor` means "this build is too old, upgrade testing-os"; a major below
|
|
22
|
+
* `minMajor` means "re-emit against the current contract".
|
|
23
|
+
*
|
|
24
|
+
* Keys mirror `allSchemas` for the contracts that carry a `schema_version`
|
|
25
|
+
* field, plus the `agentOutput` swarm envelope. `policy` and `scenario` do
|
|
26
|
+
* NOT carry a `schema_version` contract field and are intentionally absent —
|
|
27
|
+
* the gate only fires on payloads that declare a `schema_version`.
|
|
28
|
+
*/
|
|
29
|
+
export interface SupportedSchemaVersion {
|
|
30
|
+
/** The current/canonical version this build emits for the contract. */
|
|
31
|
+
current: string;
|
|
32
|
+
/** Lowest MAJOR this build will accept (inclusive). Below → TOO_OLD. */
|
|
33
|
+
minMajor: number;
|
|
34
|
+
/** Highest MAJOR this build will accept (inclusive). Above → TOO_NEW. */
|
|
35
|
+
maxMajor: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The registered contract keys that carry a `schema_version`. `record` and
|
|
39
|
+
* `recordSubmission` share the v1 record family; `agentOutput` is the swarm
|
|
40
|
+
* agent-output envelope (validated separately at collect time, registered
|
|
41
|
+
* here so a future versioned envelope has one home).
|
|
42
|
+
*/
|
|
43
|
+
export type SupportedSchemaContract = 'record' | 'recordSubmission' | 'finding' | 'pattern' | 'recommendation' | 'doctrine' | 'agentOutput';
|
|
44
|
+
export declare const SUPPORTED_SCHEMA_VERSIONS: Record<SupportedSchemaContract, SupportedSchemaVersion>;
|
|
45
|
+
//# sourceMappingURL=schema-versions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-versions.d.ts","sourceRoot":"","sources":["../src/schema-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAC/B,QAAQ,GACR,kBAAkB,GAClB,SAAS,GACT,SAAS,GACT,gBAAgB,GAChB,UAAU,GACV,aAAa,CAAC;AAElB,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAC5C,uBAAuB,EACvB,sBAAsB,CASd,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SUPPORTED_SCHEMA_VERSIONS — the single source of truth for which
|
|
3
|
+
* `schema_version` values this build of testing-os accepts.
|
|
4
|
+
*
|
|
5
|
+
* F1-CONTRACTS-001 (Wave 2, HIGH). Every contract schema declares
|
|
6
|
+
* `schema_version` as a pattern-only string (`^\d+\.\d+\.\d+$`) — it gates
|
|
7
|
+
* SHAPE, not VALUE. Nothing compared a declared `schema_version` against a
|
|
8
|
+
* supported set, so a submission declaring `schema_version: '2.0.0'` (or
|
|
9
|
+
* `99.0.0`) validated clean against the live 1.x schema whenever its shape
|
|
10
|
+
* happened to fit: a genuinely-incompatible future major was silently
|
|
11
|
+
* mis-validated instead of cleanly refused.
|
|
12
|
+
*
|
|
13
|
+
* This map is the value consumers import (NOT a hand-copied literal):
|
|
14
|
+
* - `packages/verify` imports it to drive the `schema_version` VALUE gate
|
|
15
|
+
* (`validators/schema-version.js`) and to stamp the persisted record's
|
|
16
|
+
* `schema_version` (`record.current`) instead of a hardcoded `'1.0.0'`.
|
|
17
|
+
*
|
|
18
|
+
* Per registered contract: the `current` version plus the accepted MAJOR
|
|
19
|
+
* range `[minMajor, maxMajor]`. The gate compares a payload's MAJOR against
|
|
20
|
+
* that range — patch/minor deltas inside the range PASS; a major above
|
|
21
|
+
* `maxMajor` means "this build is too old, upgrade testing-os"; a major below
|
|
22
|
+
* `minMajor` means "re-emit against the current contract".
|
|
23
|
+
*
|
|
24
|
+
* Keys mirror `allSchemas` for the contracts that carry a `schema_version`
|
|
25
|
+
* field, plus the `agentOutput` swarm envelope. `policy` and `scenario` do
|
|
26
|
+
* NOT carry a `schema_version` contract field and are intentionally absent —
|
|
27
|
+
* the gate only fires on payloads that declare a `schema_version`.
|
|
28
|
+
*/
|
|
29
|
+
export const SUPPORTED_SCHEMA_VERSIONS = {
|
|
30
|
+
record: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
31
|
+
recordSubmission: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
32
|
+
finding: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
33
|
+
pattern: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
34
|
+
recommendation: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
35
|
+
doctrine: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
36
|
+
agentOutput: { current: '1.0.0', minMajor: 1, maxMajor: 1 },
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=schema-versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-versions.js","sourceRoot":"","sources":["../src/schema-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA0BH,MAAM,CAAC,MAAM,yBAAyB,GAGlC;IACF,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IACtD,gBAAgB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IAChE,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IACvD,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IACvD,cAAc,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IAC9D,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;IACxD,WAAW,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;CACnD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogfood-lab/schemas",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "JSON schemas for the testing-os contract spine — record, finding, pattern, recommendation, doctrine, policy, scenario, submission.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"ajv-formats": "^3.0.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
+
"@dogfood-lab/dogfood-swarm": "*",
|
|
36
37
|
"@types/node": "^25.3.5",
|
|
37
38
|
"vitest": "^4.1.6"
|
|
38
39
|
},
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/dogfood-lab/testing-os/packages/schemas/src/json/agent-output.schema.json",
|
|
4
|
+
"title": "Swarm Agent Output (canonical envelope)",
|
|
5
|
+
"description": "JSON contract for agent JSON outputs written to swarms/<run-id>/wave-N/<domain>.json. F-252713-017 (Phase 7 wave 1): collect-time schema-conformance gate. Replaces silent normalization in collect.js with a structured error pointing the agent at the canonical shape. Validates the OUTER envelope ONLY — every agent output regardless of phase has { domain, summary } at minimum; findings[]/features[]/fixes[]/files_changed[] are all independently optional here (additionalProperties:true). This schema does NOT enforce phase-specific inner shape — there is no oneOf/if-then/dependentRequired branch keyed on phase. Phase-specific inner-shape enforcement (audit outputs require findings[], feature outputs require features[], amend outputs require fixes[] + files_changed[]) is performed separately by packages/dogfood-swarm/lib/output-schema.js (validateAuditOutput/validateFeatureOutput/validateAmendOutput), run by commands/collect.js AFTER this envelope gate. The category/severity/feature-category enums in the $defs below mirror AUDIT_CATEGORIES + FEATURE_CATEGORIES + SEVERITY_ENUM in output-schema.js — kept in lockstep (sealed by packages/schemas/test/stageA-agent-output-lockstep.test.ts).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["domain", "summary"],
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"properties": {
|
|
10
|
+
"domain": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"description": "Audit domain that produced this output (e.g. backend, ci-tooling, docs, outputs, pipeline)."
|
|
14
|
+
},
|
|
15
|
+
"stage": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"enum": ["A", "B", "C", "D"],
|
|
18
|
+
"description": "Health-pass stage (audit outputs only). Optional in feature/amend outputs."
|
|
19
|
+
},
|
|
20
|
+
"summary": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"minLength": 1,
|
|
23
|
+
"description": "One-line summary of what the agent did and what they found."
|
|
24
|
+
},
|
|
25
|
+
"findings": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": { "$ref": "#/$defs/finding" },
|
|
28
|
+
"description": "Audit-pass findings. Required in audit outputs (Stages A–D)."
|
|
29
|
+
},
|
|
30
|
+
"features": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": { "$ref": "#/$defs/feature" },
|
|
33
|
+
"description": "Feature-pass features. Required in feature-pass outputs."
|
|
34
|
+
},
|
|
35
|
+
"fixes": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"items": { "$ref": "#/$defs/fix" },
|
|
38
|
+
"description": "Amend-pass fixes. Required in amend outputs (Phase 7 waves)."
|
|
39
|
+
},
|
|
40
|
+
"files_changed": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": { "type": "string" },
|
|
43
|
+
"description": "Files the agent edited. Required in amend outputs."
|
|
44
|
+
},
|
|
45
|
+
"skipped": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"items": { "$ref": "#/$defs/skip" },
|
|
48
|
+
"description": "Findings/features skipped with a reason. Cross-domain dependencies, blocked-on items, etc."
|
|
49
|
+
},
|
|
50
|
+
"verification_skipped": {
|
|
51
|
+
"type": "boolean",
|
|
52
|
+
"default": false,
|
|
53
|
+
"description": "Set true when the agent skipped per-agent verification per the parallel-wave serial-final-verify discipline (PROTOCOL.md §Serial final verification). Coordinator runs a single `npm run verify` against the cumulative tree at collect time. False or absent = agent ran its own verify (legacy single-agent waves, manual dispatch)."
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"$defs": {
|
|
57
|
+
"finding": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"required": ["id", "severity", "category", "description"],
|
|
60
|
+
"additionalProperties": true,
|
|
61
|
+
"properties": {
|
|
62
|
+
"id": { "type": "string", "minLength": 1 },
|
|
63
|
+
"severity": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"],
|
|
66
|
+
"description": "Mirrors SEVERITY_ENUM in packages/dogfood-swarm/lib/output-schema.js."
|
|
67
|
+
},
|
|
68
|
+
"category": {
|
|
69
|
+
"type": "string",
|
|
70
|
+
"enum": [
|
|
71
|
+
"bug", "security", "quality", "types", "tests", "docs",
|
|
72
|
+
"defensive", "observability", "degradation", "future-proofing",
|
|
73
|
+
"ux", "accessibility",
|
|
74
|
+
"hygiene", "error_message_quality", "cli_help_quality",
|
|
75
|
+
"silent_failure", "tests_coverage"
|
|
76
|
+
],
|
|
77
|
+
"description": "Mirrors AUDIT_CATEGORIES in packages/dogfood-swarm/lib/output-schema.js. Extended in Phase 7 wave 2 W2-BACK-002 to absorb 5 historical wave-15/20 reused categories (hygiene, error_message_quality, cli_help_quality, silent_failure, tests_coverage). Underscore form preserved as historical record."
|
|
78
|
+
},
|
|
79
|
+
"file": { "type": "string" },
|
|
80
|
+
"line": { "type": "number" },
|
|
81
|
+
"symbol": { "type": "string" },
|
|
82
|
+
"description": { "type": "string", "minLength": 1 },
|
|
83
|
+
"recommendation": { "type": "string" },
|
|
84
|
+
"rule_id": { "type": "string" }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"feature": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"required": ["id", "priority", "category", "description"],
|
|
90
|
+
"additionalProperties": true,
|
|
91
|
+
"properties": {
|
|
92
|
+
"id": { "type": "string", "pattern": "^F-[A-Za-z0-9-]+$" },
|
|
93
|
+
"priority": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
|
|
96
|
+
},
|
|
97
|
+
"category": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": ["missing-feature", "ux", "performance", "integration", "production-readiness"]
|
|
100
|
+
},
|
|
101
|
+
"description": { "type": "string", "minLength": 1 },
|
|
102
|
+
"use_case": { "type": "string" },
|
|
103
|
+
"evidence_base": { "type": "string" },
|
|
104
|
+
"scope": { "type": "array", "items": { "type": "string" } },
|
|
105
|
+
"effort": { "type": "string", "enum": ["small", "medium", "large"] },
|
|
106
|
+
"cross_ref": { "type": "string" },
|
|
107
|
+
"recommendation": { "type": "string" }
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"fix": {
|
|
111
|
+
"type": "object",
|
|
112
|
+
"required": ["finding_id", "description"],
|
|
113
|
+
"additionalProperties": true,
|
|
114
|
+
"properties": {
|
|
115
|
+
"finding_id": { "type": "string", "minLength": 1 },
|
|
116
|
+
"file": { "type": "string" },
|
|
117
|
+
"description": { "type": "string", "minLength": 1 }
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"skip": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"required": ["finding_id", "reason"],
|
|
123
|
+
"additionalProperties": true,
|
|
124
|
+
"properties": {
|
|
125
|
+
"finding_id": { "type": "string", "minLength": 1 },
|
|
126
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -103,6 +103,59 @@
|
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
|
|
106
|
+
"allOf": [
|
|
107
|
+
{
|
|
108
|
+
"$comment": "d1-schemas-003 — additive conditional constraint mirroring the H4 precedent in dogfood-finding.schema.json. enforcement.reason and enforcement.review_after have always carried 'Required if ...' descriptions, but until stage A this was honor-system prose the schema dropped silently — a repo could mark itself `exempt` (opting out of Gate F per policy.schema.json:30) with reason:null/review_after:null and validate clean. The schema now enforces it: a warn-only/exempt mode requires a non-null `reason`; an exempt mode additionally requires a `review_after` date. Note the `not const null` guard — the property type is [string,null], and a literal null would satisfy bare `required`, so the value must be constrained to a real justification.",
|
|
109
|
+
"if": {
|
|
110
|
+
"properties": {
|
|
111
|
+
"enforcement": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"properties": {
|
|
114
|
+
"mode": { "enum": ["warn-only", "exempt"] }
|
|
115
|
+
},
|
|
116
|
+
"required": ["mode"]
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
"required": ["enforcement"]
|
|
120
|
+
},
|
|
121
|
+
"then": {
|
|
122
|
+
"properties": {
|
|
123
|
+
"enforcement": {
|
|
124
|
+
"required": ["reason"],
|
|
125
|
+
"properties": {
|
|
126
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"$comment": "d1-schemas-003 (exempt half) — an exempt repo is fully opted out of Gate F, so it additionally requires a scheduled review date. Same null-guard reasoning as the reason half.",
|
|
134
|
+
"if": {
|
|
135
|
+
"properties": {
|
|
136
|
+
"enforcement": {
|
|
137
|
+
"type": "object",
|
|
138
|
+
"properties": {
|
|
139
|
+
"mode": { "const": "exempt" }
|
|
140
|
+
},
|
|
141
|
+
"required": ["mode"]
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"required": ["enforcement"]
|
|
145
|
+
},
|
|
146
|
+
"then": {
|
|
147
|
+
"properties": {
|
|
148
|
+
"enforcement": {
|
|
149
|
+
"required": ["review_after"],
|
|
150
|
+
"properties": {
|
|
151
|
+
"review_after": { "type": "string", "minLength": 1 }
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
|
|
106
159
|
"$defs": {
|
|
107
160
|
"surface_policy": {
|
|
108
161
|
"type": "object",
|
|
@@ -84,6 +84,17 @@
|
|
|
84
84
|
"type": "string",
|
|
85
85
|
"description": "What a passing result looks like. Required if verifiable is true."
|
|
86
86
|
}
|
|
87
|
+
},
|
|
88
|
+
"$comment": "d1-schemas-NEW — third instance of the d1-schemas-003 family. The `expected` description has always said 'Required if verifiable is true', but until stage A nothing enforced it, so a step could claim verifiable:true with no pass condition and validate clean. A keyed if/then (NOT a dependentRequired, which fires on key presence and would wrongly trip on verifiable:false) requires `expected` only when verifiable === true. Mirrors the H4 precedent in dogfood-finding.schema.json.",
|
|
89
|
+
"if": {
|
|
90
|
+
"properties": { "verifiable": { "const": true } },
|
|
91
|
+
"required": ["verifiable"]
|
|
92
|
+
},
|
|
93
|
+
"then": {
|
|
94
|
+
"required": ["expected"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"expected": { "type": "string", "minLength": 1 }
|
|
97
|
+
}
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
100
|
},
|