@am_shork/attest 0.1.5 → 0.1.7
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 +246 -1
- package/README.md +56 -1
- package/dist/cli/index.js +81 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/json.d.ts +8 -1
- package/dist/cli/json.d.ts.map +1 -1
- package/dist/cli/json.js +8 -0
- package/dist/cli/json.js.map +1 -1
- package/dist/core/apply.d.ts.map +1 -1
- package/dist/core/apply.js +7 -1
- package/dist/core/apply.js.map +1 -1
- package/dist/core/gate.d.ts +9 -0
- package/dist/core/gate.d.ts.map +1 -1
- package/dist/core/gate.js +25 -12
- package/dist/core/gate.js.map +1 -1
- package/dist/core/loader.d.ts.map +1 -1
- package/dist/core/loader.js +16 -1
- package/dist/core/loader.js.map +1 -1
- package/dist/core/locate.d.ts +29 -2
- package/dist/core/locate.d.ts.map +1 -1
- package/dist/core/locate.js +71 -28
- package/dist/core/locate.js.map +1 -1
- package/dist/core/order.d.ts +3 -0
- package/dist/core/order.d.ts.map +1 -0
- package/dist/core/order.js +13 -0
- package/dist/core/order.js.map +1 -0
- package/dist/core/pipeline.d.ts +33 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +103 -24
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/render.d.ts +39 -0
- package/dist/core/render.d.ts.map +1 -0
- package/dist/core/render.js +168 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +16 -4
- package/dist/core/validator.js.map +1 -1
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,88 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Under consideration (non-breaking, not implemented)
|
|
11
|
+
|
|
12
|
+
- **`attest check` is described as static validation, but it executes every
|
|
13
|
+
`*.reqs.ts` it finds.** Reading a registry means evaluating the module, via
|
|
14
|
+
Vite, anywhere under the project root. That is the same threat model as
|
|
15
|
+
`vitest run` — except `check` is advertised as "static structural validation
|
|
16
|
+
(fast CI pre-check)", which is exactly the wording that gets it scheduled
|
|
17
|
+
ahead of, or outside, whatever sandbox the test run is given. On a fork MR,
|
|
18
|
+
a `*.reqs.ts` with a top-level `fetch` is enough.
|
|
19
|
+
*The candidate fix, and why it is more than a patch:* read the registry from
|
|
20
|
+
the AST instead — the compiler API is already the parser layer's tool — for
|
|
21
|
+
`check`, `cover` and `render`, keeping the loader for `verify` and `archive`,
|
|
22
|
+
which run the suite anyway and so gain nothing from avoiding evaluation.
|
|
23
|
+
This makes "a registry is a literal" a design contract rather than a
|
|
24
|
+
limitation: `params: { maxMb: MAX_MB }` imported from application code
|
|
25
|
+
already violates the single-source rule the framework exists to enforce,
|
|
26
|
+
since the value's real owner is elsewhere. It would also turn `render`'s
|
|
27
|
+
purity from a convention into something structurally guaranteed — today a
|
|
28
|
+
`Date.now()` in a registry makes `--check` fail forever.
|
|
29
|
+
*What blocks it:* a non-literal registry must become an ERROR, never a silent
|
|
30
|
+
fallback to evaluation, or the guarantee is worth nothing — so this is a
|
|
31
|
+
breaking change for repos that compute their registry, and needs an explicit
|
|
32
|
+
opt-out (`--eval`) rather than a warning period, since a warning period
|
|
33
|
+
spends the whole transition still evaluating. The real risk is extractor
|
|
34
|
+
fidelity: `-1` is a unary expression, `1_000` is not `Number(text)`,
|
|
35
|
+
`as const` needs unwrapping, and any of those misread would break a repo the
|
|
36
|
+
change is supposed to leave untouched. Differential testing against the
|
|
37
|
+
current loader over every fixture is the prerequisite.
|
|
38
|
+
- **Two gaps in the intent layer: nothing resists a bloated requirement, and
|
|
39
|
+
nothing resists a duplicated one.** Recorded as a design note, with the
|
|
40
|
+
evidence that currently blocks each candidate fix.
|
|
41
|
+
*Against bloat, what already works:* `uncovered-requirement` being an ERROR is
|
|
42
|
+
the real mechanism — every requirement costs an executable scenario, so "the
|
|
43
|
+
system should be maintainable" cannot be written and left standing. That is a
|
|
44
|
+
genuine cost function on the intent layer, which prose SDD does not have.
|
|
45
|
+
*What doesn't:* coverage is binary (≥1 scenario), so five sharp requirements
|
|
46
|
+
cost five mandatory scenarios while one requirement lumping five obligations
|
|
47
|
+
together costs one. **The rule as designed rewards lumping**, and the engine
|
|
48
|
+
has no notion of "one requirement = one obligation". Attest's own registry
|
|
49
|
+
shows it: `ATX-5` carries two obligations under one SHALL, `ATX-9` three
|
|
50
|
+
clauses, `ATX-10` two.
|
|
51
|
+
*Against duplication and contradiction:* effectively nothing. Every
|
|
52
|
+
cross-requirement check in the engine is keyed on the **id** —
|
|
53
|
+
`duplicate-requirement` (same id in two registry files), `rename-target-exists`,
|
|
54
|
+
and `add-conflict`, which content-compares only when ids collide. Two
|
|
55
|
+
requirements under different ids that contradict each other (`AUTH-3` expires a
|
|
56
|
+
session after 30 minutes, `SESS-7` says sessions never expire) pass schema,
|
|
57
|
+
`check`, `verify` and the archive gate, each green under its own scenario.
|
|
58
|
+
`params` does not help, and the reason is structural: it is an
|
|
59
|
+
**intra-requirement** mechanism. It pins one requirement's statement to its own
|
|
60
|
+
assertions; two requirements may each own a `params` entry of the same name with
|
|
61
|
+
different values and both stay green. Design §11 admits semantic drift needs
|
|
62
|
+
human review — semantic *duplication* is the same category and is not mentioned
|
|
63
|
+
at all. This matters most in the workflow the package exists for: an agent asked
|
|
64
|
+
for a new behaviour is additive by default, and will add `SESS-7` rather than
|
|
65
|
+
`modified: { 'AUTH-3': … }`. The delta workflow provides the correct path; it
|
|
66
|
+
does not force it, and the one counter-pressure (a new requirement costs a
|
|
67
|
+
scenario) does not deter an agent that will happily write one.
|
|
68
|
+
*Candidate 1 — `divergent-param` (WARNING):* the same param name declared in
|
|
69
|
+
more than one requirement with different values, scoped to a shared id prefix
|
|
70
|
+
(`AUTH-*` vs `AUTH-*`) to limit collisions between unrelated domains. It would
|
|
71
|
+
not detect abstract contradiction, only its most common concrete form: one named
|
|
72
|
+
constant pinned twice, differently. **Blocked, and by this repo's own registry:**
|
|
73
|
+
`idleTimeoutMin` is `15` in `ATX-3` and `30` in `ATX-10`, both under the same
|
|
74
|
+
prefix, and both legitimate — unrelated illustrative fixtures. So the false
|
|
75
|
+
positive is not hypothetical, and prefix scoping does not save a repo that uses
|
|
76
|
+
one prefix throughout. The mechanism needs a way to declare two params
|
|
77
|
+
independent before it can ship, and that escape hatch is undesigned.
|
|
78
|
+
*Candidate 2 — `compound-requirement` (WARNING):* more than one RFC-2119
|
|
79
|
+
keyword in a single `statement` is objectively more than one obligation, which
|
|
80
|
+
directly opposes the lumping incentive above. Cheap and deterministic, but its
|
|
81
|
+
reach is narrow: over the 12 self requirements it flags exactly one (`ATX-10`,
|
|
82
|
+
`SHALL … and MUST …`) and misses both `ATX-5` and `ATX-9`, which pack multiple
|
|
83
|
+
clauses under a single keyword.
|
|
84
|
+
*Explicitly rejected:* similarity matching between statements (token overlap,
|
|
85
|
+
embeddings). That reintroduces the fuzzy AI comparison design §0 exists to
|
|
86
|
+
remove. Real semantic duplication needs judgement and belongs to human review
|
|
87
|
+
at the propose stage; the engine should not pretend to prove it.
|
|
88
|
+
Both candidates are WARNING-level, so neither would change the exit code of an
|
|
89
|
+
existing valid setup (only ERROR fails a run) — they are listed here rather than
|
|
90
|
+
under 0.2.0 for that reason.
|
|
91
|
+
|
|
10
92
|
The breaking items below are held for **0.2.0** (under 0.x SemVer a breaking
|
|
11
93
|
change bumps the minor). "Breaking" means it changes the exit code of an existing
|
|
12
94
|
valid setup, rejects previously-valid input, removes/renames a public API or
|
|
@@ -36,6 +118,167 @@ relies on — diagnostic message text is not API.
|
|
|
36
118
|
land earlier in 0.1.x):* a pre-run report of how many spec files were located
|
|
37
119
|
and how many contain a `requirement()` call.
|
|
38
120
|
|
|
121
|
+
## [0.1.7] - 2026-07-26
|
|
122
|
+
|
|
123
|
+
A change name, a prototype key and a collation quirk each got to decide a
|
|
124
|
+
verdict; none of them do now.
|
|
125
|
+
|
|
126
|
+
### Security
|
|
127
|
+
|
|
128
|
+
- **`attest archive <change>` validated the change name only by using it.** The
|
|
129
|
+
name was interpolated straight into
|
|
130
|
+
`changes/<name>/requirements.delta.ts`, and that module is *executed* — while
|
|
131
|
+
path joining normalises `..`, so `attest archive '../../../tmp/evil'` loaded
|
|
132
|
+
and ran a module from outside `changes/` entirely. Harmless when you type it
|
|
133
|
+
yourself; not harmless the moment the name comes from a branch name or an MR
|
|
134
|
+
title, which is the natural way to wire the gate into CI. The name is now
|
|
135
|
+
checked **before a loader is even created** — a name already known to be
|
|
136
|
+
invalid must not cause a single resolution attempt — and rejected with a new
|
|
137
|
+
`invalid-change-name` ERROR.
|
|
138
|
+
The test is path safety, not a character whitelist: empty, `.`, `..`, or
|
|
139
|
+
anything containing a path separator or NUL is refused, and every other name a
|
|
140
|
+
directory may legitimately carry is admitted. A whitelist would have cost
|
|
141
|
+
adopters real change directories (`feat(auth)`, a name with a space) to buy no
|
|
142
|
+
additional safety, because the change name never reaches a glob.
|
|
143
|
+
- **A sibling proposal with a glob metacharacter in its name silently widened
|
|
144
|
+
the archive gate.** The globs that keep *other* proposals out of a gate run
|
|
145
|
+
were built by pasting directory names read from disk straight into
|
|
146
|
+
`**/changes/<name>/**`. A change called `feat(auth)` is a *pattern*, so it
|
|
147
|
+
matched nothing, and that proposal's specs joined the run — quietly enlarging
|
|
148
|
+
the scope of the single check that decides whether a change is done. Sibling
|
|
149
|
+
names are now escaped.
|
|
150
|
+
|
|
151
|
+
### Fixed
|
|
152
|
+
|
|
153
|
+
- **A statement placeholder could bind to a prototype method instead of a
|
|
154
|
+
param.** Both the validator and the renderer probed with `name in req.params`,
|
|
155
|
+
and `'toString' in {}` is `true`. So `{toString}` in a statement looked bound:
|
|
156
|
+
the `unbound-param` ERROR that exists to stop an undeclared placeholder never
|
|
157
|
+
fired, and `render` then interpolated
|
|
158
|
+
`function toString() { [native code] }` into the document that reviewers and
|
|
159
|
+
audit read as the system's promise. Both now use `Object.hasOwn`, so the
|
|
160
|
+
intent layer resolves only to what an author actually wrote. An own param
|
|
161
|
+
whose name happens to shadow a prototype key keeps working.
|
|
162
|
+
*Behaviour change:* a registry with such a statement newly fails `check`, and
|
|
163
|
+
its rendering changes (the placeholder is now left verbatim), which
|
|
164
|
+
`render --check` reports as stale. Both are the reports that should always
|
|
165
|
+
have been there.
|
|
166
|
+
- **The canonical form used for content comparison encoded the order params
|
|
167
|
+
happened to be written in.** `applyDelta` sorted param keys with
|
|
168
|
+
`localeCompare` before comparing, and `localeCompare` returns `0` for strings
|
|
169
|
+
that are *distinct* — a precomposed `ä` against its combining-mark spelling.
|
|
170
|
+
`Array#sort` is stable, so keys it called equal kept their insertion order,
|
|
171
|
+
and two requirements with identical content but differently ordered params
|
|
172
|
+
canonicalised differently: `add-conflict` reporting a requirement as
|
|
173
|
+
conflicting with an identical copy of itself. Which strings collate equal is
|
|
174
|
+
ICU-dependent on top of that, so the answer also varied with the Node build.
|
|
175
|
+
Ordering now goes through one shared code-unit comparator (`src/core/order.ts`),
|
|
176
|
+
which `render`'s id ordering — already code-unit for the same reason — now
|
|
177
|
+
shares.
|
|
178
|
+
- **The loader never removed its scratch directory.** Every `attest`
|
|
179
|
+
invocation created one under the OS temp dir to hold the vitest stub, and
|
|
180
|
+
`close()` shut the Vite server without deleting it: one directory per CI
|
|
181
|
+
build, accumulating forever. `close()` now removes it, and is idempotent.
|
|
182
|
+
|
|
183
|
+
### Changed
|
|
184
|
+
|
|
185
|
+
- **`check` walked the project tree twice and `archive` four times**, over a
|
|
186
|
+
tree that cannot change in between. One traversal now collects registry and
|
|
187
|
+
spec files together (`scanProject`). Directory recursion, spec reads, and
|
|
188
|
+
registry module evaluation all run concurrently; results are folded in sorted
|
|
189
|
+
file order, so reports stay byte-identical regardless of I/O timing. The
|
|
190
|
+
drift heuristic indexes scenarios once instead of re-filtering the whole plan
|
|
191
|
+
per requirement, which was the product that grows fastest in exactly the repos
|
|
192
|
+
where `check` needs to stay fast.
|
|
193
|
+
- **`verify` and `archive` now share one `declared-not-run` implementation.**
|
|
194
|
+
Each owned a verbatim copy, so the two verdicts agreed only by transcription —
|
|
195
|
+
in a tool whose entire argument is that agreement should be structural rather
|
|
196
|
+
than clerical.
|
|
197
|
+
- `attest <cmd> [dir]` now resolves `[dir]` to an absolute path. A relative one
|
|
198
|
+
previously worked only because Vite happens to default its own root to the
|
|
199
|
+
current directory.
|
|
200
|
+
- `render --out` writes through a temporary file and renames, so an interrupted
|
|
201
|
+
write can no longer leave a truncated document in a file that is meant to be
|
|
202
|
+
committed.
|
|
203
|
+
|
|
204
|
+
No `schemaVersion` change: the report envelope and the `Issue` shape are
|
|
205
|
+
untouched, and `invalid-change-name` is a new `code` value, which is additive.
|
|
206
|
+
|
|
207
|
+
## [0.1.6] - 2026-07-25
|
|
208
|
+
|
|
209
|
+
A readable spec for the people who cannot read the registry, plus the form
|
|
210
|
+
that turns each adoption into comparable evidence.
|
|
211
|
+
|
|
212
|
+
### Added
|
|
213
|
+
|
|
214
|
+
- **`attest render` — the requirements as Markdown, for people who don't read
|
|
215
|
+
TypeScript.** The intent layer was readable only by opening `*.reqs.ts`: the
|
|
216
|
+
`--json` surface carries issues and coverage rows, never `statement` /
|
|
217
|
+
`rationale` / `params` / `outOfScope`, so a reviewer, a QA engineer, or an
|
|
218
|
+
audit had no way in that did not go through the compiler. `render` projects the
|
|
219
|
+
registry into one document — an index of every requirement, then each one with
|
|
220
|
+
its statement, rationale, params table and out-of-scope notes. It
|
|
221
|
+
**substitutes params into the statement**, so the document reads "after **30**
|
|
222
|
+
minutes" where the source says `{idleTimeoutMin}`; an unbound placeholder is
|
|
223
|
+
left verbatim rather than hiding the `unbound-param` error `check` reports.
|
|
224
|
+
The document carries **intent only** — no coverage, no counts, no test
|
|
225
|
+
locations, no pass/fail. Those are verdicts, and `cover` / `verify` recompute
|
|
226
|
+
them on demand; a committed document that carried them was rewritten by any
|
|
227
|
+
edit that shifted a line in a spec file (one unrelated comment moved four
|
|
228
|
+
lines and turned CI red), and in a green repo the coverage was constant anyway,
|
|
229
|
+
since an uncovered requirement is already a `check` ERROR. So the rendering is
|
|
230
|
+
a pure function of the `*.reqs.ts` files: it changes if and only if intent
|
|
231
|
+
changes, which is what keeps the freshness gate below a signal rather than a
|
|
232
|
+
chore. It also means no parse and no test run — rendering is fast and offline.
|
|
233
|
+
Two things keep this from re-opening the door Attest closed. It is **one-way** —
|
|
234
|
+
Markdown is an output, nothing reads it back (design §0 now says so
|
|
235
|
+
explicitly) — and it is **gated**: a generated file you commit is a new place
|
|
236
|
+
for drift to hide, so `--out <file> --check` regenerates and compares
|
|
237
|
+
byte-for-byte, failing with a `stale-spec-doc` ERROR when the committed
|
|
238
|
+
document no longer matches the registry and `missing-spec-doc` when it was
|
|
239
|
+
never generated — two codes rather than one, because `message` is prose and
|
|
240
|
+
not API, so a shared code would leave a consumer nothing but the wording to
|
|
241
|
+
tell an incomplete setup from a document that started lying. Rendering
|
|
242
|
+
therefore takes no formatting options at all, not even a title: every knob is
|
|
243
|
+
a way for `--check` to be wrong about staleness. Attest dogfoods it —
|
|
244
|
+
`self/requirements/SPEC.md` is generated next to the registry it projects, and
|
|
245
|
+
the `dogfood` CI job fails if it goes stale.
|
|
246
|
+
`--json` gains `render` as a `command` value and an `outFile` field, and never
|
|
247
|
+
the document itself; because `render`'s own stdout is the document, `--json`
|
|
248
|
+
there requires `--out` or `--check` so stdout still carries exactly one thing.
|
|
249
|
+
No `schemaVersion` change (a new command value, and a new optional field, are
|
|
250
|
+
additive).
|
|
251
|
+
*Two contracts, deliberately different.* The Markdown is prose for humans and
|
|
252
|
+
is **not** a parsing contract — never grep or parse it, `--json` remains the
|
|
253
|
+
machine surface. But shipping `--check` does make the rendering's bytes an
|
|
254
|
+
**upgrade** contract: any later change to the format — a new field, a
|
|
255
|
+
reordering, a reworded banner — turns every committed rendering stale and every
|
|
256
|
+
`--check` job red, on an upgrade where the user changed no intent at all. Such
|
|
257
|
+
a change is therefore treated as breaking, and will be called out here with the
|
|
258
|
+
remedy, which is always one regeneration — the diagnostic prints the exact
|
|
259
|
+
command. (Putting the attest version in the banner was considered and rejected:
|
|
260
|
+
it would stale every document on every upgrade, whether the format moved or
|
|
261
|
+
not.)
|
|
262
|
+
|
|
263
|
+
- **A repeatable adoption report** — `docs/{en,zh}/feedback.template.md` plus a
|
|
264
|
+
matching **Usage feedback** GitLab issue template. 0.1.4 and 0.1.5 both came
|
|
265
|
+
out of adopting Attest into other projects, but that evidence was only ever
|
|
266
|
+
reconstructed from memory after the fact, and only for the adoptions that
|
|
267
|
+
happened to go badly enough to be memorable. The form fixes the axes so one
|
|
268
|
+
adoption can be compared against the next (framework, greenfield vs. retrofit,
|
|
269
|
+
pre-existing test count, time to first green) and asks for the two things that
|
|
270
|
+
decide whether a lint-shaped tool survives in a real repo: friction ordered by
|
|
271
|
+
time lost, and signal quality — false positives by `code`, and false negatives,
|
|
272
|
+
drift the engine should have caught and didn't. It ends with a prompt to run
|
|
273
|
+
inside the adopting repo that fills the mechanical parts (versions, counts,
|
|
274
|
+
`--json` output, params changes in git history) and then actively probes for
|
|
275
|
+
latent problems rather than summarising known ones — a root-level run against a
|
|
276
|
+
pre-existing suite, a vacuous green, spec literals that duplicate a `params`
|
|
277
|
+
value, params changes that passed silently. Reports live on the issue tracker
|
|
278
|
+
and are triaged into issues or `Unreleased`; they are deliberately not kept in
|
|
279
|
+
this tree. Docs and repo metadata only — no package surface, no `schemaVersion`
|
|
280
|
+
change, and nothing added to the published `files` allowlist.
|
|
281
|
+
|
|
39
282
|
## [0.1.5] - 2026-07-24
|
|
40
283
|
|
|
41
284
|
A follow-up to the 0.1.4 adoption fixes, closing the framework-repo gap.
|
|
@@ -195,7 +438,9 @@ Initial release.
|
|
|
195
438
|
(MIT), whose four-stage engine and diff-first change model Attest's
|
|
196
439
|
architecture is adapted from (re-implemented from scratch, no source copied).
|
|
197
440
|
|
|
198
|
-
[Unreleased]: https://gitlab.com/Pseudorca/attest/-/compare/v0.1.
|
|
441
|
+
[Unreleased]: https://gitlab.com/Pseudorca/attest/-/compare/v0.1.7...main
|
|
442
|
+
[0.1.7]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.7
|
|
443
|
+
[0.1.6]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.6
|
|
199
444
|
[0.1.5]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.5
|
|
200
445
|
[0.1.4]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.4
|
|
201
446
|
[0.1.3]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.3
|
package/README.md
CHANGED
|
@@ -69,9 +69,51 @@ requirement('AUTH-3', () => {
|
|
|
69
69
|
attest check # static: orphan tests, uncovered requirements, unbound params
|
|
70
70
|
attest verify # run tests + coverage + drift, graded report
|
|
71
71
|
attest cover # which requirements lack a scenario
|
|
72
|
+
attest render # the requirements as Markdown, for people who don't read TS
|
|
72
73
|
attest archive <change> # gate a proposed change: green + covered + no drift
|
|
73
74
|
```
|
|
74
75
|
|
|
76
|
+
`<change>` names one directory inside `changes/` — it cannot be empty, `.`,
|
|
77
|
+
`..`, or contain a path separator, since the gate loads and runs that change's
|
|
78
|
+
delta. Any other directory name is fine.
|
|
79
|
+
|
|
80
|
+
### A readable spec for humans (`attest render`)
|
|
81
|
+
|
|
82
|
+
The intent layer lives in TypeScript, which means a reviewer, a QA engineer, or
|
|
83
|
+
anyone doing an audit cannot read it. `render` projects the registry into one
|
|
84
|
+
Markdown document — an index of every requirement, then each one with its
|
|
85
|
+
statement, rationale, params and out-of-scope notes:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
attest render # to stdout
|
|
89
|
+
attest render --out docs/SPEC.md # to a file
|
|
90
|
+
attest render --out docs/SPEC.md --check # fail if that file is out of date
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The rendering **substitutes params into the statement**, so the document says
|
|
94
|
+
"after **30** minutes" where the source says `{idleTimeoutMin}` — the number a
|
|
95
|
+
reader actually wants, still from the single source.
|
|
96
|
+
|
|
97
|
+
Three properties this deliberately keeps:
|
|
98
|
+
|
|
99
|
+
- **One-way.** Markdown is only ever an output. Nothing reads it back, so the
|
|
100
|
+
free-form-prose drift that a Markdown *source* invites stays out.
|
|
101
|
+
- **Intent only.** No coverage, no counts, no test locations, no pass/fail —
|
|
102
|
+
those are verdicts, and `cover` / `verify` recompute them on demand. So the
|
|
103
|
+
document is a pure function of your `*.reqs.ts` files and changes if and only
|
|
104
|
+
if intent changes: one readable hunk per registry edit, and never a rewrite
|
|
105
|
+
because a line moved in a test file.
|
|
106
|
+
- **Gated.** A generated file you commit is a new place for drift to hide, so
|
|
107
|
+
`--check` regenerates and compares byte-for-byte, failing with
|
|
108
|
+
`stale-spec-doc` if the committed document no longer matches the registry, or
|
|
109
|
+
`missing-spec-doc` if it was never generated.
|
|
110
|
+
Put it in CI next to `attest check`. (Attest does this to itself:
|
|
111
|
+
[`self/requirements/SPEC.md`](https://gitlab.com/Pseudorca/attest/-/blob/main/self/requirements/SPEC.md)
|
|
112
|
+
is generated, and the pipeline fails if it goes stale.)
|
|
113
|
+
|
|
114
|
+
The Markdown is prose for humans and its formatting is not a stable contract —
|
|
115
|
+
don't parse it. `--json` is the machine surface.
|
|
116
|
+
|
|
75
117
|
### Framework code (`.vue`, DOM, path aliases)
|
|
76
118
|
|
|
77
119
|
The child run isolates from any ambient config by default, so specs run in a bare
|
|
@@ -92,6 +134,8 @@ flag the run stays isolated and deterministic.
|
|
|
92
134
|
Every command takes `--json` and then writes exactly one JSON document to
|
|
93
135
|
stdout — same work, same exit code. Branch on `ok`, `issues[].code` and
|
|
94
136
|
`issues[].reqId`; never parse `message`, which is prose and may be reworded.
|
|
137
|
+
(`render` is the one exception, because its own output is a document: there,
|
|
138
|
+
`--json` needs `--out` or `--check`, so stdout still carries exactly one thing.)
|
|
95
139
|
|
|
96
140
|
```bash
|
|
97
141
|
attest check --json
|
|
@@ -121,7 +165,8 @@ attest check --json
|
|
|
121
165
|
`verify` adds `passed` (was the test run itself green, independent of the
|
|
122
166
|
overall verdict); `cover` adds `coverage[]` — one `{ reqId, covered,
|
|
123
167
|
scenarioCount }` row per requirement — plus a `requirements` roll-up;
|
|
124
|
-
`archive` adds `change
|
|
168
|
+
`archive` adds `change`; `render` adds `outFile` (and never the document itself).
|
|
169
|
+
`schemaVersion` is bumped on any breaking change to
|
|
125
170
|
the shape. The TypeScript type is exported as `JsonReport`.
|
|
126
171
|
|
|
127
172
|
Even when a command crashes, `--json` still writes one parseable envelope
|
|
@@ -156,6 +201,16 @@ launcher, peer resolution from a foreign `node_modules` — so it is what catche
|
|
|
156
201
|
"green in-repo, broken once installed" bugs. It needs network and is excluded
|
|
157
202
|
from `pnpm test`; it runs in CI and as `prepublishOnly`.
|
|
158
203
|
|
|
204
|
+
## Feedback
|
|
205
|
+
|
|
206
|
+
Adoption reports drive the roadmap. After using Attest on a real project, fill in
|
|
207
|
+
the feedback template — [English](https://gitlab.com/Pseudorca/attest/-/blob/main/docs/en/feedback.template.md) · [中文](https://gitlab.com/Pseudorca/attest/-/blob/main/docs/zh/feedback.template.md) —
|
|
208
|
+
and open it as an issue (it is also the **Usage feedback** issue template). It
|
|
209
|
+
covers greenfield and mid-project adoption alike, and ends with a prompt to run
|
|
210
|
+
inside the adopting repo that fills most of the report automatically and probes
|
|
211
|
+
for problems you haven't hit yet. The highest-value part is **false negatives**:
|
|
212
|
+
drift the engine should have caught and didn't.
|
|
213
|
+
|
|
159
214
|
## Acknowledgments
|
|
160
215
|
|
|
161
216
|
Attest's architecture — the four-stage truth engine (AST parse → graded
|
package/dist/cli/index.js
CHANGED
|
@@ -9,10 +9,12 @@
|
|
|
9
9
|
// where the report is an `internal-error` envelope instead of a bare stack.
|
|
10
10
|
import { Command } from 'commander';
|
|
11
11
|
import chalk from 'chalk';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { rename, writeFile } from 'node:fs/promises';
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
|
+
import { runCheck, runVerify, runCover, runArchive, runRender, runRenderCheck, } from '../core/pipeline.js';
|
|
15
|
+
import { hasError } from '../core/types.js';
|
|
14
16
|
import { formatIssues, summarize, formatCoverage } from './report.js';
|
|
15
|
-
import { archiveReport, checkReport, coverReport, errorReport, renderJson, verifyReport, } from './json.js';
|
|
17
|
+
import { archiveReport, checkReport, coverReport, errorReport, renderJson, renderReport, verifyReport, } from './json.js';
|
|
16
18
|
import { packageVersion } from './version.js';
|
|
17
19
|
const VERSION = packageVersion();
|
|
18
20
|
const program = new Command();
|
|
@@ -20,8 +22,11 @@ program
|
|
|
20
22
|
.name('attest')
|
|
21
23
|
.description('TDD-native spec framework: tests attest that requirements hold.')
|
|
22
24
|
.version(VERSION);
|
|
25
|
+
// Always absolute: the project root is joined into module paths handed to the
|
|
26
|
+
// Vite loader and to Vitest's `root`, and a relative one only resolved
|
|
27
|
+
// correctly because Vite happens to default its own root to cwd.
|
|
23
28
|
function root(dir) {
|
|
24
|
-
return dir ? dir : process.cwd();
|
|
29
|
+
return dir ? resolve(process.cwd(), dir) : process.cwd();
|
|
25
30
|
}
|
|
26
31
|
const JSON_FLAG = '--json';
|
|
27
32
|
const JSON_HELP = 'emit one machine-readable JSON report on stdout';
|
|
@@ -31,6 +36,20 @@ const VITEST_CONFIG_HELP = 'load this Vitest config in the child run (transforms
|
|
|
31
36
|
function vitestConfig(opts) {
|
|
32
37
|
return opts.vitestConfig ? resolve(process.cwd(), opts.vitestConfig) : undefined;
|
|
33
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Write via a temporary file in the same directory, then rename.
|
|
41
|
+
*
|
|
42
|
+
* The rendering is a *committed* file guarded by `--check`. A plain write that
|
|
43
|
+
* is interrupted leaves a truncated document on disk — which `--check` would
|
|
44
|
+
* then correctly call stale, but only after someone commits the wreckage.
|
|
45
|
+
* `rename` within a directory is atomic, so the file is either the old one or
|
|
46
|
+
* the new one, never half of either.
|
|
47
|
+
*/
|
|
48
|
+
async function writeAtomic(dest, content) {
|
|
49
|
+
const tmp = join(dirname(dest), `.${VERSION}.${process.pid}.attest.tmp`);
|
|
50
|
+
await writeFile(tmp, content, 'utf8');
|
|
51
|
+
await rename(tmp, dest);
|
|
52
|
+
}
|
|
34
53
|
/**
|
|
35
54
|
* Run one command's work with a single output + exit-code contract:
|
|
36
55
|
* - success: print the JSON report (`--json`) or the human rendering, and set
|
|
@@ -104,6 +123,64 @@ program
|
|
|
104
123
|
},
|
|
105
124
|
};
|
|
106
125
|
}));
|
|
126
|
+
program
|
|
127
|
+
.command('render')
|
|
128
|
+
.description('Render the requirements as a Markdown document for human readers.')
|
|
129
|
+
.argument('[dir]', 'project root', undefined)
|
|
130
|
+
.option('--out <file>', 'write the document to this file instead of stdout')
|
|
131
|
+
.option('--check', 'fail if --out is missing or no longer matches the registry')
|
|
132
|
+
.option(JSON_FLAG, JSON_HELP)
|
|
133
|
+
.action((dir, opts, cmd) => {
|
|
134
|
+
// stdout carries exactly one document, so the Markdown and a --json report
|
|
135
|
+
// can never both go there. Usage errors are outside the --json contract
|
|
136
|
+
// (like arg parsing) and are reported as usage errors, not as reports.
|
|
137
|
+
if (opts.check && !opts.out)
|
|
138
|
+
cmd.error('error: --check requires --out <file>');
|
|
139
|
+
if (opts.json && !opts.out && !opts.check) {
|
|
140
|
+
cmd.error('error: --json requires --out <file> (stdout cannot carry both the document and the report)');
|
|
141
|
+
}
|
|
142
|
+
const dest = opts.out ? resolve(process.cwd(), opts.out) : undefined;
|
|
143
|
+
return runAction('render', opts, async () => {
|
|
144
|
+
if (opts.check) {
|
|
145
|
+
// The fix hint has to be the command the user can actually re-run from
|
|
146
|
+
// here: their own --out string, and the [dir] they passed.
|
|
147
|
+
const issues = await runRenderCheck(root(dir), dest, {
|
|
148
|
+
display: opts.out,
|
|
149
|
+
command: `attest render${dir ? ` ${dir}` : ''} --out ${opts.out}`,
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
report: renderReport(VERSION, issues, opts.out),
|
|
153
|
+
human: () => {
|
|
154
|
+
if (issues.length === 0)
|
|
155
|
+
console.log(chalk.green(`✓ ${opts.out} is up to date.`));
|
|
156
|
+
else {
|
|
157
|
+
console.log(formatIssues(issues));
|
|
158
|
+
console.log(summarize(issues));
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const { markdown, issues } = await runRender(root(dir));
|
|
164
|
+
// Never overwrite a good document with the output of a broken registry.
|
|
165
|
+
if (!hasError(issues) && dest)
|
|
166
|
+
await writeAtomic(dest, markdown);
|
|
167
|
+
return {
|
|
168
|
+
report: renderReport(VERSION, issues, opts.out),
|
|
169
|
+
human: () => {
|
|
170
|
+
if (hasError(issues)) {
|
|
171
|
+
console.log(formatIssues(issues));
|
|
172
|
+
console.log(summarize(issues));
|
|
173
|
+
}
|
|
174
|
+
else if (dest) {
|
|
175
|
+
console.log(chalk.green(`✓ Wrote ${opts.out}`));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
process.stdout.write(markdown);
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
});
|
|
107
184
|
program
|
|
108
185
|
.command('archive')
|
|
109
186
|
.argument('<change>', 'change name to archive')
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+EAA+E;AAC/E,sCAAsC;AACtC,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,4EAA4E;AAE5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/json.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { CoverageRow } from '../core/pipeline.js';
|
|
|
2
2
|
import type { Issue } from '../core/types.js';
|
|
3
3
|
/** Bumped whenever the emitted shape changes incompatibly. */
|
|
4
4
|
export declare const SCHEMA_VERSION = 1;
|
|
5
|
-
export type JsonCommand = 'check' | 'verify' | 'cover' | 'archive';
|
|
5
|
+
export type JsonCommand = 'check' | 'verify' | 'cover' | 'archive' | 'render';
|
|
6
6
|
export interface JsonSummary {
|
|
7
7
|
error: number;
|
|
8
8
|
warning: number;
|
|
@@ -30,11 +30,18 @@ export interface JsonReport {
|
|
|
30
30
|
};
|
|
31
31
|
/** `archive` only: the change being gated. */
|
|
32
32
|
change?: string;
|
|
33
|
+
/** `render` only: the file the document was written to, when `--out` was given. */
|
|
34
|
+
outFile?: string;
|
|
33
35
|
}
|
|
34
36
|
export declare function countLevels(issues: Issue[]): JsonSummary;
|
|
35
37
|
export declare function checkReport(version: string, issues: Issue[]): JsonReport;
|
|
36
38
|
export declare function verifyReport(version: string, issues: Issue[], passed: boolean, ok: boolean): JsonReport;
|
|
37
39
|
export declare function coverReport(version: string, rows: CoverageRow[]): JsonReport;
|
|
40
|
+
/**
|
|
41
|
+
* `render` only. The Markdown document itself is never part of the envelope:
|
|
42
|
+
* it is prose for humans, and the machine surface stays `ok` + issue codes.
|
|
43
|
+
*/
|
|
44
|
+
export declare function renderReport(version: string, issues: Issue[], outFile?: string): JsonReport;
|
|
38
45
|
export declare function archiveReport(version: string, change: string, blocking: Issue[]): JsonReport;
|
|
39
46
|
/**
|
|
40
47
|
* The envelope for a command that threw before it could produce a report. Keeps
|
package/dist/cli/json.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/cli/json.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,kBAAkB,CAAC;AAErD,8DAA8D;AAC9D,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/cli/json.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,kBAAkB,CAAC;AAErD,8DAA8D;AAC9D,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9E,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,uEAAuE;IACvE,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,kDAAkD;IAClD,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW,CAIxD;AAqBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAExE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,KAAK,EAAE,EACf,MAAM,EAAE,OAAO,EACf,EAAE,EAAE,OAAO,GACV,UAAU,CAEZ;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,UAAU,CAW5E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,CAAC,EAAE,MAAM,GACf,UAAU,CAGZ;AAED,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,KAAK,EAAE,GAChB,UAAU,CAUZ;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,OAAO,GACX,UAAU,CAIZ;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD"}
|
package/dist/cli/json.js
CHANGED
|
@@ -48,6 +48,14 @@ export function coverReport(version, rows) {
|
|
|
48
48
|
},
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* `render` only. The Markdown document itself is never part of the envelope:
|
|
53
|
+
* it is prose for humans, and the machine surface stays `ok` + issue codes.
|
|
54
|
+
*/
|
|
55
|
+
export function renderReport(version, issues, outFile) {
|
|
56
|
+
const report = envelope({ version, command: 'render', ok: !hasError(issues), issues });
|
|
57
|
+
return outFile === undefined ? report : { ...report, outFile };
|
|
58
|
+
}
|
|
51
59
|
export function archiveReport(version, change, blocking) {
|
|
52
60
|
return {
|
|
53
61
|
...envelope({
|
package/dist/cli/json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/cli/json.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AACzE,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,wCAAwC;AAGxC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/cli/json.ts"],"names":[],"mappings":"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"}
|
package/dist/core/apply.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAe,MAAM,YAAY,CAAC;AAE/D,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,aAAa,GAAG,WAAW,CAiExE"}
|
package/dist/core/apply.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Map<id, Requirement>, with content-compare on ADDED and already-synced
|
|
4
4
|
// no-ops on RENAMED.
|
|
5
5
|
import { RequirementSchema } from './schema.js';
|
|
6
|
+
import { byCodeUnit } from './order.js';
|
|
6
7
|
/**
|
|
7
8
|
* Apply a change delta to a base registry, returning the merged registry plus
|
|
8
9
|
* any apply-level issues (conflicts, missing targets, invalid results). The
|
|
@@ -88,7 +89,12 @@ function canonical(req) {
|
|
|
88
89
|
outOfScope: [...req.outOfScope],
|
|
89
90
|
});
|
|
90
91
|
}
|
|
92
|
+
// Code-unit order, not localeCompare: this string is a *verdict input*.
|
|
93
|
+
// localeCompare calls some distinct keys equal, and a stable sort then leaves
|
|
94
|
+
// them in insertion order — so the canonical form would encode how the params
|
|
95
|
+
// happened to be written, and `add-conflict` would report a requirement as
|
|
96
|
+
// conflicting with an identical copy of itself.
|
|
91
97
|
function sortKeys(obj) {
|
|
92
|
-
return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a
|
|
98
|
+
return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => byCodeUnit(a, b)));
|
|
93
99
|
}
|
|
94
100
|
//# sourceMappingURL=apply.js.map
|
package/dist/core/apply.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,yEAAyE;AACzE,yEAAyE;AACzE,qBAAqB;AAErB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/core/apply.ts"],"names":[],"mappings":"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"}
|
package/dist/core/gate.d.ts
CHANGED
|
@@ -18,5 +18,14 @@ export interface GateInputs {
|
|
|
18
18
|
* 3. Static coverage vs runtime coverage: every declared scenario actually
|
|
19
19
|
* ran (catches skip/only false coverage).
|
|
20
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* Declared-not-run: a scenario the static plan claims attests a requirement,
|
|
23
|
+
* which the runtime never executed (skipped, or excluded by an `.only`).
|
|
24
|
+
*
|
|
25
|
+
* Exported because `verify` and `archive` both make this call. While each owned
|
|
26
|
+
* a copy, the two verdicts agreed only by transcription — and the whole point of
|
|
27
|
+
* this framework is that agreement should be structural, not clerical.
|
|
28
|
+
*/
|
|
29
|
+
export declare function declaredNotRunIssues(plan: AttestPlan, run: RunResult): Issue[];
|
|
21
30
|
export declare function evaluateGate({ registry, plan, run }: GateInputs): Issue[];
|
|
22
31
|
//# sourceMappingURL=gate.d.ts.map
|