@dogfood-lab/schemas 1.2.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 mcp-tool-shop
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 ADDED
@@ -0,0 +1,76 @@
1
+ # @dogfood-lab/schemas
2
+
3
+ > JSON schemas for the testing-os contract spine — record, finding, pattern, recommendation, doctrine, policy, scenario, submission.
4
+
5
+ Part of the [`testing-os`](https://github.com/dogfood-lab/testing-os) monorepo — the operating system for testing in the AI era.
6
+
7
+ This package ships the 8 canonical JSON Schemas (2020-12 dialect) that the testing-os contract spine validates against. Every record, finding, pattern, recommendation, doctrine artifact, policy file, scenario definition, and submission envelope produced by the rest of the monorepo conforms to one of these schemas. Consumer packages (`@dogfood-lab/verify`, `@dogfood-lab/findings`, `@dogfood-lab/report`) load the schemas via the `./json/*` subpath export and compile them with `ajv`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @dogfood-lab/schemas
13
+ ```
14
+
15
+ ## The 8 Schemas
16
+
17
+ | Schema file | Purpose |
18
+ |---|---|
19
+ | `dogfood-record.schema.json` | Persisted test/audit record produced by dogfood runs |
20
+ | `dogfood-record-submission.schema.json` | Envelope shape `repository_dispatch` payloads must match |
21
+ | `dogfood-finding.schema.json` | Evidence-bound finding contract — anchored to source line + severity + status |
22
+ | `dogfood-pattern.schema.json` | Reusable pattern derived from findings (synthesis layer) |
23
+ | `dogfood-recommendation.schema.json` | Recommendation derived from patterns |
24
+ | `dogfood-doctrine.schema.json` | Doctrine artifact synthesized from patterns + recommendations |
25
+ | `policy.schema.json` | Per-repo policy YAML shape (gate accumulation, severity thresholds) |
26
+ | `scenario.schema.json` | Scenario definition shape (what gets tested + how) |
27
+
28
+ ## Usage — TypeScript surface
29
+
30
+ The package exports `validatePayload` and the compiled validators:
31
+
32
+ ```ts
33
+ import { validatePayload } from '@dogfood-lab/schemas';
34
+
35
+ const result = validatePayload(submission, 'dogfood-record-submission');
36
+ if (!result.ok) {
37
+ console.error('schema mismatch:', result.errors);
38
+ process.exit(1);
39
+ }
40
+ ```
41
+
42
+ ## Usage — Raw JSON schemas
43
+
44
+ The raw schema files are available via the `./json/*` subpath export. Use `createRequire` to load them at runtime:
45
+
46
+ ```js
47
+ import { createRequire } from 'node:module';
48
+ const require = createRequire(import.meta.url);
49
+
50
+ const recordSchema = require('@dogfood-lab/schemas/json/dogfood-record.schema.json');
51
+ const findingSchema = require('@dogfood-lab/schemas/json/dogfood-finding.schema.json');
52
+ ```
53
+
54
+ Or with import attributes (Node 22+):
55
+
56
+ ```js
57
+ import recordSchema from '@dogfood-lab/schemas/json/dogfood-record.schema.json' with { type: 'json' };
58
+ ```
59
+
60
+ ## Compatibility
61
+
62
+ | | Constraint |
63
+ |---|---|
64
+ | JSON Schema dialect | 2020-12 |
65
+ | Node | ≥ 20 |
66
+ | `$id` form | `https://github.com/dogfood-lab/testing-os/packages/schemas/src/json/<name>.schema.json` |
67
+
68
+ `$id` is a contract field. Changes that consumers should treat as contract changes bump the monorepo's lockstep version.
69
+
70
+ ## Docs
71
+
72
+ 📖 Full handbook: **<https://dogfood-lab.github.io/testing-os/handbook/>**
73
+
74
+ ## License
75
+
76
+ MIT © 2026 mcp-tool-shop
@@ -0,0 +1,32 @@
1
+ export interface JsonSchema {
2
+ $schema?: string;
3
+ $id?: string;
4
+ title?: string;
5
+ description?: string;
6
+ type?: string | string[];
7
+ required?: string[];
8
+ properties?: Record<string, unknown>;
9
+ additionalProperties?: boolean | JsonSchema;
10
+ [key: string]: unknown;
11
+ }
12
+ export declare const recordSchema: JsonSchema;
13
+ export declare const recordSubmissionSchema: JsonSchema;
14
+ export declare const findingSchema: JsonSchema;
15
+ export declare const patternSchema: JsonSchema;
16
+ export declare const recommendationSchema: JsonSchema;
17
+ export declare const doctrineSchema: JsonSchema;
18
+ export declare const policySchema: JsonSchema;
19
+ export declare const scenarioSchema: JsonSchema;
20
+ export declare const allSchemas: {
21
+ readonly record: JsonSchema;
22
+ readonly recordSubmission: JsonSchema;
23
+ readonly finding: JsonSchema;
24
+ readonly pattern: JsonSchema;
25
+ readonly recommendation: JsonSchema;
26
+ readonly doctrine: JsonSchema;
27
+ readonly policy: JsonSchema;
28
+ readonly scenario: JsonSchema;
29
+ };
30
+ export type SchemaName = keyof typeof allSchemas;
31
+ export { compileSchema, validatePayload, createAjv, _resetValidatorCacheForTests, type ValidationError, type ValidationResult, } from './validate.js';
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,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,OAAO,EACL,aAAa,EACb,eAAe,EACf,SAAS,EACT,4BAA4B,EAC5B,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @dogfood-lab/schemas — JSON-schema spine for testing-os.
3
+ *
4
+ * Each schema is a JSON Schema 2020-12 document. Consumers can either:
5
+ *
6
+ * 1. Import the typed schema object:
7
+ * import { recordSchema } from '@dogfood-lab/schemas';
8
+ *
9
+ * 2. Reference the raw JSON file via the subpath export:
10
+ * import recordSchema from '@dogfood-lab/schemas/json/dogfood-record.schema.json'
11
+ * with { type: 'json' };
12
+ *
13
+ * The schemas are the same files served by the legacy
14
+ * `mcp-tool-shop-org/dogfood-labs/schemas/` URLs during the cutover window.
15
+ */
16
+ import { readFileSync } from 'node:fs';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ const here = dirname(fileURLToPath(import.meta.url));
20
+ const jsonDir = resolve(here, '../src/json');
21
+ function load(filename) {
22
+ const raw = readFileSync(resolve(jsonDir, filename), 'utf8');
23
+ return JSON.parse(raw);
24
+ }
25
+ export const recordSchema = load('dogfood-record.schema.json');
26
+ export const recordSubmissionSchema = load('dogfood-record-submission.schema.json');
27
+ export const findingSchema = load('dogfood-finding.schema.json');
28
+ export const patternSchema = load('dogfood-pattern.schema.json');
29
+ export const recommendationSchema = load('dogfood-recommendation.schema.json');
30
+ export const doctrineSchema = load('dogfood-doctrine.schema.json');
31
+ export const policySchema = load('policy.schema.json');
32
+ export const scenarioSchema = load('scenario.schema.json');
33
+ export const allSchemas = {
34
+ record: recordSchema,
35
+ recordSubmission: recordSubmissionSchema,
36
+ finding: findingSchema,
37
+ pattern: patternSchema,
38
+ recommendation: recommendationSchema,
39
+ doctrine: doctrineSchema,
40
+ policy: policySchema,
41
+ scenario: scenarioSchema,
42
+ };
43
+ export { compileSchema, validatePayload, createAjv, _resetValidatorCacheForTests, } from './validate.js';
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;IAC5B,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;IAC7D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;AACvC,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,OAAO,EACL,aAAa,EACb,eAAe,EACf,SAAS,EACT,4BAA4B,GAG7B,MAAM,eAAe,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Ajv2020 validator factory for the schemas owned by this package.
3
+ *
4
+ * This is the canonical place to compile a testing-os schema. Sibling packages
5
+ * (verify, findings, ingest) historically each wired their own Ajv instance per
6
+ * schema; consumers can now go through {@link compileSchema} or
7
+ * {@link validatePayload} to share one warm validator per schema and stay in
8
+ * lockstep with the contract package itself.
9
+ *
10
+ * Ajv setup mirrors the existing in-tree convention:
11
+ * - `ajv/dist/2020.js` for draft 2020-12
12
+ * - `ajv-formats` registered for `date-time`, `uri`, etc.
13
+ * - `allErrors: true, strict: false`
14
+ *
15
+ * Strict is off because the in-tree schemas use `description` on root objects
16
+ * (which Ajv strict mode treats as an unknown keyword in some contexts) and
17
+ * we want all errors to surface in tests, not just the first.
18
+ */
19
+ import type { ValidateFunction } from 'ajv';
20
+ import { type SchemaName } from './index.js';
21
+ declare const Ajv2020Ctor: new (opts?: {
22
+ allErrors?: boolean;
23
+ strict?: boolean;
24
+ }) => {
25
+ compile: (schema: unknown) => ValidateFunction;
26
+ addFormat: (...args: unknown[]) => unknown;
27
+ };
28
+ export interface ValidationError {
29
+ path: string;
30
+ message: string;
31
+ params?: Record<string, unknown>;
32
+ }
33
+ export interface ValidationResult {
34
+ valid: boolean;
35
+ errors: ValidationError[];
36
+ }
37
+ /**
38
+ * Build a fresh Ajv2020 instance with the in-tree convention. Exposed so
39
+ * callers that need to register additional schemas, vocabularies, or formats
40
+ * can do so without forking this module.
41
+ */
42
+ export declare function createAjv(): InstanceType<typeof Ajv2020Ctor>;
43
+ /**
44
+ * Compile (and cache) the validator for one of the eight named schemas.
45
+ *
46
+ * Use this when you want the raw Ajv {@link ValidateFunction} — for example,
47
+ * to inspect `validate.errors` directly or wire it into a custom error
48
+ * formatter. For the common case prefer {@link validatePayload}.
49
+ */
50
+ export declare function compileSchema(name: SchemaName): ValidateFunction;
51
+ /**
52
+ * Validate a payload against one of the named schemas and return a
53
+ * structured result with normalised error paths/messages.
54
+ *
55
+ * Mirrors the shape used by `packages/verify/validators/schema.js` and
56
+ * `packages/findings/validate.js` so consumers can migrate without
57
+ * refactoring their error-handling code.
58
+ */
59
+ export declare function validatePayload(name: SchemaName, payload: unknown): ValidationResult;
60
+ /**
61
+ * Test-only helper for clearing the compiled-validator cache. Production code
62
+ * should never need this — the cache is correct because schemas are immutable
63
+ * for the lifetime of the process.
64
+ */
65
+ export declare function _resetValidatorCacheForTests(): void;
66
+ export {};
67
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAc,KAAK,UAAU,EAAmB,MAAM,YAAY,CAAC;AAK1E,QAAA,MAAM,WAAW,EAED,KAAK,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK;IACxE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,gBAAgB,CAAC;IAC/C,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;CAC5C,CAAC;AAMF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAID;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,YAAY,CAAC,OAAO,WAAW,CAAC,CAI5D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,gBAAgB,CAahE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,gBAAgB,CAepF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAEnD"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Ajv2020 validator factory for the schemas owned by this package.
3
+ *
4
+ * This is the canonical place to compile a testing-os schema. Sibling packages
5
+ * (verify, findings, ingest) historically each wired their own Ajv instance per
6
+ * schema; consumers can now go through {@link compileSchema} or
7
+ * {@link validatePayload} to share one warm validator per schema and stay in
8
+ * lockstep with the contract package itself.
9
+ *
10
+ * Ajv setup mirrors the existing in-tree convention:
11
+ * - `ajv/dist/2020.js` for draft 2020-12
12
+ * - `ajv-formats` registered for `date-time`, `uri`, etc.
13
+ * - `allErrors: true, strict: false`
14
+ *
15
+ * Strict is off because the in-tree schemas use `description` on root objects
16
+ * (which Ajv strict mode treats as an unknown keyword in some contexts) and
17
+ * we want all errors to surface in tests, not just the first.
18
+ */
19
+ import Ajv2020Module from 'ajv/dist/2020.js';
20
+ import addFormatsModule from 'ajv-formats';
21
+ import { allSchemas } from './index.js';
22
+ // CommonJS default-export interop: under NodeNext+esModuleInterop the named
23
+ // `default` is what we actually want at runtime. Sibling JS packages get this
24
+ // for free via Node's CJS interop; the TS source has to be explicit.
25
+ const Ajv2020Ctor = (Ajv2020Module.default ?? Ajv2020Module);
26
+ const addFormats = (addFormatsModule.default ?? addFormatsModule);
27
+ const validatorCache = new Map();
28
+ /**
29
+ * Build a fresh Ajv2020 instance with the in-tree convention. Exposed so
30
+ * callers that need to register additional schemas, vocabularies, or formats
31
+ * can do so without forking this module.
32
+ */
33
+ export function createAjv() {
34
+ const ajv = new Ajv2020Ctor({ allErrors: true, strict: false });
35
+ addFormats(ajv);
36
+ return ajv;
37
+ }
38
+ /**
39
+ * Compile (and cache) the validator for one of the eight named schemas.
40
+ *
41
+ * Use this when you want the raw Ajv {@link ValidateFunction} — for example,
42
+ * to inspect `validate.errors` directly or wire it into a custom error
43
+ * formatter. For the common case prefer {@link validatePayload}.
44
+ */
45
+ export function compileSchema(name) {
46
+ const cached = validatorCache.get(name);
47
+ if (cached)
48
+ return cached;
49
+ const schema = allSchemas[name];
50
+ if (!schema) {
51
+ throw new Error(`Unknown schema name: ${String(name)}`);
52
+ }
53
+ const ajv = createAjv();
54
+ const validate = ajv.compile(schema);
55
+ validatorCache.set(name, validate);
56
+ return validate;
57
+ }
58
+ /**
59
+ * Validate a payload against one of the named schemas and return a
60
+ * structured result with normalised error paths/messages.
61
+ *
62
+ * Mirrors the shape used by `packages/verify/validators/schema.js` and
63
+ * `packages/findings/validate.js` so consumers can migrate without
64
+ * refactoring their error-handling code.
65
+ */
66
+ export function validatePayload(name, payload) {
67
+ const validate = compileSchema(name);
68
+ const valid = validate(payload);
69
+ if (valid) {
70
+ return { valid: true, errors: [] };
71
+ }
72
+ const errors = (validate.errors ?? []).map(err => ({
73
+ path: err.instancePath || '/',
74
+ message: err.message ?? 'unknown error',
75
+ params: err.params,
76
+ }));
77
+ return { valid: false, errors };
78
+ }
79
+ /**
80
+ * Test-only helper for clearing the compiled-validator cache. Production code
81
+ * should never need this — the cache is correct because schemas are immutable
82
+ * for the lifetime of the process.
83
+ */
84
+ export function _resetValidatorCacheForTests() {
85
+ validatorCache.clear();
86
+ }
87
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,gBAAgB,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAoC,MAAM,YAAY,CAAC;AAE1E,4EAA4E;AAC5E,8EAA8E;AAC9E,qEAAqE;AACrE,MAAM,WAAW,GAAG,CACjB,aAA+D,CAAC,OAAO,IAAI,aAAa,CAI1F,CAAC;AAEF,MAAM,UAAU,GAAG,CAChB,gBAAqE,CAAC,OAAO,IAAI,gBAAgB,CACrC,CAAC;AAahE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAgC,CAAC;AAE/D;;;;GAIG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAe,CAAC;IAC9C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAgB,EAAE,OAAgB;IAChE,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEhC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAAsB,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpE,IAAI,EAAE,GAAG,CAAC,YAAY,IAAI,GAAG;QAC7B,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,eAAe;QACvC,MAAM,EAAE,GAAG,CAAC,MAA6C;KAC1D,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B;IAC1C,cAAc,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@dogfood-lab/schemas",
3
+ "version": "1.2.0",
4
+ "description": "JSON schemas for the testing-os contract spine — record, finding, pattern, recommendation, doctrine, policy, scenario, submission.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./json/*": "./src/json/*"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "test": "vitest run --passWithNoTests"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "src/json",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "dependencies": {
32
+ "ajv": "^8.18.0",
33
+ "ajv-formats": "^3.0.1"
34
+ },
35
+ "devDependencies": {
36
+ "vitest": "^3.0.0"
37
+ },
38
+ "author": "mcp-tool-shop",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/dogfood-lab/testing-os.git",
43
+ "directory": "packages/schemas"
44
+ },
45
+ "homepage": "https://github.com/dogfood-lab/testing-os",
46
+ "bugs": {
47
+ "url": "https://github.com/dogfood-lab/testing-os/issues"
48
+ },
49
+ "keywords": [
50
+ "testing-os",
51
+ "dogfood-lab",
52
+ "json-schema",
53
+ "evidence",
54
+ "verification",
55
+ "contracts"
56
+ ]
57
+ }
@@ -0,0 +1,86 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/dogfood-lab/testing-os/packages/schemas/src/json/dogfood-doctrine.schema.json",
4
+ "title": "Dogfood Doctrine",
5
+ "description": "A hardened portfolio rule earned from repeated patterns. Doctrine represents durable operating law — the strongest tier of dogfood learning. Must be backed by multiple accepted patterns.",
6
+ "type": "object",
7
+ "required": [
8
+ "schema_version",
9
+ "doctrine_id",
10
+ "title",
11
+ "status",
12
+ "doctrine_kind",
13
+ "statement",
14
+ "rationale",
15
+ "based_on_pattern_ids",
16
+ "transfer_scope"
17
+ ],
18
+ "additionalProperties": false,
19
+ "properties": {
20
+ "schema_version": {
21
+ "type": "string",
22
+ "pattern": "^\\d+\\.\\d+\\.\\d+$"
23
+ },
24
+ "doctrine_id": {
25
+ "type": "string",
26
+ "pattern": "^ddoc-[a-z0-9][a-z0-9-]*$",
27
+ "minLength": 6
28
+ },
29
+ "title": {
30
+ "type": "string",
31
+ "minLength": 10,
32
+ "maxLength": 200
33
+ },
34
+ "status": {
35
+ "type": "string",
36
+ "enum": ["candidate", "accepted", "rejected"]
37
+ },
38
+ "doctrine_kind": {
39
+ "type": "string",
40
+ "enum": [
41
+ "rollout_law",
42
+ "evidence_law",
43
+ "surface_law",
44
+ "verification_law",
45
+ "calibration_law"
46
+ ]
47
+ },
48
+ "statement": {
49
+ "type": "string",
50
+ "minLength": 20,
51
+ "maxLength": 500,
52
+ "description": "The doctrine rule itself. Must read as a directive, not a suggestion."
53
+ },
54
+ "rationale": {
55
+ "type": "string",
56
+ "minLength": 20,
57
+ "maxLength": 1000,
58
+ "description": "Why this doctrine exists. Must reference recurrence evidence."
59
+ },
60
+ "based_on_pattern_ids": {
61
+ "type": "array",
62
+ "minItems": 1,
63
+ "items": { "type": "string", "minLength": 1 }
64
+ },
65
+ "transfer_scope": {
66
+ "type": "string",
67
+ "enum": ["surface_archetype", "execution_mode", "org_wide"]
68
+ },
69
+ "strength": {
70
+ "type": "string",
71
+ "enum": ["emerging", "proven", "foundational"]
72
+ },
73
+ "review": {
74
+ "type": "object",
75
+ "additionalProperties": false,
76
+ "properties": {
77
+ "reviewed_by": { "type": "string" },
78
+ "reviewed_at": { "type": "string", "format": "date-time" },
79
+ "decision_reason": { "type": "string", "maxLength": 1000 },
80
+ "last_action": { "type": "string", "enum": ["accept", "reject", "edit"] }
81
+ }
82
+ },
83
+ "created_at": { "type": "string", "format": "date-time" },
84
+ "updated_at": { "type": "string", "format": "date-time" }
85
+ }
86
+ }