@intentset/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifact.d.ts +28 -0
- package/dist/artifact.d.ts.map +1 -0
- package/dist/artifact.js +621 -0
- package/dist/artifact.js.map +1 -0
- package/dist/carrier.d.ts +21 -0
- package/dist/carrier.d.ts.map +1 -0
- package/dist/carrier.js +70 -0
- package/dist/carrier.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +28 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +223 -0
- package/dist/context.js.map +1 -0
- package/dist/diagnostics.d.ts +37 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +22 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/export.d.ts +23 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +144 -0
- package/dist/export.js.map +1 -0
- package/dist/graph.d.ts +17 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +51 -0
- package/dist/graph.js.map +1 -0
- package/dist/hash.d.ts +16 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +55 -0
- package/dist/hash.js.map +1 -0
- package/dist/impact.d.ts +6 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +89 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/registries.d.ts +19 -0
- package/dist/registries.d.ts.map +1 -0
- package/dist/registries.js +137 -0
- package/dist/registries.js.map +1 -0
- package/dist/report.d.ts +34 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +58 -0
- package/dist/report.js.map +1 -0
- package/dist/types.d.ts +266 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +90 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +6 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +573 -0
- package/dist/validate.js.map +1 -0
- package/dist/yaml.d.ts +48 -0
- package/dist/yaml.d.ts.map +1 -0
- package/dist/yaml.js +413 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +36 -0
- package/src/artifact.ts +835 -0
- package/src/carrier.ts +81 -0
- package/src/config.ts +96 -0
- package/src/context.ts +240 -0
- package/src/diagnostics.ts +60 -0
- package/src/export.ts +173 -0
- package/src/graph.ts +49 -0
- package/src/hash.ts +53 -0
- package/src/impact.ts +90 -0
- package/src/index.ts +14 -0
- package/src/registries.ts +171 -0
- package/src/report.ts +84 -0
- package/src/types.ts +357 -0
- package/src/validate.ts +655 -0
- package/src/yaml.ts +406 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary of Core v0.1 (spec/core-0.1.md §2, §4, §5, §7) and the shapes
|
|
3
|
+
* the packages exchange. This file is the contract; it carries no logic.
|
|
4
|
+
*/
|
|
5
|
+
import type { Diagnostic } from "./diagnostics.ts";
|
|
6
|
+
|
|
7
|
+
export const SPEC_VERSION = "0.1";
|
|
8
|
+
|
|
9
|
+
export const ARTIFACT_TYPES = [
|
|
10
|
+
"product",
|
|
11
|
+
"intent",
|
|
12
|
+
"outcome",
|
|
13
|
+
"capability",
|
|
14
|
+
"behavior",
|
|
15
|
+
"rule",
|
|
16
|
+
"scenario",
|
|
17
|
+
"slice",
|
|
18
|
+
"contract",
|
|
19
|
+
"verification",
|
|
20
|
+
"knowledge",
|
|
21
|
+
"decision",
|
|
22
|
+
] as const;
|
|
23
|
+
export type ArtifactType = (typeof ARTIFACT_TYPES)[number];
|
|
24
|
+
|
|
25
|
+
export const STATUSES = ["draft", "approved", "implemented", "released", "deprecated", "retired"] as const;
|
|
26
|
+
export type Status = (typeof STATUSES)[number];
|
|
27
|
+
|
|
28
|
+
export const VISIBILITIES = ["public", "customer", "internal", "restricted"] as const;
|
|
29
|
+
export type Visibility = (typeof VISIBILITIES)[number];
|
|
30
|
+
|
|
31
|
+
/** Core §4. */
|
|
32
|
+
export const ID_PATTERN = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/;
|
|
33
|
+
|
|
34
|
+
/** The authored relationship fields of Core §5, in the direction they are written. */
|
|
35
|
+
export const LINK_KINDS = [
|
|
36
|
+
"parent",
|
|
37
|
+
"governedBy",
|
|
38
|
+
"illustrates",
|
|
39
|
+
"implements",
|
|
40
|
+
"dependsOn",
|
|
41
|
+
"exposes",
|
|
42
|
+
"consumes",
|
|
43
|
+
"verifies",
|
|
44
|
+
"explains",
|
|
45
|
+
"informedBy",
|
|
46
|
+
"requires",
|
|
47
|
+
"supports",
|
|
48
|
+
"replacedBy",
|
|
49
|
+
] as const;
|
|
50
|
+
export type LinkKind = (typeof LINK_KINDS)[number];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Allowed endpoints per relationship, Core §5. `parent` is listed per source
|
|
54
|
+
* type because its target depends on the source. `replacedBy` requires the
|
|
55
|
+
* same type on both ends, which the table cannot say; the validator checks it.
|
|
56
|
+
*/
|
|
57
|
+
export const LINK_ENDPOINTS: Record<
|
|
58
|
+
Exclude<LinkKind, "parent" | "replacedBy">,
|
|
59
|
+
{ from: readonly ArtifactType[]; to: readonly ArtifactType[] }
|
|
60
|
+
> = {
|
|
61
|
+
governedBy: { from: ["behavior"], to: ["rule"] },
|
|
62
|
+
illustrates: { from: ["scenario"], to: ["behavior"] },
|
|
63
|
+
implements: { from: ["slice"], to: ["behavior"] },
|
|
64
|
+
dependsOn: { from: ["slice"], to: ["slice"] },
|
|
65
|
+
exposes: { from: ["slice"], to: ["contract"] },
|
|
66
|
+
consumes: { from: ["slice"], to: ["contract"] },
|
|
67
|
+
verifies: { from: ["verification"], to: ["behavior", "rule", "scenario"] },
|
|
68
|
+
explains: { from: ["knowledge"], to: ["behavior", "rule", "capability"] },
|
|
69
|
+
informedBy: { from: ["slice", "contract", "behavior"], to: ["decision"] },
|
|
70
|
+
requires: { from: ["behavior"], to: ["behavior"] },
|
|
71
|
+
supports: { from: ["outcome", "capability"], to: ["intent", "outcome"] },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** `parent` targets per source type, Core §5. A product has no parent. */
|
|
75
|
+
export const PARENT_TARGETS: Partial<Record<ArtifactType, readonly ArtifactType[]>> = {
|
|
76
|
+
intent: ["product"],
|
|
77
|
+
outcome: ["intent"],
|
|
78
|
+
capability: ["outcome", "capability"],
|
|
79
|
+
behavior: ["capability"],
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Required level-two headings per type, Core §6. */
|
|
83
|
+
export const REQUIRED_SECTIONS: Record<ArtifactType, readonly string[]> = {
|
|
84
|
+
product: ["Scope"],
|
|
85
|
+
intent: ["Rationale"],
|
|
86
|
+
outcome: ["Measure"],
|
|
87
|
+
capability: ["Overview"],
|
|
88
|
+
behavior: ["Behavior", "Preconditions", "Outcomes"],
|
|
89
|
+
rule: ["Constraint"],
|
|
90
|
+
scenario: ["Given", "When", "Then"],
|
|
91
|
+
slice: ["Responsibility", "Public contract", "Verification"],
|
|
92
|
+
contract: ["Interface", "Compatibility"],
|
|
93
|
+
verification: ["Procedure", "Expected result"],
|
|
94
|
+
knowledge: ["Guidance"],
|
|
95
|
+
decision: ["Context", "Decision", "Consequences"],
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export interface Availability {
|
|
99
|
+
products: string[];
|
|
100
|
+
releases: string[];
|
|
101
|
+
roles: string[];
|
|
102
|
+
editions: string[];
|
|
103
|
+
flags: string[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const CLAIM_KINDS = ["source", "backend", "contract", "verification", "documentation"] as const;
|
|
107
|
+
export type ClaimKind = (typeof CLAIM_KINDS)[number];
|
|
108
|
+
|
|
109
|
+
export interface Claim {
|
|
110
|
+
kind: ClaimKind;
|
|
111
|
+
/** Repository-relative POSIX pattern: literal segments, `*` within a segment, `**` across segments (VSA §3). */
|
|
112
|
+
path: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** VSA §3 slice metadata. */
|
|
116
|
+
export interface SliceMeta {
|
|
117
|
+
kind: "product" | "technical";
|
|
118
|
+
rationale?: string;
|
|
119
|
+
domain: string;
|
|
120
|
+
/** Repository-relative file paths, the slice's public contract surfaces: one per package it spans (VSA §3). */
|
|
121
|
+
entrypoints: string[];
|
|
122
|
+
layers: Record<string, string[]>;
|
|
123
|
+
claims: Claim[];
|
|
124
|
+
usesResources: string[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Core §8 verification metadata. */
|
|
128
|
+
export interface VerificationMeta {
|
|
129
|
+
method: "automated" | "manual";
|
|
130
|
+
locator: string;
|
|
131
|
+
selector: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The `intentset` block of a document's frontmatter after validation, Core §4. */
|
|
135
|
+
export interface ArtifactMeta {
|
|
136
|
+
spec: typeof SPEC_VERSION;
|
|
137
|
+
profile: string;
|
|
138
|
+
id: string;
|
|
139
|
+
type: ArtifactType;
|
|
140
|
+
title: string;
|
|
141
|
+
status: Status;
|
|
142
|
+
owner: string;
|
|
143
|
+
visibility: Visibility;
|
|
144
|
+
audiences: string[];
|
|
145
|
+
parent?: string;
|
|
146
|
+
links: Partial<Record<Exclude<LinkKind, "parent">, string[]>>;
|
|
147
|
+
availability?: Availability;
|
|
148
|
+
revision?: number;
|
|
149
|
+
reviewedAt?: string;
|
|
150
|
+
reviewedBy?: string;
|
|
151
|
+
/** Namespaced extensions, preserved and never interpreted. */
|
|
152
|
+
extensions?: Record<string, unknown>;
|
|
153
|
+
slice?: SliceMeta;
|
|
154
|
+
verification?: VerificationMeta;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface Heading {
|
|
158
|
+
depth: number;
|
|
159
|
+
/** Plain text of the heading, inline markup removed. */
|
|
160
|
+
text: string;
|
|
161
|
+
/** 1-based line in the file. */
|
|
162
|
+
line: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* What a carrier parser hands to core (ADR 0003). `@intentset/markset-adapter`
|
|
167
|
+
* produces it with the Markset parser; `plainCarrier` in core produces it from
|
|
168
|
+
* nothing but the text, for the plain-Markdown fallback.
|
|
169
|
+
*/
|
|
170
|
+
export interface DocumentInput {
|
|
171
|
+
/** Repository-relative POSIX path. */
|
|
172
|
+
path: string;
|
|
173
|
+
/** The file's full UTF-8 text. */
|
|
174
|
+
source: string;
|
|
175
|
+
/** The raw YAML between the `---` fences, and the 1-based line the YAML starts on; null when absent. */
|
|
176
|
+
frontmatter: { text: string; line: number } | null;
|
|
177
|
+
/** Headings in document order, from outside code fences only. */
|
|
178
|
+
headings: Heading[];
|
|
179
|
+
/** Carrier diagnostics with origin "syntax", passed through unchanged. */
|
|
180
|
+
syntax: Diagnostic[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** One artifact: its validated metadata plus where it came from. */
|
|
184
|
+
export interface Artifact {
|
|
185
|
+
meta: ArtifactMeta;
|
|
186
|
+
path: string;
|
|
187
|
+
/** SHA-256 of the file bytes, lowercase hex. */
|
|
188
|
+
sourceHash: string;
|
|
189
|
+
/** The document body: everything after the frontmatter. */
|
|
190
|
+
body: string;
|
|
191
|
+
headings: Heading[];
|
|
192
|
+
/** Unknown top-level frontmatter keys, preserved as read (Core §3). */
|
|
193
|
+
foreign: Record<string, unknown>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface Edge {
|
|
197
|
+
kind: LinkKind;
|
|
198
|
+
from: string;
|
|
199
|
+
to: string;
|
|
200
|
+
/** True for the inverse of an authored edge; derived edges are never authored (Core §5, §12). */
|
|
201
|
+
derived: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface Graph {
|
|
205
|
+
artifacts: Map<string, Artifact>;
|
|
206
|
+
/** Authored edges, in document order then field order. */
|
|
207
|
+
edges: Edge[];
|
|
208
|
+
/** Inverse edges, one per authored edge, marked derived. */
|
|
209
|
+
derived: Edge[];
|
|
210
|
+
/** Outgoing authored edges by source ID. */
|
|
211
|
+
out: Map<string, Edge[]>;
|
|
212
|
+
/** Incoming authored edges by target ID. */
|
|
213
|
+
in: Map<string, Edge[]>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface Resource {
|
|
217
|
+
id: string;
|
|
218
|
+
path: string;
|
|
219
|
+
owner: string;
|
|
220
|
+
consumers: string[];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The repository registries that define owners, audiences, release dimensions and shared resources. */
|
|
224
|
+
export interface Registries {
|
|
225
|
+
owners: string[];
|
|
226
|
+
audiences: string[];
|
|
227
|
+
releases: string[];
|
|
228
|
+
roles: string[];
|
|
229
|
+
editions: string[];
|
|
230
|
+
flags: string[];
|
|
231
|
+
resources: Resource[];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export const EMPTY_REGISTRIES: Registries = {
|
|
235
|
+
owners: [],
|
|
236
|
+
audiences: [],
|
|
237
|
+
releases: [],
|
|
238
|
+
roles: [],
|
|
239
|
+
editions: [],
|
|
240
|
+
flags: [],
|
|
241
|
+
resources: [],
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/** `.intentset/config.yaml`: the declared repository scope a conformance claim is about (Core §11). */
|
|
245
|
+
export interface Config {
|
|
246
|
+
/** Stable identity of the repository, carried by the export (e.g. "intentset/intentset"). */
|
|
247
|
+
repository: string;
|
|
248
|
+
/** Globs selecting the documents in scope; the default is every `.md` file under the repository. */
|
|
249
|
+
scope: string[];
|
|
250
|
+
/** Path of registries.yaml, or null when the repository declares none. */
|
|
251
|
+
registries: string | null;
|
|
252
|
+
/** Globs excluded from scope and from source enumeration. */
|
|
253
|
+
ignore: string[];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Conformance levels, Core §11. Checks above the requested level do not run. */
|
|
257
|
+
export const LEVELS = ["L1", "L2", "L3", "L4", "L5"] as const;
|
|
258
|
+
export type Level = (typeof LEVELS)[number];
|
|
259
|
+
|
|
260
|
+
export interface ValidationOptions {
|
|
261
|
+
level?: Level;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export interface ValidationResult {
|
|
265
|
+
graph: Graph;
|
|
266
|
+
/** Sorted by compareDiagnostics. Includes the carrier's syntax diagnostics. */
|
|
267
|
+
diagnostics: Diagnostic[];
|
|
268
|
+
/** False when any diagnostic is an error. */
|
|
269
|
+
ok: boolean;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** One hop in an impact traversal, Core §10. */
|
|
273
|
+
export interface ImpactStep {
|
|
274
|
+
id: string;
|
|
275
|
+
/** The edge that led here, as seen from the start: "verifies←" means a verification that verifies the previous node. */
|
|
276
|
+
via: string;
|
|
277
|
+
reason: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface ImpactHit {
|
|
281
|
+
id: string;
|
|
282
|
+
type: ArtifactType;
|
|
283
|
+
title: string;
|
|
284
|
+
path: ImpactStep[];
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export interface ImpactReport {
|
|
288
|
+
start: string;
|
|
289
|
+
/** Artifacts one authored or derived edge away. */
|
|
290
|
+
direct: ImpactHit[];
|
|
291
|
+
/** Everything reachable beyond that, each with the path that reached it. */
|
|
292
|
+
candidates: ImpactHit[];
|
|
293
|
+
/** Outgoing rules, contracts and decisions, for review context. */
|
|
294
|
+
context: ImpactHit[];
|
|
295
|
+
/** Navigation ancestors through `parent`. */
|
|
296
|
+
ancestors: string[];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** The versioned export envelope (integration contract; spec/export.schema.json). */
|
|
300
|
+
export const EXPORT_CONTRACT = "intentset/export/0.1";
|
|
301
|
+
|
|
302
|
+
export interface ExportArtifact {
|
|
303
|
+
id: string;
|
|
304
|
+
type: ArtifactType;
|
|
305
|
+
title: string;
|
|
306
|
+
status: Status;
|
|
307
|
+
owner: string;
|
|
308
|
+
visibility: Visibility;
|
|
309
|
+
audiences: string[];
|
|
310
|
+
profile: string;
|
|
311
|
+
revision: number | null;
|
|
312
|
+
path: string;
|
|
313
|
+
sourceHash: string;
|
|
314
|
+
parent: string | null;
|
|
315
|
+
links: Partial<Record<Exclude<LinkKind, "parent">, string[]>>;
|
|
316
|
+
/** Inverse edges, keyed by the authored kind, marked derived by living here. */
|
|
317
|
+
derived: Partial<Record<LinkKind, string[]>>;
|
|
318
|
+
availability: Availability | null;
|
|
319
|
+
slice: SliceMeta | null;
|
|
320
|
+
verification: VerificationMeta | null;
|
|
321
|
+
extensions: Record<string, unknown> | null;
|
|
322
|
+
/** Present only when the export was asked to include bodies. */
|
|
323
|
+
body?: string;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface ExportEnvelope {
|
|
327
|
+
contract: typeof EXPORT_CONTRACT;
|
|
328
|
+
spec: typeof SPEC_VERSION;
|
|
329
|
+
generatedAt: string;
|
|
330
|
+
/** Stable identity of the repository, from config (e.g. "intentset/intentset"). */
|
|
331
|
+
repository: string;
|
|
332
|
+
products: string[];
|
|
333
|
+
source: {
|
|
334
|
+
/** The commit the export describes, or null with a reason when none could be read. */
|
|
335
|
+
commit: string | null;
|
|
336
|
+
commitUnavailable?: string;
|
|
337
|
+
};
|
|
338
|
+
/** SHA-256 over the canonical graph (ADR 0005). */
|
|
339
|
+
graphHash: string;
|
|
340
|
+
release: { product: string; label: string } | null;
|
|
341
|
+
validation: {
|
|
342
|
+
level: Level;
|
|
343
|
+
scope: string[];
|
|
344
|
+
status: "pass" | "fail";
|
|
345
|
+
errors: number;
|
|
346
|
+
warnings: number;
|
|
347
|
+
diagnostics: Diagnostic[];
|
|
348
|
+
};
|
|
349
|
+
registries: Registries;
|
|
350
|
+
artifacts: ExportArtifact[];
|
|
351
|
+
/** Optional report sections. Absent means "not supplied", never zero or pass. */
|
|
352
|
+
reports?: {
|
|
353
|
+
evidence?: unknown;
|
|
354
|
+
knowledge?: unknown;
|
|
355
|
+
impact?: unknown;
|
|
356
|
+
};
|
|
357
|
+
}
|