@am_shork/attest 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +876 -62
- package/README.md +157 -19
- package/dist/cli/index.js +91 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/json.d.ts +52 -5
- package/dist/cli/json.d.ts.map +1 -1
- package/dist/cli/json.js +50 -2
- package/dist/cli/json.js.map +1 -1
- package/dist/cli/report.d.ts +11 -1
- package/dist/cli/report.d.ts.map +1 -1
- package/dist/cli/report.js +114 -3
- package/dist/cli/report.js.map +1 -1
- package/dist/core/apply.d.ts +8 -0
- package/dist/core/apply.d.ts.map +1 -1
- package/dist/core/apply.js +10 -0
- package/dist/core/apply.js.map +1 -1
- package/dist/core/gate.d.ts +27 -1
- package/dist/core/gate.d.ts.map +1 -1
- package/dist/core/gate.js +48 -1
- package/dist/core/gate.js.map +1 -1
- package/dist/core/loader.d.ts +8 -0
- package/dist/core/loader.d.ts.map +1 -1
- package/dist/core/loader.js +19 -1
- package/dist/core/loader.js.map +1 -1
- package/dist/core/locate.d.ts +22 -1
- package/dist/core/locate.d.ts.map +1 -1
- package/dist/core/locate.js +76 -7
- package/dist/core/locate.js.map +1 -1
- package/dist/core/paths.d.ts +15 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +36 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/pipeline.d.ts +75 -5
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +212 -35
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/red-record.d.ts +56 -0
- package/dist/core/red-record.d.ts.map +1 -0
- package/dist/core/red-record.js +177 -0
- package/dist/core/red-record.js.map +1 -0
- package/dist/core/render.d.ts +1 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/core/render.js +16 -2
- package/dist/core/render.js.map +1 -1
- package/dist/core/runner.d.ts +1 -1
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +36 -11
- package/dist/core/runner.js.map +1 -1
- package/dist/core/skill.d.ts +23 -0
- package/dist/core/skill.d.ts.map +1 -0
- package/dist/core/skill.js +276 -0
- package/dist/core/skill.js.map +1 -0
- package/dist/core/static-registry.d.ts +28 -0
- package/dist/core/static-registry.d.ts.map +1 -1
- package/dist/core/static-registry.js +91 -25
- package/dist/core/static-registry.js.map +1 -1
- package/dist/core/status.d.ts +39 -0
- package/dist/core/status.d.ts.map +1 -0
- package/dist/core/status.js +64 -0
- package/dist/core/status.js.map +1 -0
- package/dist/core/targets.d.ts +52 -0
- package/dist/core/targets.d.ts.map +1 -0
- package/dist/core/targets.js +141 -0
- package/dist/core/targets.js.map +1 -0
- package/dist/core/types.d.ts +13 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/validator.d.ts +11 -0
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +28 -12
- package/dist/core/validator.js.map +1 -1
- package/dist/core/write.d.ts +2 -0
- package/dist/core/write.d.ts.map +1 -0
- package/dist/core/write.js +21 -0
- package/dist/core/write.js.map +1 -0
- package/dist/runtime.d.ts +9 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +10 -2
- package/dist/runtime.js.map +1 -1
- package/package.json +5 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Static
|
|
2
|
-
// the module (design §5.1, §5.2).
|
|
1
|
+
// Static extraction: a `*.reqs.ts` or `requirements.delta.ts` source -> the
|
|
2
|
+
// value it declares, without running the module (design §5.1, §5.2).
|
|
3
3
|
//
|
|
4
4
|
// Reading a registry used to mean evaluating it, which gave `attest check` the
|
|
5
5
|
// threat model of a test run while advertising itself as static analysis. This
|
|
@@ -12,11 +12,20 @@
|
|
|
12
12
|
// There is deliberately no fallback to evaluation: a reader that quietly runs
|
|
13
13
|
// the file when extraction fails guarantees nothing at all. `--eval` is the
|
|
14
14
|
// named way back.
|
|
15
|
+
//
|
|
16
|
+
// A change's `delta({ … })` goes through the *same* extraction, because `status`
|
|
17
|
+
// needs the ids a change adds and has no more right to execute project code than
|
|
18
|
+
// `check` does. Only the authoring function's name and the noun in the
|
|
19
|
+
// diagnostics differ, so the two readers share every line that decides whether a
|
|
20
|
+
// value is fixed by the source text — a second walker would be a second answer
|
|
21
|
+
// to "is this a literal", and those two answers must not be able to disagree.
|
|
15
22
|
import ts from 'typescript';
|
|
16
23
|
import { RegistryValidationError } from './registry.js';
|
|
17
24
|
import { RegistrySchema } from './schema.js';
|
|
18
25
|
/** The authoring function a registry file must default-export the result of. */
|
|
19
26
|
const DEFINE = 'defineRequirements';
|
|
27
|
+
/** The authoring function a change's delta file must default-export. */
|
|
28
|
+
const DELTA = 'delta';
|
|
20
29
|
/** A value could not be read from the source, and must never be guessed. */
|
|
21
30
|
class NotStatic extends Error {
|
|
22
31
|
node;
|
|
@@ -27,45 +36,67 @@ class NotStatic extends Error {
|
|
|
27
36
|
this.reason = reason;
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
|
-
|
|
39
|
+
/**
|
|
40
|
+
* The literal a file default-exports through `fn(...)`, or why it is not one.
|
|
41
|
+
*
|
|
42
|
+
* `noun` is the word the diagnostics use for what the file holds. It is a
|
|
43
|
+
* parameter rather than a second copy of these messages because the *decision*
|
|
44
|
+
* is identical for a registry and for a delta — what may be written, and what
|
|
45
|
+
* has to be run — and only the prose around it differs.
|
|
46
|
+
*/
|
|
47
|
+
function extractLiteralExport(file, source, fn, noun) {
|
|
31
48
|
const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, /* setParentNodes */ true);
|
|
32
49
|
const lineOf = (node) => sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
33
50
|
const exported = defaultExportExpression(sf);
|
|
34
51
|
if (!exported) {
|
|
35
|
-
// Same
|
|
36
|
-
//
|
|
52
|
+
// Same wording as the evaluating path: to an author who forgot the export,
|
|
53
|
+
// nothing about the diagnosis has changed.
|
|
37
54
|
return {
|
|
38
55
|
ok: false,
|
|
39
|
-
|
|
40
|
-
message:
|
|
56
|
+
reason: 'no-default',
|
|
57
|
+
message: `A ${noun} file must default-export the result of ${fn}(...).`,
|
|
41
58
|
};
|
|
42
59
|
}
|
|
43
|
-
const call =
|
|
60
|
+
const call = authoringCall(exported, sf, fn);
|
|
44
61
|
if (!call) {
|
|
45
62
|
return {
|
|
46
63
|
ok: false,
|
|
47
|
-
|
|
48
|
-
message: `A
|
|
49
|
-
|
|
64
|
+
reason: 'not-static',
|
|
65
|
+
message: `A ${noun} must be a literal: this file default-exports something other than a direct ${fn}({ … }) call, ` +
|
|
66
|
+
`so it cannot be read without running it. Inline the ${noun}, or pass --eval to read it by executing the file.`,
|
|
50
67
|
line: lineOf(exported),
|
|
51
68
|
};
|
|
52
69
|
}
|
|
53
|
-
let value;
|
|
54
70
|
try {
|
|
55
|
-
value
|
|
71
|
+
return { ok: true, value: literalValue(call) };
|
|
56
72
|
}
|
|
57
73
|
catch (err) {
|
|
58
74
|
if (!(err instanceof NotStatic))
|
|
59
75
|
throw err;
|
|
60
76
|
return {
|
|
61
77
|
ok: false,
|
|
62
|
-
|
|
63
|
-
message: `A
|
|
64
|
-
|
|
78
|
+
reason: 'not-static',
|
|
79
|
+
message: `A ${noun} must be a literal: ${err.reason} cannot be read without running the file. ` +
|
|
80
|
+
`Write the value inline, or pass --eval to read the ${noun} by executing the file.`,
|
|
65
81
|
line: lineOf(err.node),
|
|
66
82
|
};
|
|
67
83
|
}
|
|
68
|
-
|
|
84
|
+
}
|
|
85
|
+
/** Carry an extraction failure out under the code the calling reader owns. */
|
|
86
|
+
function failure(extracted, code) {
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
code,
|
|
90
|
+
message: extracted.message,
|
|
91
|
+
...(extracted.line === undefined ? {} : { line: extracted.line }),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function readRegistrySource(file, source) {
|
|
95
|
+
const extracted = extractLiteralExport(file, source, DEFINE, 'registry');
|
|
96
|
+
if (!extracted.ok) {
|
|
97
|
+
return failure(extracted, extracted.reason === 'no-default' ? 'registry-no-default' : 'registry-not-static');
|
|
98
|
+
}
|
|
99
|
+
const result = RegistrySchema.safeParse(extracted.value);
|
|
69
100
|
if (!result.success) {
|
|
70
101
|
// defineRequirements throws RegistryValidationError and loadRegistry wraps
|
|
71
102
|
// it; going through the same error keeps the message identical rather than
|
|
@@ -78,6 +109,41 @@ export function readRegistrySource(file, source) {
|
|
|
78
109
|
}
|
|
79
110
|
return { ok: true, registry: result.data };
|
|
80
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Read a change's `delta({ … })` from its source (design §7).
|
|
114
|
+
*
|
|
115
|
+
* The delta is deliberately **not** schema-validated here. `delta()` is an
|
|
116
|
+
* identity pass-through with no schema anywhere, so validating only on this path
|
|
117
|
+
* would make the static reader stricter than the evaluating one — a delta that
|
|
118
|
+
* archives today would stop being readable, which is the one thing extraction is
|
|
119
|
+
* not allowed to change.
|
|
120
|
+
*
|
|
121
|
+
* The codes are the ones `archive` already emits for the same two situations, so
|
|
122
|
+
* a consumer branching on `issues[].code` learns no new vocabulary: a file that
|
|
123
|
+
* does not export a delta is `change-not-found`, exactly as an unloadable one
|
|
124
|
+
* is, and a delta that is not a literal is `registry-not-static`, whose fix
|
|
125
|
+
* (write the value inline, or `--eval`) is the same sentence either way.
|
|
126
|
+
*/
|
|
127
|
+
export function readDeltaSource(file, source) {
|
|
128
|
+
const extracted = extractLiteralExport(file, source, DELTA, 'delta');
|
|
129
|
+
if (!extracted.ok) {
|
|
130
|
+
return failure(extracted, extracted.reason === 'no-default' ? 'change-not-found' : 'registry-not-static');
|
|
131
|
+
}
|
|
132
|
+
const value = extracted.value;
|
|
133
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
134
|
+
return {
|
|
135
|
+
ok: false,
|
|
136
|
+
code: 'change-not-found',
|
|
137
|
+
message: `A delta file must default-export the result of ${DELTA}({ … }).`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// No assertion: every field of a delta is optional, so the narrowed `object`
|
|
141
|
+
// is already assignable. Writing `as RegistryDelta` claimed a check this
|
|
142
|
+
// function deliberately does not make (see the note above on why a delta is
|
|
143
|
+
// not schema-validated here), which is the worst thing an assertion can do —
|
|
144
|
+
// look like verification.
|
|
145
|
+
return { ok: true, delta: value };
|
|
146
|
+
}
|
|
81
147
|
/**
|
|
82
148
|
* The expression a file default-exports, following one level of local binding.
|
|
83
149
|
*
|
|
@@ -112,22 +178,22 @@ function constInitializer(sf, name) {
|
|
|
112
178
|
return undefined;
|
|
113
179
|
}
|
|
114
180
|
/**
|
|
115
|
-
* The argument of the `
|
|
181
|
+
* The argument of the `fn(...)` call, if that is what this expression is.
|
|
116
182
|
*
|
|
117
183
|
* The callee is matched against the local name the import bound — an alias or a
|
|
118
184
|
* namespace import is the same call — rather than against any single-argument
|
|
119
185
|
* call, so `buildRegistry({…})` is not mistaken for a registry.
|
|
120
186
|
*/
|
|
121
|
-
function
|
|
187
|
+
function authoringCall(expr, sf, fn) {
|
|
122
188
|
if (!ts.isCallExpression(expr) || expr.arguments.length !== 1)
|
|
123
189
|
return undefined;
|
|
124
190
|
const callee = expr.expression;
|
|
125
|
-
const named = (ts.isIdentifier(callee) &&
|
|
126
|
-
(ts.isPropertyAccessExpression(callee) && callee.name.text ===
|
|
191
|
+
const named = (ts.isIdentifier(callee) && localNames(sf, fn).has(callee.text)) ||
|
|
192
|
+
(ts.isPropertyAccessExpression(callee) && callee.name.text === fn);
|
|
127
193
|
return named ? expr.arguments[0] : undefined;
|
|
128
194
|
}
|
|
129
|
-
/** Local names bound to the imported `
|
|
130
|
-
function
|
|
195
|
+
/** Local names bound to the imported `fn`, including aliases. */
|
|
196
|
+
function localNames(sf, fn) {
|
|
131
197
|
const names = new Set();
|
|
132
198
|
for (const statement of sf.statements) {
|
|
133
199
|
if (!ts.isImportDeclaration(statement))
|
|
@@ -136,13 +202,13 @@ function localDefineNames(sf) {
|
|
|
136
202
|
if (!bindings || !ts.isNamedImports(bindings))
|
|
137
203
|
continue;
|
|
138
204
|
for (const el of bindings.elements) {
|
|
139
|
-
if ((el.propertyName ?? el.name).text ===
|
|
205
|
+
if ((el.propertyName ?? el.name).text === fn)
|
|
140
206
|
names.add(el.name.text);
|
|
141
207
|
}
|
|
142
208
|
}
|
|
143
209
|
// A file that never imported it can still be read: the import may come from a
|
|
144
210
|
// global or a test harness, and the callee name is the only signal we need.
|
|
145
|
-
names.add(
|
|
211
|
+
names.add(fn);
|
|
146
212
|
return names;
|
|
147
213
|
}
|
|
148
214
|
/** Strip the type-level wrappers that do not change the value (`as const`, `satisfies`, parens). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-registry.js","sourceRoot":"","sources":["../../src/core/static-registry.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"static-registry.js","sourceRoot":"","sources":["../../src/core/static-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { RedRecord } from './red-record.js';
|
|
2
|
+
import type { AttestPlan, Outcome } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* What remains for one added requirement. Each name is the gate issue it
|
|
5
|
+
* predicts: `no-scenario` is `uncovered-requirement`, `unproven` is `never-red`,
|
|
6
|
+
* and `proven` is the absence of both.
|
|
7
|
+
*/
|
|
8
|
+
export type ObligationState = 'no-scenario' | 'unproven' | 'proven';
|
|
9
|
+
export interface ScenarioStatus {
|
|
10
|
+
name: string;
|
|
11
|
+
file: string;
|
|
12
|
+
line: number;
|
|
13
|
+
/**
|
|
14
|
+
* The recorded first run, or `null` when the record has never seen it.
|
|
15
|
+
*
|
|
16
|
+
* Kept as a third value rather than folded into a boolean because the two
|
|
17
|
+
* fixes differ, exactly as they do in the gate's two `never-red` messages: a
|
|
18
|
+
* recorded `pass` means the scenario does not test what it claims, while
|
|
19
|
+
* nothing recorded means the workflow's stage-1 run was skipped.
|
|
20
|
+
*/
|
|
21
|
+
firstRun: Outcome | null;
|
|
22
|
+
}
|
|
23
|
+
export interface StatusRow {
|
|
24
|
+
reqId: string;
|
|
25
|
+
state: ObligationState;
|
|
26
|
+
scenarios: ScenarioStatus[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One row per id the change adds, in id order.
|
|
30
|
+
*
|
|
31
|
+
* Ordered through the same code-unit comparator as everything else Attest
|
|
32
|
+
* commits or compares, so the report is a function of the input alone.
|
|
33
|
+
* Scenarios keep plan order — file, then line — because that is the order the
|
|
34
|
+
* author reads them in.
|
|
35
|
+
*/
|
|
36
|
+
export declare function statusRows(addedIds: readonly string[], plan: AttestPlan, firstRun: RedRecord): StatusRow[];
|
|
37
|
+
/** How many rows are in each state — the roll-up both renderings need. */
|
|
38
|
+
export declare function statusCounts(rows: readonly StatusRow[]): Record<ObligationState, number>;
|
|
39
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEpE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,SAAS,GAClB,SAAS,EAAE,CAYb;AAeD,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,CAQxF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Per-change progress: which of the gate's obligations a change has already
|
|
2
|
+
// met, computed from what can be read without running the suite (design §6, §8).
|
|
3
|
+
//
|
|
4
|
+
// `archive` is a change's only other touchpoint and it answers exactly one
|
|
5
|
+
// question — does the gate pass. Between "not started" and "archivable" there
|
|
6
|
+
// was no reportable state at all, so neither a person nor an agent could ask
|
|
7
|
+
// what remained without reading the delta and inferring.
|
|
8
|
+
//
|
|
9
|
+
// **This is a projection of the gate, not a second gate.** Every state here is
|
|
10
|
+
// named after the issue the gate will raise if the change is archived as it
|
|
11
|
+
// stands, and the obligation predicate is the gate's own (`hasRecordedRed`), so
|
|
12
|
+
// the two cannot answer differently about the same change. What it deliberately
|
|
13
|
+
// cannot answer is `tests-red`: that needs the suite, and a `status` that ran the
|
|
14
|
+
// suite would be `verify` with a filter. The last honest state is therefore
|
|
15
|
+
// "everything readable is in order", never "done".
|
|
16
|
+
//
|
|
17
|
+
// **Scoped to the ids the change ADDs**, for the same reason the never-red
|
|
18
|
+
// obligation is (design §6): a modified or removed requirement carries no
|
|
19
|
+
// obligation this command could report progress against, so listing one would
|
|
20
|
+
// add a row with nothing to do about it.
|
|
21
|
+
import { byCodeUnit } from './order.js';
|
|
22
|
+
import { hasRecordedRed, recordedOutcome } from './red-record.js';
|
|
23
|
+
/**
|
|
24
|
+
* One row per id the change adds, in id order.
|
|
25
|
+
*
|
|
26
|
+
* Ordered through the same code-unit comparator as everything else Attest
|
|
27
|
+
* commits or compares, so the report is a function of the input alone.
|
|
28
|
+
* Scenarios keep plan order — file, then line — because that is the order the
|
|
29
|
+
* author reads them in.
|
|
30
|
+
*/
|
|
31
|
+
export function statusRows(addedIds, plan, firstRun) {
|
|
32
|
+
return [...addedIds].sort(byCodeUnit).map((reqId) => {
|
|
33
|
+
const scenarios = plan.scenarios
|
|
34
|
+
.filter((s) => s.reqId === reqId)
|
|
35
|
+
.map((s) => ({
|
|
36
|
+
name: s.name,
|
|
37
|
+
file: s.file,
|
|
38
|
+
line: s.line,
|
|
39
|
+
firstRun: recordedOutcome(firstRun, reqId, s.name) ?? null,
|
|
40
|
+
}));
|
|
41
|
+
return { reqId, state: obligationState(reqId, scenarios, firstRun), scenarios };
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function obligationState(reqId, scenarios, firstRun) {
|
|
45
|
+
if (scenarios.length === 0)
|
|
46
|
+
return 'no-scenario';
|
|
47
|
+
// Every scenario, not any: the gate raises never-red per scenario, so one
|
|
48
|
+
// proven scenario beside an unproven one is still a blocked change.
|
|
49
|
+
return scenarios.every((s) => hasRecordedRed(firstRun, reqId, s.name))
|
|
50
|
+
? 'proven'
|
|
51
|
+
: 'unproven';
|
|
52
|
+
}
|
|
53
|
+
/** How many rows are in each state — the roll-up both renderings need. */
|
|
54
|
+
export function statusCounts(rows) {
|
|
55
|
+
const counts = {
|
|
56
|
+
'no-scenario': 0,
|
|
57
|
+
unproven: 0,
|
|
58
|
+
proven: 0,
|
|
59
|
+
};
|
|
60
|
+
for (const row of rows)
|
|
61
|
+
counts[row.state]++;
|
|
62
|
+
return counts;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/core/status.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,iFAAiF;AACjF,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,4EAA4E;AAC5E,mDAAmD;AACnD,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,8EAA8E;AAC9E,yCAAyC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAgClE;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,QAA2B,EAC3B,IAAgB,EAChB,QAAmB;IAEnB,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAClD,MAAM,SAAS,GAAqB,IAAI,CAAC,SAAS;aAC/C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC;aAChC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,eAAe,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI;SAC3D,CAAC,CAAC,CAAC;QACN,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CACtB,KAAa,EACb,SAAoC,EACpC,QAAmB;IAEnB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC;IACjD,0EAA0E;IAC1E,oEAAoE;IACpE,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACpE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,UAAU,CAAC;AACjB,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,IAA0B;IACrD,MAAM,MAAM,GAAoC;QAC9C,aAAa,EAAE,CAAC;QAChB,QAAQ,EAAE,CAAC;QACX,MAAM,EAAE,CAAC;KACV,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Issue } from './types.js';
|
|
2
|
+
/** One agent's instructions: a path Attest owns, and the bytes to put there. */
|
|
3
|
+
export interface AgentTarget {
|
|
4
|
+
/** The value `attest init --target <name>` accepts. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** The tool this reaches, for `--help` and the human report. */
|
|
7
|
+
tool: string;
|
|
8
|
+
/**
|
|
9
|
+
* Where the file goes, relative to the project root, spelled `/` on every
|
|
10
|
+
* platform (ATX-28) because it is also what the report carries.
|
|
11
|
+
*/
|
|
12
|
+
file: string;
|
|
13
|
+
/** The whole file. A pure function of nothing at all — see `workflowBody`. */
|
|
14
|
+
content(): string;
|
|
15
|
+
}
|
|
16
|
+
/** Where the Claude Code skill goes, relative to the project root. */
|
|
17
|
+
export declare const SKILL_FILE = ".claude/skills/attest/SKILL.md";
|
|
18
|
+
/**
|
|
19
|
+
* The Claude Code skill (ATX-27). `name` is what the user types to invoke it by
|
|
20
|
+
* hand; `description` is what loads it without being asked.
|
|
21
|
+
*/
|
|
22
|
+
export declare function skillContent(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Every target `init` can write, in the order it writes them.
|
|
25
|
+
*
|
|
26
|
+
* The order is this table's, never the order the flags were typed: two runs
|
|
27
|
+
* asking for the same set have to produce the same report.
|
|
28
|
+
*/
|
|
29
|
+
export declare const TARGETS: readonly AgentTarget[];
|
|
30
|
+
/**
|
|
31
|
+
* What `init` writes when the user names no target.
|
|
32
|
+
*
|
|
33
|
+
* One target rather than all of them: the others are files in a repository
|
|
34
|
+
* whose owner did not ask for them, and a tool that scatters configuration for
|
|
35
|
+
* editors nobody here uses is a tool people stop running.
|
|
36
|
+
*/
|
|
37
|
+
export declare const DEFAULT_TARGET = "claude";
|
|
38
|
+
export declare const TARGET_NAMES: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Resolve requested names to targets, or refuse the whole set.
|
|
41
|
+
*
|
|
42
|
+
* All-or-nothing on purpose, and the caller writes nothing while `issues` is
|
|
43
|
+
* non-empty: a name already known to be unwritable must not leave half a set of
|
|
44
|
+
* instruction files behind, in the same way `archive` validates a change name
|
|
45
|
+
* before a loader is even created. Duplicates collapse, because asking twice is
|
|
46
|
+
* not asking for two files.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveTargets(names: readonly string[]): {
|
|
49
|
+
targets: AgentTarget[];
|
|
50
|
+
issues: Issue[];
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../../src/core/targets.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,IAAI,MAAM,CAAC;CACnB;AAED,sEAAsE;AACtE,eAAO,MAAM,UAAU,mCAAmC,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAQrC;AAwCD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,SAAS,WAAW,EAmBzC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,WAAW,CAAC;AAEvC,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EAA+B,CAAC;AAE1E;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG;IACxD,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB,CAgBA"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Where the workflow document goes, per agent (design §9).
|
|
2
|
+
//
|
|
3
|
+
// `attest init` wrote one file, `.claude/skills/attest/SKILL.md`, so an adopter
|
|
4
|
+
// whose agent reads somewhere else got the engine and not the workflow — the
|
|
5
|
+
// exact gap `init` exists to close, open for every tool but one. A target is a
|
|
6
|
+
// destination path plus the frontmatter that tool reads; the document itself is
|
|
7
|
+
// `skill.ts` and is the same bytes for all of them.
|
|
8
|
+
//
|
|
9
|
+
// **Two rules decide what may become a target, and neither is about effort.**
|
|
10
|
+
//
|
|
11
|
+
// 1. *Attest owns the path.* `.claude/skills/attest/SKILL.md` exists because
|
|
12
|
+
// Attest exists, and so does every path below. `AGENTS.md` and `CLAUDE.md`
|
|
13
|
+
// exist because the *project* does, and what is in them is prose their
|
|
14
|
+
// maintainer curated: writing there is a read-modify-write on someone else's
|
|
15
|
+
// document, whose failure modes are destructive on a file the user cannot
|
|
16
|
+
// regenerate, and it would demote idempotence from a property of a pure
|
|
17
|
+
// function to a behaviour needing test coverage. That is a permanent scoping
|
|
18
|
+
// rule (design §9), not a gap waiting to be filled — an adopter whose agent
|
|
19
|
+
// reads such a file writes one line pointing at one of these instead.
|
|
20
|
+
// 2. *The instructions load on demand.* A skill body is fetched when its
|
|
21
|
+
// description matches, a Cursor rule when the agent asks for it, a Copilot
|
|
22
|
+
// instructions file when the open path matches its `applyTo`. A carrier that
|
|
23
|
+
// is unconditionally resident charges every unrelated request in the repo for
|
|
24
|
+
// a workflow it will not use.
|
|
25
|
+
//
|
|
26
|
+
// Adding a target is a row in the table below plus a scenario: the document,
|
|
27
|
+
// the writer and the CLI are already general over it.
|
|
28
|
+
import { WORKFLOW_DESCRIPTION, workflowBody } from './skill.js';
|
|
29
|
+
/** Where the Claude Code skill goes, relative to the project root. */
|
|
30
|
+
export const SKILL_FILE = '.claude/skills/attest/SKILL.md';
|
|
31
|
+
/**
|
|
32
|
+
* The Claude Code skill (ATX-27). `name` is what the user types to invoke it by
|
|
33
|
+
* hand; `description` is what loads it without being asked.
|
|
34
|
+
*/
|
|
35
|
+
export function skillContent() {
|
|
36
|
+
return `---
|
|
37
|
+
name: attest
|
|
38
|
+
description: ${WORKFLOW_DESCRIPTION}
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
${workflowBody()}
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A Cursor project rule. `alwaysApply: false` with a description is Cursor's
|
|
46
|
+
* agent-requested mode — the model pulls the rule in when the description
|
|
47
|
+
* matches, which is the same loading model as the skill. Deliberately no
|
|
48
|
+
* `globs`: that is the auto-attach mode, and it would make the rule fire on a
|
|
49
|
+
* file being open rather than on the work being about intent.
|
|
50
|
+
*/
|
|
51
|
+
function cursorContent() {
|
|
52
|
+
return `---
|
|
53
|
+
description: ${WORKFLOW_DESCRIPTION}
|
|
54
|
+
alwaysApply: false
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
${workflowBody()}
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A Copilot instructions file. Copilot has no description-triggered mode, so
|
|
62
|
+
* the trigger is the path: `applyTo` is the intent layer, the specs and a change
|
|
63
|
+
* folder — where the decisions this document is about are made.
|
|
64
|
+
*
|
|
65
|
+
* The limit is real and is the reason the glob is not `**`: editing an
|
|
66
|
+
* implementation file to make a scenario pass does not load these instructions,
|
|
67
|
+
* so the rules about *not* editing the scenario instead arrive when the agent is
|
|
68
|
+
* in the spec, not when it is tempted. Unconditional loading buys that at the
|
|
69
|
+
* cost of every unrelated request in the repo, which rule 2 above declines.
|
|
70
|
+
*/
|
|
71
|
+
function copilotContent() {
|
|
72
|
+
return `---
|
|
73
|
+
description: ${WORKFLOW_DESCRIPTION}
|
|
74
|
+
applyTo: '**/*.reqs.ts,**/*.spec.ts,**/changes/**'
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
${workflowBody()}
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Every target `init` can write, in the order it writes them.
|
|
82
|
+
*
|
|
83
|
+
* The order is this table's, never the order the flags were typed: two runs
|
|
84
|
+
* asking for the same set have to produce the same report.
|
|
85
|
+
*/
|
|
86
|
+
export const TARGETS = [
|
|
87
|
+
{
|
|
88
|
+
name: 'claude',
|
|
89
|
+
tool: 'Claude Code',
|
|
90
|
+
file: SKILL_FILE,
|
|
91
|
+
content: skillContent,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'copilot',
|
|
95
|
+
tool: 'GitHub Copilot',
|
|
96
|
+
file: '.github/instructions/attest.instructions.md',
|
|
97
|
+
content: copilotContent,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'cursor',
|
|
101
|
+
tool: 'Cursor',
|
|
102
|
+
file: '.cursor/rules/attest.mdc',
|
|
103
|
+
content: cursorContent,
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
/**
|
|
107
|
+
* What `init` writes when the user names no target.
|
|
108
|
+
*
|
|
109
|
+
* One target rather than all of them: the others are files in a repository
|
|
110
|
+
* whose owner did not ask for them, and a tool that scatters configuration for
|
|
111
|
+
* editors nobody here uses is a tool people stop running.
|
|
112
|
+
*/
|
|
113
|
+
export const DEFAULT_TARGET = 'claude';
|
|
114
|
+
export const TARGET_NAMES = TARGETS.map((t) => t.name);
|
|
115
|
+
/**
|
|
116
|
+
* Resolve requested names to targets, or refuse the whole set.
|
|
117
|
+
*
|
|
118
|
+
* All-or-nothing on purpose, and the caller writes nothing while `issues` is
|
|
119
|
+
* non-empty: a name already known to be unwritable must not leave half a set of
|
|
120
|
+
* instruction files behind, in the same way `archive` validates a change name
|
|
121
|
+
* before a loader is even created. Duplicates collapse, because asking twice is
|
|
122
|
+
* not asking for two files.
|
|
123
|
+
*/
|
|
124
|
+
export function resolveTargets(names) {
|
|
125
|
+
const wanted = new Set(names);
|
|
126
|
+
const issues = [];
|
|
127
|
+
for (const name of wanted) {
|
|
128
|
+
if (!TARGETS.some((t) => t.name === name)) {
|
|
129
|
+
issues.push({
|
|
130
|
+
level: 'ERROR',
|
|
131
|
+
code: 'unknown-target',
|
|
132
|
+
message: `Unknown agent target '${name}'. Known targets: ${TARGET_NAMES.join(', ')}.`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
targets: issues.length > 0 ? [] : TARGETS.filter((t) => wanted.has(t.name)),
|
|
138
|
+
issues,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../../src/core/targets.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,gFAAgF;AAChF,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,oDAAoD;AACpD,EAAE;AACF,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,0EAA0E;AAC1E,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAC3E,gFAAgF;AAChF,+EAA+E;AAC/E,yEAAyE;AACzE,yEAAyE;AACzE,8EAA8E;AAC9E,gFAAgF;AAChF,iFAAiF;AACjF,iCAAiC;AACjC,EAAE;AACF,6EAA6E;AAC7E,sDAAsD;AAGtD,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiBhE,sEAAsE;AACtE,MAAM,CAAC,MAAM,UAAU,GAAG,gCAAgC,CAAC;AAE3D;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO;;eAEM,oBAAoB;;;EAGjC,YAAY,EAAE;CACf,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa;IACpB,OAAO;eACM,oBAAoB;;;;EAIjC,YAAY,EAAE;CACf,CAAC;AACF,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,cAAc;IACrB,OAAO;eACM,oBAAoB;;;;EAIjC,YAAY,EAAE;CACf,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAA2B;IAC7C;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,YAAY;KACtB;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,gBAAgB;QACtB,IAAI,EAAE,6CAA6C;QACnD,OAAO,EAAE,cAAc;KACxB;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,aAAa;KACvB;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEvC,MAAM,CAAC,MAAM,YAAY,GAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAE1E;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,KAAwB;IAIrD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC;gBACV,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAE,yBAAyB,IAAI,qBAAqB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aACtF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM;KACP,CAAC;AACJ,CAAC"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -19,12 +19,25 @@ export interface AttestPlan {
|
|
|
19
19
|
scenarios: ParsedScenario[];
|
|
20
20
|
paramRefs: ParamRef[];
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* What one scenario did in a run. Only the two executed states exist: a skipped
|
|
24
|
+
* or todo scenario has no outcome at all, which is what `declared-not-run`
|
|
25
|
+
* reports (design §8) and what keeps a skip from being recorded as a red.
|
|
26
|
+
*/
|
|
27
|
+
export type Outcome = 'pass' | 'fail';
|
|
22
28
|
/** Result of an executable verification run (design §5.4). */
|
|
23
29
|
export interface RunResult {
|
|
24
30
|
/** True when no test failed. */
|
|
25
31
|
passed: boolean;
|
|
26
32
|
/** reqId -> set of scenario names that actually executed (from the task tree). */
|
|
27
33
|
runtimeCoverage: Map<string, Set<string>>;
|
|
34
|
+
/**
|
|
35
|
+
* reqId -> scenario name -> how it ended. The same task-tree walk that fills
|
|
36
|
+
* `runtimeCoverage` already had to tell `pass` from `fail` to decide whether a
|
|
37
|
+
* scenario executed at all; this keeps that distinction instead of discarding
|
|
38
|
+
* it, which is what §6's mechanism 2 records.
|
|
39
|
+
*/
|
|
40
|
+
outcomes: Map<string, Map<string, Outcome>>;
|
|
28
41
|
}
|
|
29
42
|
/** Severity levels for graded reporting (design §5.3). */
|
|
30
43
|
export type Level = 'ERROR' | 'WARNING' | 'INFO';
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEzD,sEAAsE;AACtE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,gCAAgC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEzD,sEAAsE;AACtE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtC,8DAA8D;AAC9D,MAAM,WAAW,SAAS;IACxB,gCAAgC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,kFAAkF;IAClF,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C;;;;;OAKG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC7C;AAED,0DAA0D;AAC1D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAEjD"}
|
package/dist/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,4EAA4E;AAC5E,gFAAgF;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,4EAA4E;AAC5E,gFAAgF;AAqEhF;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAe;IACtC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC;AACjD,CAAC"}
|
package/dist/core/validator.d.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { AttestPlan, Issue, ParamRef, Registry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Uncovered requirements: intent exists but no scenario attests it (design §5.3).
|
|
4
|
+
*
|
|
5
|
+
* Exported because `check` and `cover` both report this, and `cover` used to
|
|
6
|
+
* report it only as a `covered: false` row — so a `--json` consumer following
|
|
7
|
+
* the documented rule ("branch on `ok` / `issues[].code`") got a false verdict
|
|
8
|
+
* with an empty `issues` array from exactly one command. Two commands stating
|
|
9
|
+
* one fact in two shapes is the same clerical agreement `declaredNotRunIssues`
|
|
10
|
+
* was extracted to remove.
|
|
11
|
+
*/
|
|
12
|
+
export declare function uncoveredIssues(registry: Registry, plan: AttestPlan): Issue[];
|
|
2
13
|
/**
|
|
3
14
|
* Static structural validation (design §5.3). Emits ERROR-level issues for:
|
|
4
15
|
* - orphan-test: a scenario covers an unknown requirement id
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAkB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAkB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAExF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,CAc7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,KAAK,EAAE,CAiE/E;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,QAAQ,EAAE,GACf,KAAK,EAAE,CA+BT"}
|