@comity-dev/schemas 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Canonical, machine-readable JSON Schema definitions for Comity package metadata,
7
7
  ## Scope
8
8
 
9
9
  - `package-metadata.v1.json` — required fields and types for every `@comity/*` package's `package.json` (`name`, `version`, `type`, `license`, `engines`, `exports`, `comity.layer`, `comity.implements`).
10
- - ADR-008 register schema — machine-readable composition exception register.
10
+ - ADR-008 register schema and register — the canonical JSON Schema 2020-12 document and register from `docs/standards/decisions/data/`, embedded at build time (`pnpm --filter @comity-dev/schemas generate`); `adr008CoreExceptionRegister` is derived, never hand-edited. Compile with `createAjv2020Instance()`.
11
11
  - `comity-config.json` schema — repository-level configuration shape.
12
12
 
13
13
  ## Ownership
@@ -0,0 +1,17 @@
1
+ import Ajv from "ajv";
2
+ import Ajv2020 from "ajv/dist/2020.js";
3
+ /**
4
+ * Creates a fresh Ajv instance with strict settings and standard formats.
5
+ *
6
+ * @returns Configured Ajv instance
7
+ */
8
+ export declare function createAjvInstance(): Ajv;
9
+ /**
10
+ * Creates a fresh Ajv instance for JSON Schema draft 2020-12 documents, such
11
+ * as the canonical ADR-008 register schema. Separate from
12
+ * {@link createAjvInstance} so the draft-07 package-metadata and config
13
+ * schemas are unaffected.
14
+ *
15
+ * @returns Configured Ajv 2020-12 instance
16
+ */
17
+ export declare function createAjv2020Instance(): Ajv2020;
@@ -0,0 +1,36 @@
1
+ import Ajv from "ajv";
2
+ import Ajv2020 from "ajv/dist/2020.js";
3
+ import addFormats from "ajv-formats";
4
+ /**
5
+ * Creates a fresh Ajv instance with strict settings and standard formats.
6
+ *
7
+ * @returns Configured Ajv instance
8
+ */
9
+ export function createAjvInstance() {
10
+ const ajv = new Ajv({
11
+ allErrors: true,
12
+ strict: false,
13
+ strictTypes: false,
14
+ verbose: true,
15
+ });
16
+ addFormats(ajv);
17
+ return ajv;
18
+ }
19
+ /**
20
+ * Creates a fresh Ajv instance for JSON Schema draft 2020-12 documents, such
21
+ * as the canonical ADR-008 register schema. Separate from
22
+ * {@link createAjvInstance} so the draft-07 package-metadata and config
23
+ * schemas are unaffected.
24
+ *
25
+ * @returns Configured Ajv 2020-12 instance
26
+ */
27
+ export function createAjv2020Instance() {
28
+ const ajv = new Ajv2020({
29
+ allErrors: true,
30
+ strict: false,
31
+ strictTypes: false,
32
+ verbose: true,
33
+ });
34
+ addFormats(ajv);
35
+ return ajv;
36
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Canonical Comity constants.
3
+ *
4
+ * These values are derived from the authoritative Comity Standards
5
+ * (layering-policy.md, ADR-026). They MUST be kept in sync with those
6
+ * documents; updating them here implies updating the standards.
7
+ *
8
+ * @see layering-policy.md §2.1 / ADR-026 (package classification)
9
+ *
10
+ * ADR-026 defines `comity.layer` as the architecture classification of
11
+ * Comity RUNTIME packages (`@comity/*`). The six runtime layers are:
12
+ *
13
+ * primitives, kernel, composition, core,
14
+ * technology-adapter, integration-adapter
15
+ *
16
+ * `dev-tooling` is a reserved Development-side extension for
17
+ * `@comity-dev/*` packages only. It is NOT a seventh runtime layer
18
+ * and MUST NOT be used by `@comity/*` packages. The name-scope ↔
19
+ * layer boundary is enforced by the package-metadata JSON Schema
20
+ * (`schemas/package-metadata.ts`).
21
+ *
22
+ * Rationale for the extension: Development tooling packages
23
+ * legitimately use Node APIs, `process.env`, and other patterns that
24
+ * the runtime Semgrep and ESLint rules forbid. Declaring `dev-tooling`
25
+ * on these packages lets the validator engines (semgrep, depcruise,
26
+ * eslint, adapter-peers) scope those rules away from them. The
27
+ * runtime six-layer model is unchanged.
28
+ */
29
+ export declare const RUNTIME_LAYERS: readonly string[];
30
+ /**
31
+ * All layer values accepted by `comity.layer`. The boundary between
32
+ * runtime and development layers is enforced by the schema, not by
33
+ * this list alone.
34
+ */
35
+ export declare const VALID_LAYERS: readonly string[];
36
+ /**
37
+ * @see ADR-026 (package naming)
38
+ * architecture-validation.md §8
39
+ */
40
+ export declare const PACKAGE_NAME_PATTERN = "^@comity(-dev)?/[a-z0-9]+(?:-[a-z0-9]+)*$";
41
+ /**
42
+ * @see architecture-validation.md §8 (metadata — engines.node minimum)
43
+ */
44
+ export declare const MIN_NODE_VERSION = "24.0.0";
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Canonical Comity constants.
3
+ *
4
+ * These values are derived from the authoritative Comity Standards
5
+ * (layering-policy.md, ADR-026). They MUST be kept in sync with those
6
+ * documents; updating them here implies updating the standards.
7
+ *
8
+ * @see layering-policy.md §2.1 / ADR-026 (package classification)
9
+ *
10
+ * ADR-026 defines `comity.layer` as the architecture classification of
11
+ * Comity RUNTIME packages (`@comity/*`). The six runtime layers are:
12
+ *
13
+ * primitives, kernel, composition, core,
14
+ * technology-adapter, integration-adapter
15
+ *
16
+ * `dev-tooling` is a reserved Development-side extension for
17
+ * `@comity-dev/*` packages only. It is NOT a seventh runtime layer
18
+ * and MUST NOT be used by `@comity/*` packages. The name-scope ↔
19
+ * layer boundary is enforced by the package-metadata JSON Schema
20
+ * (`schemas/package-metadata.ts`).
21
+ *
22
+ * Rationale for the extension: Development tooling packages
23
+ * legitimately use Node APIs, `process.env`, and other patterns that
24
+ * the runtime Semgrep and ESLint rules forbid. Declaring `dev-tooling`
25
+ * on these packages lets the validator engines (semgrep, depcruise,
26
+ * eslint, adapter-peers) scope those rules away from them. The
27
+ * runtime six-layer model is unchanged.
28
+ */
29
+ export const RUNTIME_LAYERS = Object.freeze([
30
+ "primitives",
31
+ "kernel",
32
+ "composition",
33
+ "core",
34
+ "technology-adapter",
35
+ "integration-adapter",
36
+ ]);
37
+ /**
38
+ * All layer values accepted by `comity.layer`. The boundary between
39
+ * runtime and development layers is enforced by the schema, not by
40
+ * this list alone.
41
+ */
42
+ export const VALID_LAYERS = Object.freeze([
43
+ ...RUNTIME_LAYERS,
44
+ "dev-tooling",
45
+ ]);
46
+ /**
47
+ * @see ADR-026 (package naming)
48
+ * architecture-validation.md §8
49
+ */
50
+ export const PACKAGE_NAME_PATTERN = "^@comity(-dev)?/[a-z0-9]+(?:-[a-z0-9]+)*$";
51
+ /**
52
+ * @see architecture-validation.md §8 (metadata — engines.node minimum)
53
+ */
54
+ export const MIN_NODE_VERSION = "24.0.0";
@@ -0,0 +1,8 @@
1
+ export type { Adr008Register, Adr008RegisterEdge, } from "./schemas/adr-008-register.js";
2
+ export type { ComityConfig } from "./schemas/comity-config.js";
3
+ export type { PackageMetadata, ValidationResult, } from "./schemas/package-metadata.js";
4
+ export { createAjv2020Instance, createAjvInstance } from "./ajv-instance.js";
5
+ export { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "./constants.js";
6
+ export { adr008CoreExceptionRegister, adr008RegisterSchema, validateAdr008Register, } from "./schemas/adr-008-register.js";
7
+ export { comityConfigSchema, validateComityConfig, } from "./schemas/comity-config.js";
8
+ export { packageMetadataSchema, validatePackageMetadata, } from "./schemas/package-metadata.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { createAjv2020Instance, createAjvInstance } from "./ajv-instance.js";
2
+ export { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "./constants.js";
3
+ export { adr008CoreExceptionRegister, adr008RegisterSchema, validateAdr008Register, } from "./schemas/adr-008-register.js";
4
+ export { comityConfigSchema, validateComityConfig, } from "./schemas/comity-config.js";
5
+ export { packageMetadataSchema, validatePackageMetadata, } from "./schemas/package-metadata.js";
@@ -0,0 +1,3 @@
1
+ import type { Adr008Register } from "./adr-008-register.js";
2
+ export declare const adr008RegisterSchemaDocument: Record<string, unknown>;
3
+ export declare const adr008CanonicalRegister: Adr008Register;
@@ -0,0 +1,390 @@
1
+ // GENERATED FILE — DO NOT EDIT.
2
+ // Source: docs/standards/decisions/data/adr-008-core-exception-register{,.schema}.json
3
+ // Regenerate with: pnpm --filter @comity-dev/schemas generate
4
+ export const adr008RegisterSchemaDocument = {
5
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
6
+ "$id": "comity:adr-008-core-exception-register.schema.json",
7
+ "title": "ADR-008 Core-to-Core Dependency Exception Register",
8
+ "description": "Machine-readable serialization of the ADR-008 closed register of Core-to-Core dependency exceptions. ADR-008 (Markdown) remains the architectural authority; this register is a derived representation and MUST NOT redefine architecture.",
9
+ "type": "object",
10
+ "additionalProperties": false,
11
+ "required": [
12
+ "$schema",
13
+ "schemaVersion",
14
+ "authority",
15
+ "source",
16
+ "edges"
17
+ ],
18
+ "properties": {
19
+ "$schema": {
20
+ "const": "comity:adr-008-core-exception-register.schema.json"
21
+ },
22
+ "schemaVersion": {
23
+ "type": "integer",
24
+ "const": 1,
25
+ "description": "Version of the register schema. Incremented when the data contract changes in a breaking way."
26
+ },
27
+ "authority": {
28
+ "const": "ADR-008",
29
+ "description": "The architectural authority this register serializes."
30
+ },
31
+ "source": {
32
+ "const": "../ADR-008-explicit-core-module-composition-exceptions.md",
33
+ "description": "Path to the authoritative ADR document, relative to the register file (the ADR lives in the parent directory of data/)."
34
+ },
35
+ "edges": {
36
+ "type": "array",
37
+ "description": "Closed list of approved Core-to-Core dependency exceptions.",
38
+ "items": {
39
+ "$ref": "#/$defs/dependencyEdge"
40
+ },
41
+ "uniqueItems": true
42
+ }
43
+ },
44
+ "$defs": {
45
+ "dependencyEdge": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": [
49
+ "from",
50
+ "to",
51
+ "layer",
52
+ "categories",
53
+ "importKind",
54
+ "lifecycle",
55
+ "justification",
56
+ "adrReference"
57
+ ],
58
+ "properties": {
59
+ "from": {
60
+ "type": "string",
61
+ "pattern": "^@comity/[a-z0-9-]+$",
62
+ "description": "Source package name."
63
+ },
64
+ "to": {
65
+ "type": "string",
66
+ "pattern": "^@comity/[a-z0-9-]+$",
67
+ "description": "Target package name."
68
+ },
69
+ "layer": {
70
+ "const": "core-to-core",
71
+ "description": "Layer relationship. This register covers only Core-to-Core edges."
72
+ },
73
+ "categories": {
74
+ "type": "array",
75
+ "minItems": 1,
76
+ "uniqueItems": true,
77
+ "items": {
78
+ "type": "string",
79
+ "enum": [
80
+ "capability",
81
+ "infrastructure-contract",
82
+ "value-import",
83
+ "candidate-for-removal"
84
+ ]
85
+ },
86
+ "description": "All classifications that apply to this edge. A single edge may belong to multiple classifications (e.g., storefront -> catalog is both a capability exception and a value-import exception). This is the sole classification field."
87
+ },
88
+ "importKind": {
89
+ "type": "string",
90
+ "enum": [
91
+ "type-only",
92
+ "value",
93
+ "mixed"
94
+ ],
95
+ "description": "Whether the dependency is type-only, value, or a mix of both."
96
+ },
97
+ "lifecycle": {
98
+ "type": "string",
99
+ "enum": [
100
+ "approved",
101
+ "deprecated",
102
+ "migration-candidate"
103
+ ],
104
+ "description": "Lifecycle status: approved exception, deprecated pattern tracked for removal, or scheduled migration candidate."
105
+ },
106
+ "justification": {
107
+ "type": "string",
108
+ "minLength": 1,
109
+ "description": "Justification as recorded in ADR-008."
110
+ },
111
+ "adrReference": {
112
+ "type": "string",
113
+ "minLength": 1,
114
+ "description": "Reference back to ADR-008, including the specific register section/table where practical."
115
+ },
116
+ "removalCandidate": {
117
+ "type": "object",
118
+ "additionalProperties": false,
119
+ "required": [
120
+ "criteria",
121
+ "action"
122
+ ],
123
+ "description": "Removal candidate tracking, mirroring ADR-008 'Candidates for Removal'. Required when lifecycle is 'migration-candidate'.",
124
+ "properties": {
125
+ "criteria": {
126
+ "type": "string",
127
+ "description": "The ADR-008 acceptance criteria this dependency fails."
128
+ },
129
+ "action": {
130
+ "type": "string",
131
+ "description": "The migration action required to remove or refactor the dependency."
132
+ }
133
+ }
134
+ }
135
+ },
136
+ "if": {
137
+ "properties": {
138
+ "lifecycle": {
139
+ "const": "migration-candidate"
140
+ }
141
+ },
142
+ "required": [
143
+ "lifecycle"
144
+ ]
145
+ },
146
+ "then": {
147
+ "required": [
148
+ "removalCandidate"
149
+ ]
150
+ }
151
+ }
152
+ }
153
+ };
154
+ export const adr008CanonicalRegister = {
155
+ "$schema": "comity:adr-008-core-exception-register.schema.json",
156
+ "schemaVersion": 1,
157
+ "authority": "ADR-008",
158
+ "source": "../ADR-008-explicit-core-module-composition-exceptions.md",
159
+ "edges": [
160
+ {
161
+ "from": "@comity/storefront",
162
+ "to": "@comity/catalog",
163
+ "layer": "core-to-core",
164
+ "categories": [
165
+ "capability"
166
+ ],
167
+ "importKind": "type-only",
168
+ "lifecycle": "approved",
169
+ "justification": "Storefront page composition references catalog domain contracts and models.",
170
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
171
+ },
172
+ {
173
+ "from": "@comity/storefront",
174
+ "to": "@comity/taxonomy",
175
+ "layer": "core-to-core",
176
+ "categories": [
177
+ "capability"
178
+ ],
179
+ "importKind": "type-only",
180
+ "lifecycle": "approved",
181
+ "justification": "Storefront category page composition references taxonomy domain contracts and models.",
182
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
183
+ },
184
+ {
185
+ "from": "@comity/storefront",
186
+ "to": "@comity/content",
187
+ "layer": "core-to-core",
188
+ "categories": [
189
+ "capability"
190
+ ],
191
+ "importKind": "type-only",
192
+ "lifecycle": "approved",
193
+ "justification": "Storefront content page composer references content domain models.",
194
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
195
+ },
196
+ {
197
+ "from": "@comity/storefront",
198
+ "to": "@comity/search",
199
+ "layer": "core-to-core",
200
+ "categories": [
201
+ "capability"
202
+ ],
203
+ "importKind": "type-only",
204
+ "lifecycle": "approved",
205
+ "justification": "Storefront search page contract references SearchResultModel.",
206
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
207
+ },
208
+ {
209
+ "from": "@comity/catalog",
210
+ "to": "@comity/media",
211
+ "layer": "core-to-core",
212
+ "categories": [
213
+ "capability"
214
+ ],
215
+ "importKind": "type-only",
216
+ "lifecycle": "approved",
217
+ "justification": "Catalog projections reference MediaModel for product/brand media.",
218
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
219
+ },
220
+ {
221
+ "from": "@comity/content",
222
+ "to": "@comity/media",
223
+ "layer": "core-to-core",
224
+ "categories": [
225
+ "capability"
226
+ ],
227
+ "importKind": "type-only",
228
+ "lifecycle": "approved",
229
+ "justification": "Content blocks/pages reference MediaModel.",
230
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
231
+ },
232
+ {
233
+ "from": "@comity/content",
234
+ "to": "@comity/seo",
235
+ "layer": "core-to-core",
236
+ "categories": [
237
+ "capability"
238
+ ],
239
+ "importKind": "type-only",
240
+ "lifecycle": "approved",
241
+ "justification": "Content pages reference SeoModel.",
242
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
243
+ },
244
+ {
245
+ "from": "@comity/taxonomy",
246
+ "to": "@comity/media",
247
+ "layer": "core-to-core",
248
+ "categories": [
249
+ "capability"
250
+ ],
251
+ "importKind": "type-only",
252
+ "lifecycle": "approved",
253
+ "justification": "Taxonomy models reference MediaModel for category image.",
254
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
255
+ },
256
+ {
257
+ "from": "@comity/order",
258
+ "to": "@comity/pricing",
259
+ "layer": "core-to-core",
260
+ "categories": [
261
+ "capability",
262
+ "value-import"
263
+ ],
264
+ "importKind": "value",
265
+ "lifecycle": "approved",
266
+ "justification": "@comity/order composes its order-level PriceRecord via the public PriceRecord type and combine (record composition, not calculation); the record type stays pricing-owned.",
267
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
268
+ },
269
+ {
270
+ "from": "@comity/order",
271
+ "to": "@comity/organization",
272
+ "layer": "core-to-core",
273
+ "categories": [
274
+ "capability"
275
+ ],
276
+ "importKind": "type-only",
277
+ "lifecycle": "approved",
278
+ "justification": "Order contracts reference ChannelId for commercial channel scoping.",
279
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
280
+ },
281
+ {
282
+ "from": "@comity/fulfillment",
283
+ "to": "@comity/order",
284
+ "layer": "core-to-core",
285
+ "categories": [
286
+ "capability"
287
+ ],
288
+ "importKind": "type-only",
289
+ "lifecycle": "approved",
290
+ "justification": "Fulfillment references the committed order by OrderId and reuses the OrderAddressSnapshot contract for shipping recipients; it never holds an Order and imports no value from @comity/order.",
291
+ "adrReference": "ADR-008 — Amendment 2, Capability Exceptions"
292
+ },
293
+ {
294
+ "from": "@comity/fulfillment",
295
+ "to": "@comity/organization",
296
+ "layer": "core-to-core",
297
+ "categories": [
298
+ "capability"
299
+ ],
300
+ "importKind": "type-only",
301
+ "lifecycle": "approved",
302
+ "justification": "Fulfillment repository contracts require TenantId for multi-tenant isolation, as order and customer repositories do.",
303
+ "adrReference": "ADR-008 — Amendment 2, Capability Exceptions"
304
+ },
305
+ {
306
+ "from": "@comity/customer",
307
+ "to": "@comity/validation",
308
+ "layer": "core-to-core",
309
+ "categories": [
310
+ "capability"
311
+ ],
312
+ "importKind": "type-only",
313
+ "lifecycle": "approved",
314
+ "justification": "Customer validator consumes the shared Validator contract.",
315
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
316
+ },
317
+ {
318
+ "from": "@comity/customer",
319
+ "to": "@comity/organization",
320
+ "layer": "core-to-core",
321
+ "categories": [
322
+ "capability"
323
+ ],
324
+ "importKind": "type-only",
325
+ "lifecycle": "approved",
326
+ "justification": "Customer repository requires TenantId for multi-tenant isolation.",
327
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
328
+ },
329
+ {
330
+ "from": "@comity/address",
331
+ "to": "@comity/validation",
332
+ "layer": "core-to-core",
333
+ "categories": [
334
+ "capability"
335
+ ],
336
+ "importKind": "type-only",
337
+ "lifecycle": "approved",
338
+ "justification": "Address validator consumes the shared Validator contract.",
339
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
340
+ },
341
+ {
342
+ "from": "@comity/identity",
343
+ "to": "@comity/validation",
344
+ "layer": "core-to-core",
345
+ "categories": [
346
+ "capability"
347
+ ],
348
+ "importKind": "type-only",
349
+ "lifecycle": "approved",
350
+ "justification": "Identity validator consumes the shared Validator contract.",
351
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
352
+ },
353
+ {
354
+ "from": "@comity/auth-tokens",
355
+ "to": "@comity/auth",
356
+ "layer": "core-to-core",
357
+ "categories": [
358
+ "value-import"
359
+ ],
360
+ "importKind": "mixed",
361
+ "lifecycle": "approved",
362
+ "justification": "Token facade error surface normalizes AuthError at runtime. @comity/auth owns authentication error semantics; direction is intentional and non-cyclic.",
363
+ "adrReference": "ADR-008 — Dependency Register, Value-Import Exceptions"
364
+ },
365
+ {
366
+ "from": "@comity/router",
367
+ "to": "@comity/http",
368
+ "layer": "core-to-core",
369
+ "categories": [
370
+ "infrastructure-contract"
371
+ ],
372
+ "importKind": "type-only",
373
+ "lifecycle": "deprecated",
374
+ "justification": "Router contracts reference HttpContext, HttpHandler, HttpMethod. Compatibility exception; extraction candidate.",
375
+ "adrReference": "ADR-008 — Dependency Register, Infrastructure Contract Exceptions"
376
+ },
377
+ {
378
+ "from": "@comity/payment",
379
+ "to": "@comity/pricing",
380
+ "layer": "core-to-core",
381
+ "categories": [
382
+ "capability"
383
+ ],
384
+ "importKind": "type-only",
385
+ "lifecycle": "approved",
386
+ "justification": "Payment module uses Money value object from pricing for amount representation in PaymentRequest and PaymentOutcome.",
387
+ "adrReference": "ADR-008 — Dependency Register, Capability Exceptions"
388
+ }
389
+ ]
390
+ };
@@ -0,0 +1,52 @@
1
+ import type { Ajv, ErrorObject } from "ajv";
2
+ /**
3
+ * Canonical schema for the ADR-008 Core Exception Register.
4
+ *
5
+ * Derived at build time from the canonical JSON Schema
6
+ * `docs/standards/decisions/data/adr-008-core-exception-register.schema.json`
7
+ * (ADR-009 §3, §5). It is a JSON Schema 2020-12 document, so it must be
8
+ * compiled with {@link createAjv2020Instance}.
9
+ *
10
+ * @see ADR-008 — Explicit Core Module Composition Exceptions
11
+ * @see ADR-009 — Machine-Readable Core Exception Register
12
+ */
13
+ export declare const adr008RegisterSchema: Record<string, unknown>;
14
+ /**
15
+ * Canonical ADR-008 register, derived at build time from
16
+ * `docs/standards/decisions/data/adr-008-core-exception-register.json`.
17
+ * ADR-008 (Markdown) remains the architectural authority.
18
+ */
19
+ export declare const adr008CoreExceptionRegister: Adr008Register;
20
+ /**
21
+ * Validates a parsed ADR-008 register document against the canonical schema.
22
+ *
23
+ * @param document — parsed ADR-008 register
24
+ * @param ajv — optional pre-built Ajv instance; it MUST support JSON Schema
25
+ * 2020-12 (use {@link createAjv2020Instance})
26
+ * @returns validation result
27
+ */
28
+ export declare function validateAdr008Register(document: unknown, ajv?: Ajv): {
29
+ valid: boolean;
30
+ errors: ErrorObject[];
31
+ };
32
+ export interface Adr008RegisterEdge {
33
+ from: string;
34
+ to: string;
35
+ layer: string;
36
+ categories: string[];
37
+ importKind: string;
38
+ lifecycle: string;
39
+ justification: string;
40
+ adrReference: string;
41
+ removalCandidate?: {
42
+ criteria: string;
43
+ action: string;
44
+ };
45
+ }
46
+ export interface Adr008Register {
47
+ $schema: string;
48
+ schemaVersion: number;
49
+ authority: string;
50
+ source: string;
51
+ edges: Adr008RegisterEdge[];
52
+ }
@@ -0,0 +1,37 @@
1
+ import { createAjv2020Instance } from "../ajv-instance.js";
2
+ import { adr008CanonicalRegister, adr008RegisterSchemaDocument, } from "./adr-008-canonical.generated.js";
3
+ /**
4
+ * Canonical schema for the ADR-008 Core Exception Register.
5
+ *
6
+ * Derived at build time from the canonical JSON Schema
7
+ * `docs/standards/decisions/data/adr-008-core-exception-register.schema.json`
8
+ * (ADR-009 §3, §5). It is a JSON Schema 2020-12 document, so it must be
9
+ * compiled with {@link createAjv2020Instance}.
10
+ *
11
+ * @see ADR-008 — Explicit Core Module Composition Exceptions
12
+ * @see ADR-009 — Machine-Readable Core Exception Register
13
+ */
14
+ export const adr008RegisterSchema = adr008RegisterSchemaDocument;
15
+ /**
16
+ * Canonical ADR-008 register, derived at build time from
17
+ * `docs/standards/decisions/data/adr-008-core-exception-register.json`.
18
+ * ADR-008 (Markdown) remains the architectural authority.
19
+ */
20
+ export const adr008CoreExceptionRegister = adr008CanonicalRegister;
21
+ /**
22
+ * Validates a parsed ADR-008 register document against the canonical schema.
23
+ *
24
+ * @param document — parsed ADR-008 register
25
+ * @param ajv — optional pre-built Ajv instance; it MUST support JSON Schema
26
+ * 2020-12 (use {@link createAjv2020Instance})
27
+ * @returns validation result
28
+ */
29
+ export function validateAdr008Register(document, ajv = createAjv2020Instance()) {
30
+ const id = adr008RegisterSchema["$id"];
31
+ const validate = ajv.getSchema(id) ?? ajv.compile(adr008RegisterSchema);
32
+ const valid = validate(document);
33
+ return {
34
+ valid: Boolean(valid),
35
+ errors: valid ? [] : (validate.errors ?? []),
36
+ };
37
+ }
@@ -0,0 +1,163 @@
1
+ import type { Ajv, ErrorObject } from "ajv";
2
+ /**
3
+ * Canonical schema for repository `comity.config.json`.
4
+ *
5
+ * The configuration holds REPOSITORY FACTS — package locations, repository
6
+ * type, declared exceptions. It MUST NOT silently redefine Comity-wide
7
+ * policy; policy belongs in the Standards and is enforced by shared tools.
8
+ *
9
+ * @see layering-policy.md (policy owner)
10
+ * @see ADR-007 (integration-adapter vs technology-adapter categorization)
11
+ */
12
+ export declare const comityConfigSchema: {
13
+ $id: string;
14
+ type: string;
15
+ additionalProperties: boolean;
16
+ required: string[];
17
+ properties: {
18
+ repository: {
19
+ type: string;
20
+ required: string[];
21
+ additionalProperties: boolean;
22
+ properties: {
23
+ name: {
24
+ type: string;
25
+ minLength: number;
26
+ description: string;
27
+ };
28
+ type: {
29
+ type: string;
30
+ enum: string[];
31
+ description: string;
32
+ };
33
+ };
34
+ };
35
+ packages: {
36
+ type: string;
37
+ required: string[];
38
+ additionalProperties: boolean;
39
+ properties: {
40
+ roots: {
41
+ type: string;
42
+ items: {
43
+ type: string;
44
+ minLength: number;
45
+ };
46
+ minItems: number;
47
+ description: string;
48
+ };
49
+ exclude: {
50
+ type: string;
51
+ items: {
52
+ type: string;
53
+ minLength: number;
54
+ };
55
+ description: string;
56
+ };
57
+ };
58
+ };
59
+ validation: {
60
+ type: string;
61
+ additionalProperties: boolean;
62
+ properties: {
63
+ rules: {
64
+ type: string;
65
+ description: string;
66
+ additionalProperties: {
67
+ type: string;
68
+ };
69
+ };
70
+ exceptions: {
71
+ type: string;
72
+ additionalProperties: boolean;
73
+ properties: {
74
+ dependencyEdges: {
75
+ type: string;
76
+ description: string;
77
+ items: {
78
+ type: string;
79
+ required: string[];
80
+ properties: {
81
+ from: {
82
+ type: string;
83
+ };
84
+ to: {
85
+ type: string;
86
+ };
87
+ adr: {
88
+ type: string;
89
+ };
90
+ rationale: {
91
+ type: string;
92
+ };
93
+ };
94
+ additionalProperties: boolean;
95
+ };
96
+ };
97
+ layerOverrides: {
98
+ type: string;
99
+ description: string;
100
+ items: {
101
+ type: string;
102
+ required: string[];
103
+ properties: {
104
+ package: {
105
+ type: string;
106
+ };
107
+ layer: {
108
+ type: string;
109
+ };
110
+ adr: {
111
+ type: string;
112
+ };
113
+ rationale: {
114
+ type: string;
115
+ };
116
+ };
117
+ additionalProperties: boolean;
118
+ };
119
+ };
120
+ };
121
+ };
122
+ };
123
+ };
124
+ };
125
+ };
126
+ /**
127
+ * Validates a parsed comity.config.json document.
128
+ *
129
+ * @param document — parsed comity.config.json
130
+ * @param ajv — optional pre-built Ajv instance
131
+ * @returns validation result
132
+ */
133
+ export declare function validateComityConfig(document: unknown, ajv?: Ajv): {
134
+ valid: boolean;
135
+ errors: ErrorObject[];
136
+ };
137
+ export interface ComityConfig {
138
+ repository: {
139
+ name: string;
140
+ type: string;
141
+ };
142
+ packages: {
143
+ roots: string[];
144
+ exclude?: string[];
145
+ };
146
+ validation?: {
147
+ rules?: Record<string, boolean>;
148
+ exceptions?: {
149
+ dependencyEdges?: Array<{
150
+ from: string;
151
+ to: string;
152
+ adr: string;
153
+ rationale?: string;
154
+ }>;
155
+ layerOverrides?: Array<{
156
+ package: string;
157
+ layer: string;
158
+ adr: string;
159
+ rationale?: string;
160
+ }>;
161
+ };
162
+ };
163
+ }
@@ -0,0 +1,122 @@
1
+ import { createAjvInstance } from "../ajv-instance.js";
2
+ /**
3
+ * Canonical schema for repository `comity.config.json`.
4
+ *
5
+ * The configuration holds REPOSITORY FACTS — package locations, repository
6
+ * type, declared exceptions. It MUST NOT silently redefine Comity-wide
7
+ * policy; policy belongs in the Standards and is enforced by shared tools.
8
+ *
9
+ * @see layering-policy.md (policy owner)
10
+ * @see ADR-007 (integration-adapter vs technology-adapter categorization)
11
+ */
12
+ export const comityConfigSchema = {
13
+ $id: "https://comityjs.dev/schemas/comity-config.v1.json",
14
+ type: "object",
15
+ additionalProperties: false,
16
+ required: ["repository", "packages"],
17
+ properties: {
18
+ repository: {
19
+ type: "object",
20
+ required: ["name", "type"],
21
+ additionalProperties: false,
22
+ properties: {
23
+ name: {
24
+ type: "string",
25
+ minLength: 1,
26
+ description: "Logical name of the repository.",
27
+ },
28
+ type: {
29
+ type: "string",
30
+ enum: [
31
+ "development",
32
+ "community",
33
+ "enterprise",
34
+ "third-party",
35
+ "fixture",
36
+ ],
37
+ description: "Repository category.",
38
+ },
39
+ },
40
+ },
41
+ packages: {
42
+ type: "object",
43
+ required: ["roots"],
44
+ additionalProperties: false,
45
+ properties: {
46
+ roots: {
47
+ type: "array",
48
+ items: { type: "string", minLength: 1 },
49
+ minItems: 1,
50
+ description: "Workspace package roots, relative to the repository root.",
51
+ },
52
+ exclude: {
53
+ type: "array",
54
+ items: { type: "string", minLength: 1 },
55
+ description: "Package path patterns to exclude from validation.",
56
+ },
57
+ },
58
+ },
59
+ validation: {
60
+ type: "object",
61
+ additionalProperties: false,
62
+ properties: {
63
+ rules: {
64
+ type: "object",
65
+ description: "Repository-specific rule selection. Allowed keys: metadata, dependencies, eslint, semgrep, orchestrator.",
66
+ additionalProperties: { type: "boolean" },
67
+ },
68
+ exceptions: {
69
+ type: "object",
70
+ additionalProperties: false,
71
+ properties: {
72
+ dependencyEdges: {
73
+ type: "array",
74
+ description: "Locally-permitted dependency edges. Each entry MUST reference an ADR.",
75
+ items: {
76
+ type: "object",
77
+ required: ["from", "to", "adr"],
78
+ properties: {
79
+ from: { type: "string" },
80
+ to: { type: "string" },
81
+ adr: { type: "string" },
82
+ rationale: { type: "string" },
83
+ },
84
+ additionalProperties: false,
85
+ },
86
+ },
87
+ layerOverrides: {
88
+ type: "array",
89
+ description: "Layer classification overrides — for transitional packages only.",
90
+ items: {
91
+ type: "object",
92
+ required: ["package", "layer", "adr"],
93
+ properties: {
94
+ package: { type: "string" },
95
+ layer: { type: "string" },
96
+ adr: { type: "string" },
97
+ rationale: { type: "string" },
98
+ },
99
+ additionalProperties: false,
100
+ },
101
+ },
102
+ },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ };
108
+ /**
109
+ * Validates a parsed comity.config.json document.
110
+ *
111
+ * @param document — parsed comity.config.json
112
+ * @param ajv — optional pre-built Ajv instance
113
+ * @returns validation result
114
+ */
115
+ export function validateComityConfig(document, ajv = createAjvInstance()) {
116
+ const validate = ajv.compile(comityConfigSchema);
117
+ const valid = validate(document);
118
+ return {
119
+ valid: Boolean(valid),
120
+ errors: valid ? [] : (validate.errors ?? []),
121
+ };
122
+ }
@@ -0,0 +1,6 @@
1
+ export type { Adr008Register, Adr008RegisterEdge, } from "./adr-008-register.js";
2
+ export type { ComityConfig } from "./comity-config.js";
3
+ export type { PackageMetadata, ValidationResult } from "./package-metadata.js";
4
+ export { adr008CoreExceptionRegister, adr008RegisterSchema, validateAdr008Register, } from "./adr-008-register.js";
5
+ export { comityConfigSchema, validateComityConfig } from "./comity-config.js";
6
+ export { packageMetadataSchema, validatePackageMetadata, } from "./package-metadata.js";
@@ -0,0 +1,3 @@
1
+ export { adr008CoreExceptionRegister, adr008RegisterSchema, validateAdr008Register, } from "./adr-008-register.js";
2
+ export { comityConfigSchema, validateComityConfig } from "./comity-config.js";
3
+ export { packageMetadataSchema, validatePackageMetadata, } from "./package-metadata.js";
@@ -0,0 +1,157 @@
1
+ import type { Ajv, ErrorObject } from "ajv";
2
+ /**
3
+ * Canonical schema for Comity package metadata.
4
+ *
5
+ * Covers both namespaces, with a name-scope ↔ layer boundary:
6
+ * - `@comity/*` (runtime) → `comity.layer` MUST be one of the six
7
+ * runtime layers (ADR-026).
8
+ * - `@comity-dev/*` (tooling) → `comity.layer` MUST be `dev-tooling`.
9
+ *
10
+ * The boundary is enforced by the `if/then/else` clause on `comity.layer`.
11
+ *
12
+ * @see ADR-026 — Architecture Validator Authoritative Classification
13
+ * @see layering-policy.md §2.1
14
+ * @see architecture-validation.md §8 (package naming, type, engines.node)
15
+ * @see public-api.md §3 (exports subpath rules)
16
+ *
17
+ * This schema is the authoritative machine-readable definition of what every
18
+ * Comity package manifest MUST contain. Repositories consume this schema via
19
+ * the shared `comity-validate` orchestrator; they do not redefine it.
20
+ */
21
+ export declare const packageMetadataSchema: {
22
+ $id: string;
23
+ type: string;
24
+ required: string[];
25
+ additionalProperties: boolean;
26
+ properties: {
27
+ name: {
28
+ type: string;
29
+ pattern: string;
30
+ description: string;
31
+ };
32
+ version: {
33
+ type: string;
34
+ pattern: string;
35
+ description: string;
36
+ };
37
+ type: {
38
+ const: string;
39
+ description: string;
40
+ };
41
+ license: {
42
+ type: string;
43
+ minLength: number;
44
+ description: string;
45
+ };
46
+ engines: {
47
+ type: string;
48
+ required: string[];
49
+ properties: {
50
+ node: {
51
+ type: string;
52
+ pattern: string;
53
+ description: string;
54
+ };
55
+ };
56
+ additionalProperties: boolean;
57
+ };
58
+ comity: {
59
+ type: string;
60
+ description: string;
61
+ required: string[];
62
+ properties: {
63
+ layer: {
64
+ type: string;
65
+ enum: string[];
66
+ description: string;
67
+ };
68
+ implements: {
69
+ type: string;
70
+ pattern: string;
71
+ description: string;
72
+ };
73
+ };
74
+ additionalProperties: boolean;
75
+ };
76
+ exports: {
77
+ type: string;
78
+ description: string;
79
+ additionalProperties: boolean;
80
+ };
81
+ typesVersions: {
82
+ type: string;
83
+ description: string;
84
+ additionalProperties: boolean;
85
+ };
86
+ };
87
+ allOf: ({
88
+ if: {
89
+ properties: {
90
+ name: {
91
+ pattern: string;
92
+ };
93
+ };
94
+ required: string[];
95
+ };
96
+ then: {
97
+ properties: {
98
+ comity: {
99
+ properties: {
100
+ layer: {
101
+ enum: string[];
102
+ const?: never;
103
+ };
104
+ };
105
+ };
106
+ };
107
+ };
108
+ } | {
109
+ if: {
110
+ properties: {
111
+ name: {
112
+ pattern: string;
113
+ };
114
+ };
115
+ required: string[];
116
+ };
117
+ then: {
118
+ properties: {
119
+ comity: {
120
+ properties: {
121
+ layer: {
122
+ const: string;
123
+ enum?: never;
124
+ };
125
+ };
126
+ };
127
+ };
128
+ };
129
+ })[];
130
+ };
131
+ /**
132
+ * Validates a parsed package.json against the canonical schema.
133
+ *
134
+ * @param manifest — parsed package.json object
135
+ * @param ajv — optional pre-built Ajv instance
136
+ * @returns validation result
137
+ */
138
+ export declare function validatePackageMetadata(manifest: unknown, ajv?: Ajv): ValidationResult;
139
+ export interface PackageMetadata {
140
+ name: string;
141
+ version: string;
142
+ type: "module";
143
+ license: string;
144
+ engines: {
145
+ node: string;
146
+ };
147
+ comity?: {
148
+ layer: string;
149
+ implements?: string;
150
+ };
151
+ exports: Record<string, unknown>;
152
+ typesVersions?: Record<string, unknown>;
153
+ }
154
+ export interface ValidationResult {
155
+ valid: boolean;
156
+ errors: ErrorObject[];
157
+ }
@@ -0,0 +1,147 @@
1
+ import { createAjvInstance } from "../ajv-instance.js";
2
+ import { MIN_NODE_VERSION, PACKAGE_NAME_PATTERN, RUNTIME_LAYERS, VALID_LAYERS, } from "../constants.js";
3
+ /**
4
+ * Canonical schema for Comity package metadata.
5
+ *
6
+ * Covers both namespaces, with a name-scope ↔ layer boundary:
7
+ * - `@comity/*` (runtime) → `comity.layer` MUST be one of the six
8
+ * runtime layers (ADR-026).
9
+ * - `@comity-dev/*` (tooling) → `comity.layer` MUST be `dev-tooling`.
10
+ *
11
+ * The boundary is enforced by the `if/then/else` clause on `comity.layer`.
12
+ *
13
+ * @see ADR-026 — Architecture Validator Authoritative Classification
14
+ * @see layering-policy.md §2.1
15
+ * @see architecture-validation.md §8 (package naming, type, engines.node)
16
+ * @see public-api.md §3 (exports subpath rules)
17
+ *
18
+ * This schema is the authoritative machine-readable definition of what every
19
+ * Comity package manifest MUST contain. Repositories consume this schema via
20
+ * the shared `comity-validate` orchestrator; they do not redefine it.
21
+ */
22
+ export const packageMetadataSchema = {
23
+ $id: "https://comityjs.dev/schemas/package-metadata.v1.json",
24
+ type: "object",
25
+ required: ["name", "version", "type", "license", "engines", "exports"],
26
+ additionalProperties: true,
27
+ properties: {
28
+ name: {
29
+ type: "string",
30
+ pattern: PACKAGE_NAME_PATTERN,
31
+ description: "Package name MUST follow the `@comity/<kebab-case-name>` or `@comity-dev/<kebab-case-name>` convention.",
32
+ },
33
+ version: {
34
+ type: "string",
35
+ pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+",
36
+ description: "Semantic version of the package.",
37
+ },
38
+ type: {
39
+ const: "module",
40
+ description: "Package type MUST be `module` (ESM).",
41
+ },
42
+ license: {
43
+ type: "string",
44
+ minLength: 1,
45
+ description: "Package license MUST be declared.",
46
+ },
47
+ engines: {
48
+ type: "object",
49
+ required: ["node"],
50
+ properties: {
51
+ node: {
52
+ type: "string",
53
+ pattern: `>=${MIN_NODE_VERSION}`,
54
+ description: `Node.js engine MUST be >= ${MIN_NODE_VERSION}.`,
55
+ },
56
+ },
57
+ additionalProperties: true,
58
+ },
59
+ comity: {
60
+ type: "object",
61
+ description: "Comity metadata — authoritative source of package classification.",
62
+ required: ["layer"],
63
+ properties: {
64
+ layer: {
65
+ type: "string",
66
+ enum: [...VALID_LAYERS],
67
+ description: "Architectural layer. Runtime `@comity/*` packages MUST use one of the six runtime layers (primitives, kernel, composition, core, technology-adapter, integration-adapter). Development `@comity-dev/*` packages MUST use `dev-tooling`.",
68
+ },
69
+ implements: {
70
+ // Per ADR-026, `implements` is a single Core Module name. The
71
+ // legacy validator reports a violation when this is an array;
72
+ // we keep the schema strict and surface the violation through
73
+ // the metadata check.
74
+ type: "string",
75
+ pattern: PACKAGE_NAME_PATTERN,
76
+ description: "Single Core Module that this Adapter implements (technology-adapter and integration-adapter).",
77
+ },
78
+ },
79
+ additionalProperties: false,
80
+ },
81
+ exports: {
82
+ type: "object",
83
+ description: "Declared public subpaths. Forbidden subpaths (utils, helpers, shared, internal, lazy) are validated by ESLint.",
84
+ additionalProperties: true,
85
+ },
86
+ typesVersions: {
87
+ type: "object",
88
+ description: "TypeScript typesVersions MUST be consistent with declared exports.",
89
+ additionalProperties: true,
90
+ },
91
+ },
92
+ // Name-scope ↔ layer boundary. The runtime six-layer model is
93
+ // preserved; `dev-tooling` is reserved for `@comity-dev/*`.
94
+ // Implemented at the manifest level so `name` and `comity.layer`
95
+ // can be evaluated as siblings.
96
+ allOf: [
97
+ {
98
+ if: {
99
+ properties: {
100
+ name: { pattern: "^@comity/" },
101
+ },
102
+ required: ["name"],
103
+ },
104
+ then: {
105
+ properties: {
106
+ comity: {
107
+ properties: {
108
+ layer: { enum: [...RUNTIME_LAYERS] },
109
+ },
110
+ },
111
+ },
112
+ },
113
+ },
114
+ {
115
+ if: {
116
+ properties: {
117
+ name: { pattern: "^@comity-dev/" },
118
+ },
119
+ required: ["name"],
120
+ },
121
+ then: {
122
+ properties: {
123
+ comity: {
124
+ properties: {
125
+ layer: { const: "dev-tooling" },
126
+ },
127
+ },
128
+ },
129
+ },
130
+ },
131
+ ],
132
+ };
133
+ /**
134
+ * Validates a parsed package.json against the canonical schema.
135
+ *
136
+ * @param manifest — parsed package.json object
137
+ * @param ajv — optional pre-built Ajv instance
138
+ * @returns validation result
139
+ */
140
+ export function validatePackageMetadata(manifest, ajv = createAjvInstance()) {
141
+ const validate = ajv.compile(packageMetadataSchema);
142
+ const valid = validate(manifest);
143
+ return {
144
+ valid: Boolean(valid),
145
+ errors: valid ? [] : (validate.errors ?? []),
146
+ };
147
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comity-dev/schemas",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Reusable JSON Schema definitions for Comity package metadata, ADR-008 register, and repository configuration. Development tooling.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -40,7 +40,8 @@
40
40
  "typescript": "^5.9.3"
41
41
  },
42
42
  "scripts": {
43
- "build": "tsc -p tsconfig.json",
44
- "test": "vitest run"
43
+ "generate": "node scripts/generate-adr-008.mjs",
44
+ "build": "node scripts/generate-adr-008.mjs && node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
45
+ "test": "vitest run --passWithNoTests"
45
46
  }
46
47
  }