@am_shork/attest 0.7.4 → 0.9.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 +1449 -157
- package/README.md +3 -2
- package/dist/cli/index.js +11 -8
- package/dist/cli/json.d.ts +26 -1
- package/dist/cli/json.js +28 -2
- package/dist/cli/report.js +9 -1
- package/dist/core/apply.d.ts +18 -1
- package/dist/core/apply.js +19 -2
- package/dist/core/gate.js +3 -3
- package/dist/core/locate.d.ts +19 -4
- package/dist/core/locate.js +90 -40
- package/dist/core/merge.js +218 -72
- package/dist/core/pipeline.d.ts +17 -1
- package/dist/core/pipeline.js +149 -35
- package/dist/core/red-record.d.ts +14 -5
- package/dist/core/red-record.js +82 -24
- package/dist/core/registry-issues.d.ts +30 -0
- package/dist/core/registry-issues.js +26 -0
- package/dist/core/registry.d.ts +12 -5
- package/dist/core/registry.js +10 -8
- package/dist/core/runner.js +21 -9
- package/dist/core/schema.d.ts +32 -27
- package/dist/core/schema.js +33 -5
- package/dist/core/skill.js +101 -27
- package/dist/core/splice.d.ts +62 -3
- package/dist/core/splice.js +297 -27
- package/dist/core/static-registry.d.ts +42 -0
- package/dist/core/static-registry.js +136 -21
- package/dist/core/status.js +2 -2
- package/dist/core/terminal.js +5 -2
- package/dist/core/types.d.ts +39 -10
- package/dist/core/validator.d.ts +1 -0
- package/dist/core/validator.js +22 -0
- package/package.json +2 -2
package/dist/core/status.js
CHANGED
|
@@ -49,7 +49,7 @@ export function statusRows(addedIds, plan, firstRun) {
|
|
|
49
49
|
name: s.name,
|
|
50
50
|
file: s.file,
|
|
51
51
|
line: s.line,
|
|
52
|
-
firstRun: recordedOutcome(firstRun, reqId, s.name) ?? null,
|
|
52
|
+
firstRun: recordedOutcome(firstRun, { reqId, file: s.file, name: s.name }) ?? null,
|
|
53
53
|
}));
|
|
54
54
|
return { reqId, state: obligationState(reqId, scenarios, firstRun), scenarios };
|
|
55
55
|
});
|
|
@@ -59,7 +59,7 @@ function obligationState(reqId, scenarios, firstRun) {
|
|
|
59
59
|
return 'no-scenario';
|
|
60
60
|
// Every scenario, not any: the gate raises never-red per scenario, so one
|
|
61
61
|
// proven scenario beside an unproven one is still a blocked change.
|
|
62
|
-
return scenarios.every((s) => hasRecordedRed(firstRun, reqId, s.name))
|
|
62
|
+
return scenarios.every((s) => hasRecordedRed(firstRun, { reqId, file: s.file, name: s.name }))
|
|
63
63
|
? 'proven'
|
|
64
64
|
: 'unproven';
|
|
65
65
|
}
|
package/dist/core/terminal.js
CHANGED
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
// write to the terminal of whoever is checking it. On a fork MR the author is
|
|
13
13
|
// not the reviewer, and the payload is a scenario name or an exception: erase
|
|
14
14
|
// the lines above, repaint a red verdict green, rewrite the window title. The
|
|
15
|
-
// `--json` path was never exposed
|
|
16
|
-
//
|
|
15
|
+
// `--json` path was recorded here as never exposed, on the grounds that
|
|
16
|
+
// `JSON.stringify` escapes every C0 character — true, and narrower than the
|
|
17
|
+
// class below, which also holds DEL and C1. `cli/json.ts` now applies the same
|
|
18
|
+
// rule at the point that document is serialised (ATX-74); this still has to
|
|
19
|
+
// hold independently, because a stream has no such point.
|
|
17
20
|
//
|
|
18
21
|
// **In `core/` rather than in the CLI**, though the CLI is its main caller: the
|
|
19
22
|
// loader has to sanitise Vite's log output for the same reason and cannot
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
export type { Requirement, Registry, ParamValue } from './schema.js';
|
|
2
2
|
export type { IssueCode } from './docs.js';
|
|
3
3
|
import type { IssueCode } from './docs.js';
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* What identifies one scenario, everywhere the engine compares one (design §5.4).
|
|
6
|
+
*
|
|
7
|
+
* All three, and as a bundle rather than three positional strings: the file was
|
|
8
|
+
* missing from the key that `declared-not-run` and the first-run record are
|
|
9
|
+
* decided by, and adding it as a fourth `string` argument beside `reqId` and
|
|
10
|
+
* `name` would have made two adjacent parameters of one type that a caller can
|
|
11
|
+
* silently transpose. The compiler cannot catch that; a field name can.
|
|
12
|
+
*/
|
|
13
|
+
export interface ScenarioRef {
|
|
6
14
|
reqId: string;
|
|
7
|
-
name: string;
|
|
8
15
|
file: string;
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
18
|
+
/** A scenario extracted statically from a spec file (design §5.2). */
|
|
19
|
+
export interface ParsedScenario extends ScenarioRef {
|
|
9
20
|
line: number;
|
|
10
21
|
}
|
|
11
22
|
/**
|
|
@@ -31,15 +42,33 @@ export type Outcome = 'pass' | 'fail';
|
|
|
31
42
|
export interface RunResult {
|
|
32
43
|
/** True when no test failed. */
|
|
33
44
|
passed: boolean;
|
|
34
|
-
/** reqId -> set of scenario names that actually executed (from the task tree). */
|
|
35
|
-
runtimeCoverage: Map<string, Set<string>>;
|
|
36
45
|
/**
|
|
37
|
-
* reqId ->
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
46
|
+
* reqId -> spec file -> the scenario names that actually executed (from the
|
|
47
|
+
* task tree).
|
|
48
|
+
*
|
|
49
|
+
* **The file is part of the key, and its absence was a false green.** Keyed by
|
|
50
|
+
* `(reqId, name)` alone, two spec files declaring the same scenario name under
|
|
51
|
+
* the same `requirement()` are one entry, so whichever of them executed
|
|
52
|
+
* vouched for the other and `declared-not-run` stayed silent about a scenario
|
|
53
|
+
* that never ran — the one report this tool exists to refuse. The static plan
|
|
54
|
+
* carries `file` on every `ParsedScenario` and the task tree carries it on
|
|
55
|
+
* every file task, so only this map ever forgot it.
|
|
56
|
+
*
|
|
57
|
+
* Project-relative POSIX, like `unloadedFiles` and for the same reason: it is
|
|
58
|
+
* compared against a plan built that way (`paths.ts`).
|
|
59
|
+
*/
|
|
60
|
+
runtimeCoverage: Map<string, Map<string, Set<string>>>;
|
|
61
|
+
/**
|
|
62
|
+
* reqId -> spec file -> scenario name -> how it ended. The same task-tree walk
|
|
63
|
+
* that fills `runtimeCoverage` already had to tell `pass` from `fail` to
|
|
64
|
+
* decide whether a scenario executed at all; this keeps that distinction
|
|
65
|
+
* instead of discarding it, which is what §6's mechanism 2 records.
|
|
66
|
+
*
|
|
67
|
+
* Keyed identically, and for the identical reason: the same collapse reaches
|
|
68
|
+
* `mergeRedRecord`, where a base scenario's recorded `fail` satisfied a
|
|
69
|
+
* same-named proposed scenario's first-red obligation.
|
|
41
70
|
*/
|
|
42
|
-
outcomes: Map<string, Map<string, Outcome
|
|
71
|
+
outcomes: Map<string, Map<string, Map<string, Outcome>>>;
|
|
43
72
|
/**
|
|
44
73
|
* Spec files that failed to *load*, as project-relative POSIX paths.
|
|
45
74
|
*
|
package/dist/core/validator.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { AttestPlan, Issue, ParamRef, Registry } from './types.js';
|
|
|
13
13
|
export declare function uncoveredIssues(registry: Registry, plan: AttestPlan): Issue[];
|
|
14
14
|
/**
|
|
15
15
|
* Static structural validation (design §5.3). Emits ERROR-level issues for:
|
|
16
|
+
* - empty-spec: the root declares no requirements at all
|
|
16
17
|
* - orphan-test: a scenario covers an unknown requirement id
|
|
17
18
|
* - uncovered-requirement: a requirement has no scenario
|
|
18
19
|
* - unbound-param: a statement placeholder has no matching param
|
package/dist/core/validator.js
CHANGED
|
@@ -28,6 +28,7 @@ export function uncoveredIssues(registry, plan) {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Static structural validation (design §5.3). Emits ERROR-level issues for:
|
|
31
|
+
* - empty-spec: the root declares no requirements at all
|
|
31
32
|
* - orphan-test: a scenario covers an unknown requirement id
|
|
32
33
|
* - uncovered-requirement: a requirement has no scenario
|
|
33
34
|
* - unbound-param: a statement placeholder has no matching param
|
|
@@ -47,6 +48,27 @@ export function uncoveredIssues(registry, plan) {
|
|
|
47
48
|
export function validateStructure(registry, plan, unreadable = []) {
|
|
48
49
|
const issues = [];
|
|
49
50
|
const knownIds = new Set(Object.keys(registry));
|
|
51
|
+
// empty-spec: nothing under this root declares intent, so no finding below is
|
|
52
|
+
// about a requirement — and the report has no line saying why. It is stated
|
|
53
|
+
// first because everything else this function can emit against an empty
|
|
54
|
+
// registry is fallout from it: every scenario in the project is an orphan, and
|
|
55
|
+
// the diagnosis after 135 of them is a diagnosis nobody reaches.
|
|
56
|
+
//
|
|
57
|
+
// Guarded on `unreadable`, which is the same withdrawal the orphan advice
|
|
58
|
+
// makes below and for the same reason. "Point attest at the directory holding
|
|
59
|
+
// your *.reqs.ts files" is right for a root that has none, and **wrong** for
|
|
60
|
+
// one whose registry is sitting right there and failed to load: the files were
|
|
61
|
+
// found, the fix is the load error already in the report, and following the
|
|
62
|
+
// hint would move a working path. A registry that could not be read is not an
|
|
63
|
+
// absent one, and the two take different repairs.
|
|
64
|
+
if (knownIds.size === 0 && unreadable.length === 0) {
|
|
65
|
+
issues.push({
|
|
66
|
+
level: 'ERROR',
|
|
67
|
+
code: 'empty-spec',
|
|
68
|
+
message: `No requirements found under this root, so there is no intent here to attest. ` +
|
|
69
|
+
`Point attest at the directory holding your *.reqs.ts files, or add one.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
50
72
|
// orphan-test: covers a requirement that does not exist.
|
|
51
73
|
//
|
|
52
74
|
// "Add it to the registry, or fix the id" is the right advice for an id that
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@am_shork/attest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "TDD-native spec framework: tests are the source of truth for verification, ID-bound requirements the source of truth for intent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"chalk": "^5.3.0",
|
|
49
49
|
"commander": "^12.1.0",
|
|
50
50
|
"typescript": "^5.5.0 || ^6.0.0",
|
|
51
|
-
"zod": "^
|
|
51
|
+
"zod": "^4.4.3"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"vite": "^8.0.0",
|