@intentset/core 0.6.0 → 0.7.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 +41 -0
- package/dist/artifact.d.ts.map +1 -1
- package/dist/artifact.js +18 -5
- package/dist/artifact.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +49 -2
- package/dist/config.js.map +1 -1
- package/dist/export.js +18 -3
- package/dist/export.js.map +1 -1
- package/dist/read-export.d.ts.map +1 -1
- package/dist/read-export.js +80 -14
- package/dist/read-export.js.map +1 -1
- package/dist/types.d.ts +43 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -2
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +10 -0
- package/dist/validate.js.map +1 -1
- package/package.json +1 -1
- package/src/artifact.ts +15 -4
- package/src/config.ts +71 -3
- package/src/export.ts +19 -3
- package/src/read-export.ts +93 -12
- package/src/types.ts +45 -6
- package/src/validate.ts +11 -0
package/src/types.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The vocabulary of Core v0.
|
|
2
|
+
* The vocabulary of Core v0.2 (spec/core-0.2.md §2, §4, §5, §7) and the shapes
|
|
3
3
|
* the packages exchange. This file is the contract; it carries no logic.
|
|
4
4
|
*/
|
|
5
5
|
import type { Diagnostic } from "./diagnostics.ts";
|
|
6
6
|
|
|
7
|
-
export const SPEC_VERSION = "0.
|
|
7
|
+
export const SPEC_VERSION = "0.2";
|
|
8
|
+
|
|
9
|
+
/** The version `SPEC_VERSION` followed (Core §1), named so the error for a record still at it can point to `intentset migrate`. */
|
|
10
|
+
export const PREVIOUS_SPEC_VERSION = "0.1";
|
|
8
11
|
|
|
9
12
|
export const ARTIFACT_TYPES = [
|
|
10
13
|
"product",
|
|
@@ -136,6 +139,8 @@ export interface VerificationMeta {
|
|
|
136
139
|
method: "automated" | "manual";
|
|
137
140
|
locator: string;
|
|
138
141
|
selector: string;
|
|
142
|
+
/** Slice or resource IDs the check drives beyond what its behaviors' slices reach (Core §8, ADR 0013); unique. */
|
|
143
|
+
exercises?: string[];
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
export const MEASURE_DIRECTIONS = ["increase", "decrease"] as const;
|
|
@@ -286,6 +291,20 @@ export interface Config {
|
|
|
286
291
|
registries: string | null;
|
|
287
292
|
/** Globs excluded from scope and from source enumeration. */
|
|
288
293
|
ignore: string[];
|
|
294
|
+
/** How run evidence is judged current (Core §8, ADR 0013). */
|
|
295
|
+
evidence: EvidenceConfig;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** The two bindings of run evidence to what it checks (Core §8). */
|
|
299
|
+
export const EVIDENCE_BINDINGS = ["subject", "commit"] as const;
|
|
300
|
+
export type EvidenceBinding = (typeof EVIDENCE_BINDINGS)[number];
|
|
301
|
+
|
|
302
|
+
/** `evidence:` in `.intentset/config.yaml`; both members optional. */
|
|
303
|
+
export interface EvidenceConfig {
|
|
304
|
+
/** The binding a repository asks for; null leaves the default (subject where slices exist, else commit). */
|
|
305
|
+
binding: EvidenceBinding | null;
|
|
306
|
+
/** Files whose change affects every check and that belong to no slice: paths or patterns, mixed into every subject. */
|
|
307
|
+
globalInputs: string[];
|
|
289
308
|
}
|
|
290
309
|
|
|
291
310
|
/** Conformance levels, Core §11. Checks above the requested level do not run. */
|
|
@@ -336,8 +355,11 @@ export interface ImpactReport {
|
|
|
336
355
|
* the first version a consumer could pin: 0.1 carried untyped report slots and
|
|
337
356
|
* restricted artifacts by default (ADR 0008). 0.3 added the measure type, the
|
|
338
357
|
* `evidenceSources` registry, and `measure` and `tips` on every artifact (ADR 0012).
|
|
358
|
+
* 0.4 carries the evidence binding: which binding judged each verification, the
|
|
359
|
+
* subject it was judged at, each record's binding and subject hash, and a
|
|
360
|
+
* verification's `exercises` (ADR 0014).
|
|
339
361
|
*/
|
|
340
|
-
export const EXPORT_CONTRACT = "intentset/export/0.
|
|
362
|
+
export const EXPORT_CONTRACT = "intentset/export/0.4";
|
|
341
363
|
|
|
342
364
|
/** The contracts this implementation reads. A consumer rejects every other value (spec/export.md §5). */
|
|
343
365
|
export const SUPPORTED_EXPORT_CONTRACTS: readonly string[] = [EXPORT_CONTRACT];
|
|
@@ -367,7 +389,8 @@ export interface ExportArtifact {
|
|
|
367
389
|
withheldLinks: number;
|
|
368
390
|
availability: Availability | null;
|
|
369
391
|
slice: SliceMeta | null;
|
|
370
|
-
|
|
392
|
+
/** `exercises` is the list as authored, less withheld IDs (counted in `withheldLinks`); empty when the record names none. */
|
|
393
|
+
verification: (Omit<VerificationMeta, "exercises"> & { exercises: string[] }) | null;
|
|
371
394
|
/** Null unless the artifact is a measure; `direction` is null when the author set none. */
|
|
372
395
|
measure: (Omit<MeasureMeta, "direction"> & { direction: MeasureDirection | null }) | null;
|
|
373
396
|
/** Null unless the artifact is knowledge with tips (Core §9). */
|
|
@@ -377,7 +400,7 @@ export interface ExportArtifact {
|
|
|
377
400
|
body?: string;
|
|
378
401
|
}
|
|
379
402
|
|
|
380
|
-
/** A run record as the evidence report carries it: spec/evidence.schema.json's record, unchanged. */
|
|
403
|
+
/** A run record as the evidence report carries it: spec/evidence.schema.json's record, unchanged, `binding` and `subjectHash` included. */
|
|
381
404
|
export interface ExportRunRecord {
|
|
382
405
|
evidenceId: string;
|
|
383
406
|
verificationId: string;
|
|
@@ -391,10 +414,18 @@ export interface ExportRunRecord {
|
|
|
391
414
|
finishedAt: string;
|
|
392
415
|
result: "pass" | "fail" | "skip" | "error";
|
|
393
416
|
uri: string;
|
|
417
|
+
/** What the record is bound to (Core §8); absent means commit. */
|
|
418
|
+
binding?: EvidenceBinding;
|
|
419
|
+
/** The hash of the subject the run checked; present when `binding` is subject. */
|
|
420
|
+
subjectHash?: string;
|
|
394
421
|
rationale?: string;
|
|
395
422
|
extensions?: Record<string, unknown>;
|
|
396
423
|
}
|
|
397
424
|
|
|
425
|
+
/** Why the binding of a report is the one in force: the repository asked, the default (subject, since slices claim files), or the fallback to commit for want of slice claims (EVID004). */
|
|
426
|
+
export const EVIDENCE_BINDING_REASONS = ["configured", "default", "no-slices"] as const;
|
|
427
|
+
export type EvidenceBindingReason = (typeof EVIDENCE_BINDING_REASONS)[number];
|
|
428
|
+
|
|
398
429
|
/** Core §8 freshness, as the evidence check classifies it. Only current-pass is a pass. */
|
|
399
430
|
export const EXPORT_EVIDENCE_STATUSES = [
|
|
400
431
|
"current-pass",
|
|
@@ -416,6 +447,10 @@ export interface EvidenceReportSection {
|
|
|
416
447
|
scope: { product: string; release: string } | null;
|
|
417
448
|
/** Run records read, before classification. */
|
|
418
449
|
records: number;
|
|
450
|
+
/** The binding the repository judged by (Core §8): every verification below was judged by it. */
|
|
451
|
+
binding: EvidenceBinding;
|
|
452
|
+
/** Why: `no-slices` is the fallback to commit binding (EVID004), the only way a repository that asked for nothing is judged by commit. */
|
|
453
|
+
bindingReason: EvidenceBindingReason;
|
|
419
454
|
/** One per verification artifact, sorted by ID. */
|
|
420
455
|
verifications: ExportVerificationEvidence[];
|
|
421
456
|
/** One per behavior, rule and scenario that is not retired, sorted by ID. */
|
|
@@ -426,7 +461,11 @@ export interface ExportVerificationEvidence {
|
|
|
426
461
|
id: string;
|
|
427
462
|
method: "automated" | "manual";
|
|
428
463
|
status: ExportEvidenceStatus;
|
|
429
|
-
/**
|
|
464
|
+
/** The binding that judged it. */
|
|
465
|
+
binding: EvidenceBinding;
|
|
466
|
+
/** Under subject binding, the SHA-256 of the verification's subject at this snapshot, which a `subject` record's `subjectHash` must equal to be current; null under commit binding, and when none could be computed. */
|
|
467
|
+
subject: string | null;
|
|
468
|
+
/** Why the status is qualified, or what was set aside, and for a stale subject record which part of the subject moved; null when nothing was. */
|
|
430
469
|
note: string | null;
|
|
431
470
|
/** The record that decided the status: the latest at the snapshot, else the latest in scope; null when none. */
|
|
432
471
|
latest: ExportRunRecord | null;
|
package/src/validate.ts
CHANGED
|
@@ -438,6 +438,17 @@ function checkLifecycle(context: Context): void {
|
|
|
438
438
|
});
|
|
439
439
|
}
|
|
440
440
|
});
|
|
441
|
+
meta.verification?.exercises?.forEach((target, i) => {
|
|
442
|
+
if (graph.artifacts.get(target)?.meta.type !== "slice" && !resourceIds.has(target)) {
|
|
443
|
+
reportOn(context, artifact, {
|
|
444
|
+
code: "CORE003",
|
|
445
|
+
field: `/intentset/verification/exercises/${i}`,
|
|
446
|
+
message: `exercises names ${target}, which is neither a slice in the graph nor a resource in the registries.`,
|
|
447
|
+
remediation:
|
|
448
|
+
"Name the slice or registry resource the check drives, so a change to its files makes the evidence stale (Core §8), or remove the entry.",
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
441
452
|
if (meta.status === "retired" && (meta.links.replacedBy ?? []).length === 0) {
|
|
442
453
|
reportOn(context, artifact, {
|
|
443
454
|
code: "CORE005",
|