@am_shork/attest 0.1.5 → 0.1.6
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 +133 -1
- package/README.md +52 -1
- package/dist/cli/index.js +62 -2
- 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/pipeline.d.ts +24 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +39 -0
- 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 +164 -0
- package/dist/core/render.js.map +1 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,62 @@ 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
|
+
- **Two gaps in the intent layer: nothing resists a bloated requirement, and
|
|
13
|
+
nothing resists a duplicated one.** Recorded as a design note, with the
|
|
14
|
+
evidence that currently blocks each candidate fix.
|
|
15
|
+
*Against bloat, what already works:* `uncovered-requirement` being an ERROR is
|
|
16
|
+
the real mechanism — every requirement costs an executable scenario, so "the
|
|
17
|
+
system should be maintainable" cannot be written and left standing. That is a
|
|
18
|
+
genuine cost function on the intent layer, which prose SDD does not have.
|
|
19
|
+
*What doesn't:* coverage is binary (≥1 scenario), so five sharp requirements
|
|
20
|
+
cost five mandatory scenarios while one requirement lumping five obligations
|
|
21
|
+
together costs one. **The rule as designed rewards lumping**, and the engine
|
|
22
|
+
has no notion of "one requirement = one obligation". Attest's own registry
|
|
23
|
+
shows it: `ATX-5` carries two obligations under one SHALL, `ATX-9` three
|
|
24
|
+
clauses, `ATX-10` two.
|
|
25
|
+
*Against duplication and contradiction:* effectively nothing. Every
|
|
26
|
+
cross-requirement check in the engine is keyed on the **id** —
|
|
27
|
+
`duplicate-requirement` (same id in two registry files), `rename-target-exists`,
|
|
28
|
+
and `add-conflict`, which content-compares only when ids collide. Two
|
|
29
|
+
requirements under different ids that contradict each other (`AUTH-3` expires a
|
|
30
|
+
session after 30 minutes, `SESS-7` says sessions never expire) pass schema,
|
|
31
|
+
`check`, `verify` and the archive gate, each green under its own scenario.
|
|
32
|
+
`params` does not help, and the reason is structural: it is an
|
|
33
|
+
**intra-requirement** mechanism. It pins one requirement's statement to its own
|
|
34
|
+
assertions; two requirements may each own a `params` entry of the same name with
|
|
35
|
+
different values and both stay green. Design §11 admits semantic drift needs
|
|
36
|
+
human review — semantic *duplication* is the same category and is not mentioned
|
|
37
|
+
at all. This matters most in the workflow the package exists for: an agent asked
|
|
38
|
+
for a new behaviour is additive by default, and will add `SESS-7` rather than
|
|
39
|
+
`modified: { 'AUTH-3': … }`. The delta workflow provides the correct path; it
|
|
40
|
+
does not force it, and the one counter-pressure (a new requirement costs a
|
|
41
|
+
scenario) does not deter an agent that will happily write one.
|
|
42
|
+
*Candidate 1 — `divergent-param` (WARNING):* the same param name declared in
|
|
43
|
+
more than one requirement with different values, scoped to a shared id prefix
|
|
44
|
+
(`AUTH-*` vs `AUTH-*`) to limit collisions between unrelated domains. It would
|
|
45
|
+
not detect abstract contradiction, only its most common concrete form: one named
|
|
46
|
+
constant pinned twice, differently. **Blocked, and by this repo's own registry:**
|
|
47
|
+
`idleTimeoutMin` is `15` in `ATX-3` and `30` in `ATX-10`, both under the same
|
|
48
|
+
prefix, and both legitimate — unrelated illustrative fixtures. So the false
|
|
49
|
+
positive is not hypothetical, and prefix scoping does not save a repo that uses
|
|
50
|
+
one prefix throughout. The mechanism needs a way to declare two params
|
|
51
|
+
independent before it can ship, and that escape hatch is undesigned.
|
|
52
|
+
*Candidate 2 — `compound-requirement` (WARNING):* more than one RFC-2119
|
|
53
|
+
keyword in a single `statement` is objectively more than one obligation, which
|
|
54
|
+
directly opposes the lumping incentive above. Cheap and deterministic, but its
|
|
55
|
+
reach is narrow: over the 12 self requirements it flags exactly one (`ATX-10`,
|
|
56
|
+
`SHALL … and MUST …`) and misses both `ATX-5` and `ATX-9`, which pack multiple
|
|
57
|
+
clauses under a single keyword.
|
|
58
|
+
*Explicitly rejected:* similarity matching between statements (token overlap,
|
|
59
|
+
embeddings). That reintroduces the fuzzy AI comparison design §0 exists to
|
|
60
|
+
remove. Real semantic duplication needs judgement and belongs to human review
|
|
61
|
+
at the propose stage; the engine should not pretend to prove it.
|
|
62
|
+
Both candidates are WARNING-level, so neither would change the exit code of an
|
|
63
|
+
existing valid setup (only ERROR fails a run) — they are listed here rather than
|
|
64
|
+
under 0.2.0 for that reason.
|
|
65
|
+
|
|
10
66
|
The breaking items below are held for **0.2.0** (under 0.x SemVer a breaking
|
|
11
67
|
change bumps the minor). "Breaking" means it changes the exit code of an existing
|
|
12
68
|
valid setup, rejects previously-valid input, removes/renames a public API or
|
|
@@ -36,6 +92,81 @@ relies on — diagnostic message text is not API.
|
|
|
36
92
|
land earlier in 0.1.x):* a pre-run report of how many spec files were located
|
|
37
93
|
and how many contain a `requirement()` call.
|
|
38
94
|
|
|
95
|
+
## [0.1.6] - 2026-07-25
|
|
96
|
+
|
|
97
|
+
A readable spec for the people who cannot read the registry, plus the form
|
|
98
|
+
that turns each adoption into comparable evidence.
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
|
|
102
|
+
- **`attest render` — the requirements as Markdown, for people who don't read
|
|
103
|
+
TypeScript.** The intent layer was readable only by opening `*.reqs.ts`: the
|
|
104
|
+
`--json` surface carries issues and coverage rows, never `statement` /
|
|
105
|
+
`rationale` / `params` / `outOfScope`, so a reviewer, a QA engineer, or an
|
|
106
|
+
audit had no way in that did not go through the compiler. `render` projects the
|
|
107
|
+
registry into one document — an index of every requirement, then each one with
|
|
108
|
+
its statement, rationale, params table and out-of-scope notes. It
|
|
109
|
+
**substitutes params into the statement**, so the document reads "after **30**
|
|
110
|
+
minutes" where the source says `{idleTimeoutMin}`; an unbound placeholder is
|
|
111
|
+
left verbatim rather than hiding the `unbound-param` error `check` reports.
|
|
112
|
+
The document carries **intent only** — no coverage, no counts, no test
|
|
113
|
+
locations, no pass/fail. Those are verdicts, and `cover` / `verify` recompute
|
|
114
|
+
them on demand; a committed document that carried them was rewritten by any
|
|
115
|
+
edit that shifted a line in a spec file (one unrelated comment moved four
|
|
116
|
+
lines and turned CI red), and in a green repo the coverage was constant anyway,
|
|
117
|
+
since an uncovered requirement is already a `check` ERROR. So the rendering is
|
|
118
|
+
a pure function of the `*.reqs.ts` files: it changes if and only if intent
|
|
119
|
+
changes, which is what keeps the freshness gate below a signal rather than a
|
|
120
|
+
chore. It also means no parse and no test run — rendering is fast and offline.
|
|
121
|
+
Two things keep this from re-opening the door Attest closed. It is **one-way** —
|
|
122
|
+
Markdown is an output, nothing reads it back (design §0 now says so
|
|
123
|
+
explicitly) — and it is **gated**: a generated file you commit is a new place
|
|
124
|
+
for drift to hide, so `--out <file> --check` regenerates and compares
|
|
125
|
+
byte-for-byte, failing with a `stale-spec-doc` ERROR when the committed
|
|
126
|
+
document no longer matches the registry and `missing-spec-doc` when it was
|
|
127
|
+
never generated — two codes rather than one, because `message` is prose and
|
|
128
|
+
not API, so a shared code would leave a consumer nothing but the wording to
|
|
129
|
+
tell an incomplete setup from a document that started lying. Rendering
|
|
130
|
+
therefore takes no formatting options at all, not even a title: every knob is
|
|
131
|
+
a way for `--check` to be wrong about staleness. Attest dogfoods it —
|
|
132
|
+
`self/requirements/SPEC.md` is generated next to the registry it projects, and
|
|
133
|
+
the `dogfood` CI job fails if it goes stale.
|
|
134
|
+
`--json` gains `render` as a `command` value and an `outFile` field, and never
|
|
135
|
+
the document itself; because `render`'s own stdout is the document, `--json`
|
|
136
|
+
there requires `--out` or `--check` so stdout still carries exactly one thing.
|
|
137
|
+
No `schemaVersion` change (a new command value, and a new optional field, are
|
|
138
|
+
additive).
|
|
139
|
+
*Two contracts, deliberately different.* The Markdown is prose for humans and
|
|
140
|
+
is **not** a parsing contract — never grep or parse it, `--json` remains the
|
|
141
|
+
machine surface. But shipping `--check` does make the rendering's bytes an
|
|
142
|
+
**upgrade** contract: any later change to the format — a new field, a
|
|
143
|
+
reordering, a reworded banner — turns every committed rendering stale and every
|
|
144
|
+
`--check` job red, on an upgrade where the user changed no intent at all. Such
|
|
145
|
+
a change is therefore treated as breaking, and will be called out here with the
|
|
146
|
+
remedy, which is always one regeneration — the diagnostic prints the exact
|
|
147
|
+
command. (Putting the attest version in the banner was considered and rejected:
|
|
148
|
+
it would stale every document on every upgrade, whether the format moved or
|
|
149
|
+
not.)
|
|
150
|
+
|
|
151
|
+
- **A repeatable adoption report** — `docs/{en,zh}/feedback.template.md` plus a
|
|
152
|
+
matching **Usage feedback** GitLab issue template. 0.1.4 and 0.1.5 both came
|
|
153
|
+
out of adopting Attest into other projects, but that evidence was only ever
|
|
154
|
+
reconstructed from memory after the fact, and only for the adoptions that
|
|
155
|
+
happened to go badly enough to be memorable. The form fixes the axes so one
|
|
156
|
+
adoption can be compared against the next (framework, greenfield vs. retrofit,
|
|
157
|
+
pre-existing test count, time to first green) and asks for the two things that
|
|
158
|
+
decide whether a lint-shaped tool survives in a real repo: friction ordered by
|
|
159
|
+
time lost, and signal quality — false positives by `code`, and false negatives,
|
|
160
|
+
drift the engine should have caught and didn't. It ends with a prompt to run
|
|
161
|
+
inside the adopting repo that fills the mechanical parts (versions, counts,
|
|
162
|
+
`--json` output, params changes in git history) and then actively probes for
|
|
163
|
+
latent problems rather than summarising known ones — a root-level run against a
|
|
164
|
+
pre-existing suite, a vacuous green, spec literals that duplicate a `params`
|
|
165
|
+
value, params changes that passed silently. Reports live on the issue tracker
|
|
166
|
+
and are triaged into issues or `Unreleased`; they are deliberately not kept in
|
|
167
|
+
this tree. Docs and repo metadata only — no package surface, no `schemaVersion`
|
|
168
|
+
change, and nothing added to the published `files` allowlist.
|
|
169
|
+
|
|
39
170
|
## [0.1.5] - 2026-07-24
|
|
40
171
|
|
|
41
172
|
A follow-up to the 0.1.4 adoption fixes, closing the framework-repo gap.
|
|
@@ -195,7 +326,8 @@ Initial release.
|
|
|
195
326
|
(MIT), whose four-stage engine and diff-first change model Attest's
|
|
196
327
|
architecture is adapted from (re-implemented from scratch, no source copied).
|
|
197
328
|
|
|
198
|
-
[Unreleased]: https://gitlab.com/Pseudorca/attest/-/compare/v0.1.
|
|
329
|
+
[Unreleased]: https://gitlab.com/Pseudorca/attest/-/compare/v0.1.6...main
|
|
330
|
+
[0.1.6]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.6
|
|
199
331
|
[0.1.5]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.5
|
|
200
332
|
[0.1.4]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.4
|
|
201
333
|
[0.1.3]: https://gitlab.com/Pseudorca/attest/-/tags/v0.1.3
|
package/README.md
CHANGED
|
@@ -69,9 +69,47 @@ 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
|
+
### A readable spec for humans (`attest render`)
|
|
77
|
+
|
|
78
|
+
The intent layer lives in TypeScript, which means a reviewer, a QA engineer, or
|
|
79
|
+
anyone doing an audit cannot read it. `render` projects the registry into one
|
|
80
|
+
Markdown document — an index of every requirement, then each one with its
|
|
81
|
+
statement, rationale, params and out-of-scope notes:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
attest render # to stdout
|
|
85
|
+
attest render --out docs/SPEC.md # to a file
|
|
86
|
+
attest render --out docs/SPEC.md --check # fail if that file is out of date
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The rendering **substitutes params into the statement**, so the document says
|
|
90
|
+
"after **30** minutes" where the source says `{idleTimeoutMin}` — the number a
|
|
91
|
+
reader actually wants, still from the single source.
|
|
92
|
+
|
|
93
|
+
Three properties this deliberately keeps:
|
|
94
|
+
|
|
95
|
+
- **One-way.** Markdown is only ever an output. Nothing reads it back, so the
|
|
96
|
+
free-form-prose drift that a Markdown *source* invites stays out.
|
|
97
|
+
- **Intent only.** No coverage, no counts, no test locations, no pass/fail —
|
|
98
|
+
those are verdicts, and `cover` / `verify` recompute them on demand. So the
|
|
99
|
+
document is a pure function of your `*.reqs.ts` files and changes if and only
|
|
100
|
+
if intent changes: one readable hunk per registry edit, and never a rewrite
|
|
101
|
+
because a line moved in a test file.
|
|
102
|
+
- **Gated.** A generated file you commit is a new place for drift to hide, so
|
|
103
|
+
`--check` regenerates and compares byte-for-byte, failing with
|
|
104
|
+
`stale-spec-doc` if the committed document no longer matches the registry, or
|
|
105
|
+
`missing-spec-doc` if it was never generated.
|
|
106
|
+
Put it in CI next to `attest check`. (Attest does this to itself:
|
|
107
|
+
[`self/requirements/SPEC.md`](https://gitlab.com/Pseudorca/attest/-/blob/main/self/requirements/SPEC.md)
|
|
108
|
+
is generated, and the pipeline fails if it goes stale.)
|
|
109
|
+
|
|
110
|
+
The Markdown is prose for humans and its formatting is not a stable contract —
|
|
111
|
+
don't parse it. `--json` is the machine surface.
|
|
112
|
+
|
|
75
113
|
### Framework code (`.vue`, DOM, path aliases)
|
|
76
114
|
|
|
77
115
|
The child run isolates from any ambient config by default, so specs run in a bare
|
|
@@ -92,6 +130,8 @@ flag the run stays isolated and deterministic.
|
|
|
92
130
|
Every command takes `--json` and then writes exactly one JSON document to
|
|
93
131
|
stdout — same work, same exit code. Branch on `ok`, `issues[].code` and
|
|
94
132
|
`issues[].reqId`; never parse `message`, which is prose and may be reworded.
|
|
133
|
+
(`render` is the one exception, because its own output is a document: there,
|
|
134
|
+
`--json` needs `--out` or `--check`, so stdout still carries exactly one thing.)
|
|
95
135
|
|
|
96
136
|
```bash
|
|
97
137
|
attest check --json
|
|
@@ -121,7 +161,8 @@ attest check --json
|
|
|
121
161
|
`verify` adds `passed` (was the test run itself green, independent of the
|
|
122
162
|
overall verdict); `cover` adds `coverage[]` — one `{ reqId, covered,
|
|
123
163
|
scenarioCount }` row per requirement — plus a `requirements` roll-up;
|
|
124
|
-
`archive` adds `change
|
|
164
|
+
`archive` adds `change`; `render` adds `outFile` (and never the document itself).
|
|
165
|
+
`schemaVersion` is bumped on any breaking change to
|
|
125
166
|
the shape. The TypeScript type is exported as `JsonReport`.
|
|
126
167
|
|
|
127
168
|
Even when a command crashes, `--json` still writes one parseable envelope
|
|
@@ -156,6 +197,16 @@ launcher, peer resolution from a foreign `node_modules` — so it is what catche
|
|
|
156
197
|
"green in-repo, broken once installed" bugs. It needs network and is excluded
|
|
157
198
|
from `pnpm test`; it runs in CI and as `prepublishOnly`.
|
|
158
199
|
|
|
200
|
+
## Feedback
|
|
201
|
+
|
|
202
|
+
Adoption reports drive the roadmap. After using Attest on a real project, fill in
|
|
203
|
+
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) —
|
|
204
|
+
and open it as an issue (it is also the **Usage feedback** issue template). It
|
|
205
|
+
covers greenfield and mid-project adoption alike, and ends with a prompt to run
|
|
206
|
+
inside the adopting repo that fills most of the report automatically and probes
|
|
207
|
+
for problems you haven't hit yet. The highest-value part is **false negatives**:
|
|
208
|
+
drift the engine should have caught and didn't.
|
|
209
|
+
|
|
159
210
|
## Acknowledgments
|
|
160
211
|
|
|
161
212
|
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 { writeFile } from 'node:fs/promises';
|
|
12
13
|
import { resolve } from 'node:path';
|
|
13
|
-
import { runCheck, runVerify, runCover, runArchive } from '../core/pipeline.js';
|
|
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();
|
|
@@ -104,6 +106,64 @@ program
|
|
|
104
106
|
},
|
|
105
107
|
};
|
|
106
108
|
}));
|
|
109
|
+
program
|
|
110
|
+
.command('render')
|
|
111
|
+
.description('Render the requirements as a Markdown document for human readers.')
|
|
112
|
+
.argument('[dir]', 'project root', undefined)
|
|
113
|
+
.option('--out <file>', 'write the document to this file instead of stdout')
|
|
114
|
+
.option('--check', 'fail if --out is missing or no longer matches the registry')
|
|
115
|
+
.option(JSON_FLAG, JSON_HELP)
|
|
116
|
+
.action((dir, opts, cmd) => {
|
|
117
|
+
// stdout carries exactly one document, so the Markdown and a --json report
|
|
118
|
+
// can never both go there. Usage errors are outside the --json contract
|
|
119
|
+
// (like arg parsing) and are reported as usage errors, not as reports.
|
|
120
|
+
if (opts.check && !opts.out)
|
|
121
|
+
cmd.error('error: --check requires --out <file>');
|
|
122
|
+
if (opts.json && !opts.out && !opts.check) {
|
|
123
|
+
cmd.error('error: --json requires --out <file> (stdout cannot carry both the document and the report)');
|
|
124
|
+
}
|
|
125
|
+
const dest = opts.out ? resolve(process.cwd(), opts.out) : undefined;
|
|
126
|
+
return runAction('render', opts, async () => {
|
|
127
|
+
if (opts.check) {
|
|
128
|
+
// The fix hint has to be the command the user can actually re-run from
|
|
129
|
+
// here: their own --out string, and the [dir] they passed.
|
|
130
|
+
const issues = await runRenderCheck(root(dir), dest, {
|
|
131
|
+
display: opts.out,
|
|
132
|
+
command: `attest render${dir ? ` ${dir}` : ''} --out ${opts.out}`,
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
report: renderReport(VERSION, issues, opts.out),
|
|
136
|
+
human: () => {
|
|
137
|
+
if (issues.length === 0)
|
|
138
|
+
console.log(chalk.green(`✓ ${opts.out} is up to date.`));
|
|
139
|
+
else {
|
|
140
|
+
console.log(formatIssues(issues));
|
|
141
|
+
console.log(summarize(issues));
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
const { markdown, issues } = await runRender(root(dir));
|
|
147
|
+
// Never overwrite a good document with the output of a broken registry.
|
|
148
|
+
if (!hasError(issues) && dest)
|
|
149
|
+
await writeFile(dest, markdown, 'utf8');
|
|
150
|
+
return {
|
|
151
|
+
report: renderReport(VERSION, issues, opts.out),
|
|
152
|
+
human: () => {
|
|
153
|
+
if (hasError(issues)) {
|
|
154
|
+
console.log(formatIssues(issues));
|
|
155
|
+
console.log(summarize(issues));
|
|
156
|
+
}
|
|
157
|
+
else if (dest) {
|
|
158
|
+
console.log(chalk.green(`✓ Wrote ${opts.out}`));
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
process.stdout.write(markdown);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
});
|
|
107
167
|
program
|
|
108
168
|
.command('archive')
|
|
109
169
|
.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;AACpC,OAAO,
|
|
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/pipeline.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RenderTarget } from './render.js';
|
|
1
2
|
import type { Issue } from './types.js';
|
|
2
3
|
/** Static structural check (design §9: `attest check`). */
|
|
3
4
|
export declare function runCheck(root: string): Promise<Issue[]>;
|
|
@@ -20,6 +21,29 @@ export interface CoverageRow {
|
|
|
20
21
|
}
|
|
21
22
|
/** Coverage-only report (design §9: `attest cover`). */
|
|
22
23
|
export declare function runCover(root: string): Promise<CoverageRow[]>;
|
|
24
|
+
export interface RenderResult {
|
|
25
|
+
/** The rendered document; empty string when `issues` contains an ERROR. */
|
|
26
|
+
markdown: string;
|
|
27
|
+
/** Registry-loading issues — rendering a half-loaded registry would lie. */
|
|
28
|
+
issues: Issue[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Markdown projection of the intent layer (design §9: `attest render`).
|
|
32
|
+
*
|
|
33
|
+
* Reads the registry and nothing else — no spec parse, no run — because the
|
|
34
|
+
* document is intent only. That is what keeps it a pure function of the
|
|
35
|
+
* `*.reqs.ts` files, so a committed rendering can be gated without going stale
|
|
36
|
+
* every time a line moves in a test file.
|
|
37
|
+
*/
|
|
38
|
+
export declare function runRender(root: string): Promise<RenderResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Freshness gate for a committed rendering (`attest render --check`).
|
|
41
|
+
*
|
|
42
|
+
* A generated file checked into the repo is itself a drift surface — the exact
|
|
43
|
+
* failure mode Attest exists to remove — so the projection only earns its place
|
|
44
|
+
* alongside a gate that fails when the file no longer matches its source.
|
|
45
|
+
*/
|
|
46
|
+
export declare function runRenderCheck(root: string, outFile: string, target: RenderTarget): Promise<Issue[]>;
|
|
23
47
|
/** Archive gate for a change (design §8, §9: `attest archive <change>`). */
|
|
24
48
|
export declare function runArchive(root: string, changeName: string, options?: RunOptions): Promise<Issue[]>;
|
|
25
49
|
/** True when a spec suite exists at all (used by the CLI to warn on empty roots). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,OAAO,KAAK,EAAc,KAAK,EAAY,MAAM,YAAY,CAAC;AAE9D,2DAA2D;AAC3D,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAa7D;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;CACb;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAmC7F;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAmBnE;AAED,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAWnE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,KAAK,EAAE,CAAC,CAOlB;AAED,4EAA4E;AAC5E,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,KAAK,EAAE,CAAC,CA8ClB;AAED,qFAAqF;AACrF,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7D"}
|
package/dist/core/pipeline.js
CHANGED
|
@@ -6,6 +6,8 @@ import { validateStructure, detectPotentialDrift } from './validator.js';
|
|
|
6
6
|
import { runAndCollect } from './runner.js';
|
|
7
7
|
import { applyDelta } from './apply.js';
|
|
8
8
|
import { evaluateGate } from './gate.js';
|
|
9
|
+
import { renderMarkdown, staleIssue } from './render.js';
|
|
10
|
+
import { readFile } from 'node:fs/promises';
|
|
9
11
|
import { join, relative } from 'node:path';
|
|
10
12
|
import { configDefaults } from 'vitest/config';
|
|
11
13
|
import { hasError } from './types.js';
|
|
@@ -82,6 +84,43 @@ export async function runCover(root) {
|
|
|
82
84
|
await loader.close();
|
|
83
85
|
}
|
|
84
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Markdown projection of the intent layer (design §9: `attest render`).
|
|
89
|
+
*
|
|
90
|
+
* Reads the registry and nothing else — no spec parse, no run — because the
|
|
91
|
+
* document is intent only. That is what keeps it a pure function of the
|
|
92
|
+
* `*.reqs.ts` files, so a committed rendering can be gated without going stale
|
|
93
|
+
* every time a line moves in a test file.
|
|
94
|
+
*/
|
|
95
|
+
export async function runRender(root) {
|
|
96
|
+
const loader = await createLoader();
|
|
97
|
+
try {
|
|
98
|
+
const { registry, issues } = await loadRegistry(root, loader);
|
|
99
|
+
// A registry that failed to load yields a document that silently omits
|
|
100
|
+
// requirements. An incomplete spec doc is worse than none, so refuse.
|
|
101
|
+
if (hasError(issues))
|
|
102
|
+
return { markdown: '', issues };
|
|
103
|
+
return { markdown: renderMarkdown(registry), issues };
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
await loader.close();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Freshness gate for a committed rendering (`attest render --check`).
|
|
111
|
+
*
|
|
112
|
+
* A generated file checked into the repo is itself a drift surface — the exact
|
|
113
|
+
* failure mode Attest exists to remove — so the projection only earns its place
|
|
114
|
+
* alongside a gate that fails when the file no longer matches its source.
|
|
115
|
+
*/
|
|
116
|
+
export async function runRenderCheck(root, outFile, target) {
|
|
117
|
+
const { markdown, issues } = await runRender(root);
|
|
118
|
+
if (hasError(issues))
|
|
119
|
+
return issues;
|
|
120
|
+
const current = await readFile(outFile, 'utf8').catch(() => undefined);
|
|
121
|
+
const stale = staleIssue(target, current, markdown);
|
|
122
|
+
return stale ? [...issues, stale] : issues;
|
|
123
|
+
}
|
|
85
124
|
/** Archive gate for a change (design §8, §9: `attest archive <change>`). */
|
|
86
125
|
export async function runArchive(root, changeName, options = {}) {
|
|
87
126
|
const loader = await createLoader();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Issue, Registry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render the registry as a standalone Markdown document.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately takes no formatting options (not even a title): every knob that
|
|
6
|
+
* changes the output is a way for `--check` to disagree with the run that
|
|
7
|
+
* generated the file, and a freshness gate that can be wrong about staleness is
|
|
8
|
+
* worse than no gate.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderMarkdown(registry: Registry): string;
|
|
11
|
+
/**
|
|
12
|
+
* How to talk about the file being gated. Both strings come from the caller
|
|
13
|
+
* rather than being derived from the paths: a path relative to the *project
|
|
14
|
+
* root* is not the path the user typed, and a command rebuilt from it drops the
|
|
15
|
+
* `[dir]` argument — which made the fix hint name a different registry than the
|
|
16
|
+
* one being checked.
|
|
17
|
+
*/
|
|
18
|
+
export interface RenderTarget {
|
|
19
|
+
/** The output path as the user wrote it. */
|
|
20
|
+
display: string;
|
|
21
|
+
/** The exact command that regenerates the file. */
|
|
22
|
+
command: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The freshness verdict for a committed rendering: `undefined` when the file on
|
|
26
|
+
* disk is exactly what the registry renders to now, an ERROR otherwise.
|
|
27
|
+
*
|
|
28
|
+
* The two failures get distinct codes — `missing-spec-doc` for a rendering that
|
|
29
|
+
* was never generated, `stale-spec-doc` for one whose bytes drifted — even
|
|
30
|
+
* though the fix is the same command. `message` is prose and not part of the
|
|
31
|
+
* API, so a code shared between the two would leave a consumer that cares about
|
|
32
|
+
* the difference (a first-time setup versus a document going out of date) with
|
|
33
|
+
* nothing to branch on but the wording.
|
|
34
|
+
*
|
|
35
|
+
* Kept here rather than in the pipeline, and pure, because this is the verdict
|
|
36
|
+
* that makes a generated file safe to commit: a byte comparison, no heuristics.
|
|
37
|
+
*/
|
|
38
|
+
export declare function staleIssue(target: RenderTarget, current: string | undefined, fresh: string): Issue | undefined;
|
|
39
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAe,MAAM,YAAY,CAAC;AAQ/D;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAezD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,KAAK,EAAE,MAAM,GACZ,KAAK,GAAG,SAAS,CAYnB"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Human-readable projection of the intent layer (design §0: Markdown is an
|
|
2
|
+
// *output*, never an input).
|
|
3
|
+
//
|
|
4
|
+
// The registry is the only source of truth; this module renders it for people
|
|
5
|
+
// who do not read TypeScript — reviewers, QA, audit. Nothing here is ever read
|
|
6
|
+
// back, so the direction OpenSpec's pure-Markdown model went (Markdown as
|
|
7
|
+
// truth, and the free-form drift that comes with it) stays closed.
|
|
8
|
+
//
|
|
9
|
+
// Three properties this file must keep:
|
|
10
|
+
// - **Intent only.** The document says what the system promises, never what is
|
|
11
|
+
// proven or green: coverage and results are verdicts, and verdicts belong to
|
|
12
|
+
// `cover` / `verify`, which recompute them on demand. Putting them here also
|
|
13
|
+
// made the document churn on code that changed no intent at all — a line
|
|
14
|
+
// shifting in a spec file rewrote it — and in a green repo the coverage was
|
|
15
|
+
// constant anyway (an uncovered requirement is a `check` ERROR), so it was
|
|
16
|
+
// diff noise carrying no information.
|
|
17
|
+
// - **A pure function of the registry.** No parse, no run, no options. The
|
|
18
|
+
// rendering therefore changes if and only if a `*.reqs.ts` changes, which is
|
|
19
|
+
// what makes `--check` a signal instead of a chore.
|
|
20
|
+
// - **Params interpolated into the statement.** The source says
|
|
21
|
+
// "{idleTimeoutMin} minutes"; a human reader wants "30 minutes". This is the
|
|
22
|
+
// one thing the projection gives that reading the source does not.
|
|
23
|
+
const BANNER = '<!-- Generated by `attest render` — do not edit. Edit the `*.reqs.ts` registry and regenerate. -->';
|
|
24
|
+
/**
|
|
25
|
+
* Render the registry as a standalone Markdown document.
|
|
26
|
+
*
|
|
27
|
+
* Deliberately takes no formatting options (not even a title): every knob that
|
|
28
|
+
* changes the output is a way for `--check` to disagree with the run that
|
|
29
|
+
* generated the file, and a freshness gate that can be wrong about staleness is
|
|
30
|
+
* worse than no gate.
|
|
31
|
+
*/
|
|
32
|
+
export function renderMarkdown(registry) {
|
|
33
|
+
const ids = Object.keys(registry).sort(compareIds);
|
|
34
|
+
const out = [BANNER, '', '# Requirements', ''];
|
|
35
|
+
if (ids.length === 0) {
|
|
36
|
+
out.push('_No requirements are defined yet._', '');
|
|
37
|
+
return out.join('\n');
|
|
38
|
+
}
|
|
39
|
+
out.push(...overviewTable(registry, ids), '');
|
|
40
|
+
for (const id of ids) {
|
|
41
|
+
out.push(...section(id, registry[id]), '');
|
|
42
|
+
}
|
|
43
|
+
return out.join('\n');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The freshness verdict for a committed rendering: `undefined` when the file on
|
|
47
|
+
* disk is exactly what the registry renders to now, an ERROR otherwise.
|
|
48
|
+
*
|
|
49
|
+
* The two failures get distinct codes — `missing-spec-doc` for a rendering that
|
|
50
|
+
* was never generated, `stale-spec-doc` for one whose bytes drifted — even
|
|
51
|
+
* though the fix is the same command. `message` is prose and not part of the
|
|
52
|
+
* API, so a code shared between the two would leave a consumer that cares about
|
|
53
|
+
* the difference (a first-time setup versus a document going out of date) with
|
|
54
|
+
* nothing to branch on but the wording.
|
|
55
|
+
*
|
|
56
|
+
* Kept here rather than in the pipeline, and pure, because this is the verdict
|
|
57
|
+
* that makes a generated file safe to commit: a byte comparison, no heuristics.
|
|
58
|
+
*/
|
|
59
|
+
export function staleIssue(target, current, fresh) {
|
|
60
|
+
if (current === fresh)
|
|
61
|
+
return undefined;
|
|
62
|
+
const missing = current === undefined;
|
|
63
|
+
const why = missing
|
|
64
|
+
? `No rendering at "${target.display}".`
|
|
65
|
+
: `"${target.display}" no longer matches the registry.`;
|
|
66
|
+
return {
|
|
67
|
+
level: 'ERROR',
|
|
68
|
+
code: missing ? 'missing-spec-doc' : 'stale-spec-doc',
|
|
69
|
+
file: target.display,
|
|
70
|
+
message: `${why} Regenerate it with: ${target.command}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Order ids the way a reader expects: prefix alphabetically, then the number
|
|
75
|
+
* numerically. A plain string sort puts ATX-10 between ATX-1 and ATX-2, which
|
|
76
|
+
* scrambles the document as soon as a registry reaches ten requirements.
|
|
77
|
+
*/
|
|
78
|
+
function compareIds(a, b) {
|
|
79
|
+
const split = (id) => {
|
|
80
|
+
const at = id.lastIndexOf('-');
|
|
81
|
+
return [id.slice(0, at), Number(id.slice(at + 1))];
|
|
82
|
+
};
|
|
83
|
+
const [prefixA, numA] = split(a);
|
|
84
|
+
const [prefixB, numB] = split(b);
|
|
85
|
+
// Code-unit comparison, not localeCompare: the ordering has to be identical
|
|
86
|
+
// on every machine, or `--check` would flap with the runner's locale.
|
|
87
|
+
if (prefixA !== prefixB)
|
|
88
|
+
return prefixA < prefixB ? -1 : 1;
|
|
89
|
+
return numA - numB;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* An index of the whole registry: id + the promise itself. Deliberately carries
|
|
93
|
+
* no counts — a roll-up would conflict in every pair of parallel branches that
|
|
94
|
+
* each add a requirement, for a number the table below already shows.
|
|
95
|
+
*/
|
|
96
|
+
function overviewTable(registry, ids) {
|
|
97
|
+
const rows = ids.map((id) => {
|
|
98
|
+
const req = registry[id];
|
|
99
|
+
return `| [${id}](${anchor(id)}) | ${cell(interpolate(req.statement, req.params))} |`;
|
|
100
|
+
});
|
|
101
|
+
return ['| ID | Requirement |', '| --- | --- |', ...rows];
|
|
102
|
+
}
|
|
103
|
+
function section(id, req) {
|
|
104
|
+
const out = [
|
|
105
|
+
`## ${id}`,
|
|
106
|
+
'',
|
|
107
|
+
interpolate(req.statement, req.params),
|
|
108
|
+
'',
|
|
109
|
+
`**Why:** ${req.rationale}`,
|
|
110
|
+
];
|
|
111
|
+
const params = Object.entries(req.params);
|
|
112
|
+
if (params.length > 0) {
|
|
113
|
+
out.push('', '| Param | Value |', '| --- | --- |', ...params.map(([name, value]) => `| ${code(name)} | ${cell(formatValue(value))} |`));
|
|
114
|
+
}
|
|
115
|
+
if (req.outOfScope.length > 0) {
|
|
116
|
+
out.push('', '**Out of scope**', '', ...req.outOfScope.map((s) => `- ${s}`));
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Substitute `{param}` placeholders with the actual value, emphasised so a
|
|
122
|
+
* reader can see which words in the sentence are pinned to a single source.
|
|
123
|
+
* An unbound placeholder is left verbatim — `check` already reports it as an
|
|
124
|
+
* `unbound-param` error, and silently swallowing it here would hide that.
|
|
125
|
+
*/
|
|
126
|
+
function interpolate(statement, params) {
|
|
127
|
+
return statement.replace(/\{(\w+)\}/g, (whole, name) => name in params ? `**${plain(params[name])}**` : whole);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A param value as prose, for inline use inside a statement. Escaped, unlike
|
|
131
|
+
* the statement and rationale around it: those are prose an author may want to
|
|
132
|
+
* mark up, a param value is data and must survive verbatim — an unescaped `*`
|
|
133
|
+
* would otherwise break out of the emphasis it is wrapped in.
|
|
134
|
+
*/
|
|
135
|
+
function plain(value) {
|
|
136
|
+
const one = (v) => v.replace(/([*_`[\]\\])/g, '\\$1');
|
|
137
|
+
return Array.isArray(value) ? value.map((v) => one(String(v))).join(', ') : one(String(value));
|
|
138
|
+
}
|
|
139
|
+
/** A param value as code, for the params table. */
|
|
140
|
+
function formatValue(value) {
|
|
141
|
+
return Array.isArray(value)
|
|
142
|
+
? value.map((v) => code(String(v))).join(', ')
|
|
143
|
+
: code(String(value));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Wrap text in a code span that survives backticks in the value: the fence has
|
|
147
|
+
* to be longer than the longest run inside it, and a value touching a backtick
|
|
148
|
+
* at either end needs padding spaces.
|
|
149
|
+
*/
|
|
150
|
+
function code(value) {
|
|
151
|
+
const longest = Math.max(0, ...[...value.matchAll(/`+/g)].map((m) => m[0].length));
|
|
152
|
+
const fence = '`'.repeat(longest + 1);
|
|
153
|
+
const pad = value.startsWith('`') || value.endsWith('`') ? ' ' : '';
|
|
154
|
+
return `${fence}${pad}${value}${pad}${fence}`;
|
|
155
|
+
}
|
|
156
|
+
/** Make prose safe inside a table cell: no row-breaking pipes, no newlines. */
|
|
157
|
+
function cell(text) {
|
|
158
|
+
return text.replace(/\s*\n\s*/g, ' ').replace(/\|/g, '\\|');
|
|
159
|
+
}
|
|
160
|
+
/** GitHub/GitLab slug for a `## AUTH-3` heading. */
|
|
161
|
+
function anchor(id) {
|
|
162
|
+
return `#${id.toLowerCase()}`;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@am_shork/attest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
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": {
|
|
@@ -71,6 +71,8 @@
|
|
|
71
71
|
"attest": "node bin/attest.js",
|
|
72
72
|
"check:self": "node bin/attest.js check self",
|
|
73
73
|
"verify:self": "node bin/attest.js verify self",
|
|
74
|
-
"cover:self": "node bin/attest.js cover self"
|
|
74
|
+
"cover:self": "node bin/attest.js cover self",
|
|
75
|
+
"render:self": "node bin/attest.js render self --out self/requirements/SPEC.md",
|
|
76
|
+
"render:self:check": "node bin/attest.js render self --out self/requirements/SPEC.md --check"
|
|
75
77
|
}
|
|
76
78
|
}
|