@supersuit/hyperspec 0.7.0 → 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 +93 -0
- package/README.md +76 -9
- package/SPEC.md +2 -2
- package/WRITING.md +463 -18
- package/bin/hyperspec.mjs +137 -6
- package/examples/writing/course/claims.jsonl +0 -0
- package/examples/writing/course/goldens/lesson.md +1 -0
- package/examples/writing/course/materials/brief.md +9 -0
- package/examples/writing/course/materials/brief.md.segments.jsonl +6 -0
- package/examples/writing/course/outline.md +11 -0
- package/examples/writing/course/part-1.md +64 -0
- package/examples/writing/course/part-2.md +57 -0
- package/examples/writing/course/runs.jsonl +0 -0
- package/examples/writing/course.hyperspec.md +206 -0
- package/examples/writing/essay/judge/panel-buyer.packet.json +118 -0
- package/examples/writing/essay/judge/panel-expert.packet.json +114 -0
- package/examples/writing/essay/judge/panel-novice.packet.json +114 -0
- package/examples/writing/essay/judge/panel-skeptic.packet.json +114 -0
- package/examples/writing/essay/sample-verdicts/panel-buyer.verdict.json +11 -0
- package/examples/writing/essay/sample-verdicts/panel-expert.verdict.json +13 -0
- package/examples/writing/essay/sample-verdicts/panel-novice.verdict.json +11 -0
- package/examples/writing/essay/sample-verdicts/panel-skeptic.verdict.json +13 -0
- package/examples/writing/story/judge/panel-buyer.packet.json +118 -0
- package/examples/writing/story/judge/panel-expert.packet.json +114 -0
- package/examples/writing/story/judge/panel-novice.packet.json +114 -0
- package/examples/writing/story/judge/panel-skeptic.packet.json +114 -0
- package/examples/writing/story/sample-verdicts/panel-buyer.verdict.json +13 -0
- package/examples/writing/story/sample-verdicts/panel-expert.verdict.json +11 -0
- package/examples/writing/story/sample-verdicts/panel-novice.verdict.json +11 -0
- package/examples/writing/story/sample-verdicts/panel-skeptic.verdict.json +11 -0
- package/package.json +1 -1
- package/src/check.mjs +25 -7
- package/src/evidence.mjs +74 -0
- package/src/judge.mjs +50 -66
- package/src/judges/index.mjs +7 -1
- package/src/judges/panel.mjs +135 -0
- package/src/sequence-draft.mjs +75 -0
- package/src/stations/index.mjs +5 -1
- package/src/stations/links.mjs +11 -3
- package/src/stations/quotes.mjs +26 -2
- package/src/stations/sequence.mjs +388 -0
- package/src/stations/triage.mjs +20 -0
- package/src/triage.mjs +401 -0
- package/src/writing-fields.mjs +81 -0
- package/src/writing.mjs +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,98 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.0 (2026-09-29)
|
|
4
|
+
|
|
5
|
+
The pressure test a draft gets before it ships is now part of the run, and so is answering it.
|
|
6
|
+
Several readers reading a draft through their own lenses, and someone deciding what to do about
|
|
7
|
+
each thing they said, was done by hand twice, once for a letter and once for a book outline, and
|
|
8
|
+
both times the review read a stale, truncated copy and none of its readers was the person the
|
|
9
|
+
piece was for. The `panel` judge fixes both by construction, and `hyperspec triage` holds every
|
|
10
|
+
finding, the panel's or an outside review's, to an answer that `check` keeps true against the draft.
|
|
11
|
+
|
|
12
|
+
- The `panel` judgment station, the seventh, run last. One packet per reader,
|
|
13
|
+
`panel-<reader>.packet.json`: the readers the new optional `writing.panel` lists (`id`, `who`,
|
|
14
|
+
`knows`, `lens`), or by default a `skeptic`, a `novice` and an `expert`, and always the audience's
|
|
15
|
+
own reader, added last as `buyer`. It applies when the reader station does (a written audience
|
|
16
|
+
with a rubric). The verdict is `{ good, improve, missing, remove }`, every item `{ evidence, note }`
|
|
17
|
+
under the evidence rule, so a review of any copy but the current draft is refused. The panel
|
|
18
|
+
never fails a draft: improve, missing and remove items are warnings (`judge-panel-improve`,
|
|
19
|
+
`-missing`, `-remove`) and go to the triage file. A panel ledger line carries `reader`, and each
|
|
20
|
+
reader's history is its own. Lint refuses a panel that is not a list of readers, a reader with no
|
|
21
|
+
id, who or lens, an id that is not a slug, used twice or `buyer`, and a hollow `knows`
|
|
22
|
+
(`writing-panel`, `-reader`, `-id`, `-id-duplicate`, `-buyer`, `-who`, `-lens`, `-knows`, test 1).
|
|
23
|
+
- `triage.jsonl`, beside the runs ledger: one finding per line, `{ finding_id, source, reader, kind,
|
|
24
|
+
text, evidence, draft_sha256, disposition, answer }`, each once (the id hashes what it says).
|
|
25
|
+
- The `triage` station, run last in `check`: fails on an unanswered finding
|
|
26
|
+
(`station-triage-untriaged`), a `taken` or `already-true` answer whose evidence is missing or not
|
|
27
|
+
in the draft (`-evidence-missing`, `-evidence-not-found`), a `kept` answer with no reason
|
|
28
|
+
(`-reason-missing`), a disposition outside the four (`-disposition`) or a line that is not a
|
|
29
|
+
finding (`-unreadable`); warns on an `open` finding (`-open`) and on a kept or open answer about a
|
|
30
|
+
passage that has left the draft (`-stale`). With no triage file it skips.
|
|
31
|
+
- `hyperspec triage status` (the counts, the station's rules, and the synthesis: every passage two
|
|
32
|
+
or more readers raised findings about), `triage answer` (refuses with `triage-evidence-missing`,
|
|
33
|
+
`-too-short`, `-not-found` or `triage-reason-missing`, writing nothing), `triage import` (an
|
|
34
|
+
outside review in markdown or plain text as findings: headings name readers, Good, Improve,
|
|
35
|
+
Missing and Remove labels set the kind, praise is counted and not triaged, and a quote the draft
|
|
36
|
+
does not hold warns, `triage-import-quote-not-found`; `triage-import-empty` when there is nothing
|
|
37
|
+
to answer) and `triage reply` (a plain-text reply to the reviewer; it never sends, and exits 1
|
|
38
|
+
while a finding is unanswered).
|
|
39
|
+
- The quotes station reads the new optional `writing.quotes.examples`: `true` reads a quoted span
|
|
40
|
+
whose sentence names no known speaker as an example phrasing, not a quotation; a list exempts
|
|
41
|
+
exactly those phrasings. A quotation that names its speaker is checked either way. Lint refuses
|
|
42
|
+
any other value (`writing-quotes`, `writing-quotes-examples`, test 1).
|
|
43
|
+
- The sequence station gains the quiz rules, on when the new `writing.form.sequence.quiz` names the
|
|
44
|
+
quiz heading: every defined term tested by some question (a simple plural counts), no question
|
|
45
|
+
using a term defined after the unit it is tagged with, every question tagged, every answer one of
|
|
46
|
+
its options (`station-sequence-quiz-missing`, `-untagged`, `-answer`, `-used-before-defined`,
|
|
47
|
+
`-untested`). Promoted from the checker the first book written this way used, with its question
|
|
48
|
+
shape. A hollow `quiz` fails lint (`writing-form-sequence-quiz`, test 1).
|
|
49
|
+
- The evidence rule moved to `src/evidence.mjs`, shared by `judge record` and `triage`; `judge.mjs`
|
|
50
|
+
re-exports what it exported.
|
|
51
|
+
- The worked examples: the essay and the story ship four panel packets each, with a hand-filled
|
|
52
|
+
sample verdict per reader; the course carries a quiz at the end of each part and `quiz: Check
|
|
53
|
+
yourself`.
|
|
54
|
+
|
|
55
|
+
**Behavior change:** `check` runs nine stations, so `--json` and the ledger's `stations` carry
|
|
56
|
+
`triage` (as `skip` for every spec without a triage file). `judge prepare` writes the four panel
|
|
57
|
+
packets for every spec whose audience has a rubric, where 0.8 wrote none; `--only` still limits it.
|
|
58
|
+
No other finding id changed.
|
|
59
|
+
|
|
60
|
+
## 0.8.0 (2026-09-29)
|
|
61
|
+
|
|
62
|
+
A work read in order can now be checked as one. Every station so far held ONE piece to its spec; a
|
|
63
|
+
course, a primer or a textbook makes promises ACROSS its pieces (Lesson 5 is written for someone who
|
|
64
|
+
has read Lessons 1 to 4 and nothing else), and nothing checked them. Declare `writing.form.sequence`
|
|
65
|
+
and the new `sequence` station does, deterministically, on every `check`. Promoted from a checker
|
|
66
|
+
written for one book, so every sequential work gets it by construction.
|
|
67
|
+
|
|
68
|
+
- `writing.form.sequence`, optional, every key optional: `unit` (the heading word, default
|
|
69
|
+
`Lesson`), `files` (the work's files in reading order; a `*` in a file name matches, sorted by
|
|
70
|
+
number), `sections` (default "After this lesson you can", "New terms", "Try this"),
|
|
71
|
+
`terms_section` (default "New terms"), `outline` (numbered items promising `*Terms: a, b.*`),
|
|
72
|
+
`knows` (words a lesson may use before one defines them, beside `audience.knows`) and `teaser`
|
|
73
|
+
(default "Next,": a closing line naming what is coming). Lint refuses a key that is present and
|
|
74
|
+
hollow under test 1, and a `files` entry matching nothing or an `outline` that is not a file under
|
|
75
|
+
test 6.
|
|
76
|
+
- The `sequence` station, run last: every unit carries its sections; every term is defined in
|
|
77
|
+
exactly one unit; no unit uses a term before the unit that defines it (code, the unit's own terms
|
|
78
|
+
section and its closing teaser are not uses, and a `(from Lesson N)` reminder defines nothing);
|
|
79
|
+
each unit defines what the outline promises, for the units the draft holds; unit numbers increase;
|
|
80
|
+
a pointer to a later unit is a warning. Findings: `station-sequence-no-units`, `-numbering`,
|
|
81
|
+
`-missing-section`, `-defined-twice`, `-used-before-defined`, `-outline-unreadable`,
|
|
82
|
+
`-outline-unkept` (fail) and `-forward-pointer` (warn). A spec with no `sequence` skips it.
|
|
83
|
+
- `hyperspec check <spec>` needs no `--draft` when the spec lists `sequence.files`: the files,
|
|
84
|
+
joined in order with each one's frontmatter blanked, are the draft, and every station reads them.
|
|
85
|
+
A finding names the file and its own line (`(course/part-1.md line 25)`; `file` and `line` in
|
|
86
|
+
`--json`), a relative link resolves beside the file that holds it, and the ledger keys the run by
|
|
87
|
+
the `files` entry as written, so the work keeps one history as parts are added. `--draft` still
|
|
88
|
+
names one file, which may hold every lesson.
|
|
89
|
+
- A third worked example, `examples/writing/course.hyperspec.md`: four lessons in two part files
|
|
90
|
+
with an outline, passing every station with two forward-pointer warnings.
|
|
91
|
+
|
|
92
|
+
**Behavior change:** `check` runs eight stations, so `--json` and the ledger's `stations` carry
|
|
93
|
+
`sequence` (as `skip` for every spec without a sequence). No other station, finding id or schema
|
|
94
|
+
field changed, and a 0.7 ledger's verdicts read as they did.
|
|
95
|
+
|
|
3
96
|
## 0.7.0 (2026-09-29)
|
|
4
97
|
|
|
5
98
|
A spec can now have its judgments made and recorded. `check` covers what a function of the spec
|
package/README.md
CHANGED
|
@@ -28,9 +28,13 @@ improvement ledger. Every test is defined in [SPEC.md](SPEC.md).
|
|
|
28
28
|
| `hyperspec segments init <material> --id <mid> [--out F] [--by paragraph\|sentence]` | Split a material into segments to label. Refuses to overwrite an existing file. |
|
|
29
29
|
| `hyperspec dna init <scope-dir> --writer W --form F --audience A --purpose P` | Start a writer-DNA scope folder. Refuses to overwrite an existing `scope.md`. |
|
|
30
30
|
| `hyperspec dna measure <scope-dir>` | Check every golden in a scope and write its measured features. |
|
|
31
|
-
| `hyperspec check <spec> --draft <file> [--only a,b]` | Run a writing spec's deterministic stations against a draft. |
|
|
31
|
+
| `hyperspec check <spec> [--draft <file>] [--only a,b]` | Run a writing spec's deterministic stations against a draft, or, for a sequential work, against its files in reading order. |
|
|
32
32
|
| `hyperspec judge prepare <spec> --draft <file> --out <dir> [--only a,b] [--force]` | Write one packet per judgment station, for an outside judge to fill. |
|
|
33
33
|
| `hyperspec judge record <packet> --verdict <file>` | Check a judge's verdict against its packet, derive the station's status, and record it. |
|
|
34
|
+
| `hyperspec triage status <spec> [--draft <file>]` | Count every finding's answer, list the passages two or more readers share, and hold every answer to the draft. |
|
|
35
|
+
| `hyperspec triage answer <spec> <finding> taken\|kept\|already-true\|open [--evidence S] [--reason S] [--draft <file>]` | Answer one finding: evidence from the draft for taken and already-true, a reason for kept. |
|
|
36
|
+
| `hyperspec triage import <spec> <review> [--source S] [--draft <file>]` | Bring an outside review in as findings to answer. |
|
|
37
|
+
| `hyperspec triage reply <spec> [--source S] [--draft <file>]` | Print a plain-text reply to the reviewer from the answers. Never sends anything. |
|
|
34
38
|
| `hyperspec learn prepare <spec> --first <draft> --approved <draft> --out <dir> [--force]` | Write the edits between a first draft and the approved one, for a judge to classify by spec block. |
|
|
35
39
|
| `hyperspec learn record <packet> --verdict <file>` | Count the classified edits by block and name one next move. |
|
|
36
40
|
| `hyperspec recipe check <output-or-recipe>` | Check that a recipe records everything the standard asks for. |
|
|
@@ -57,6 +61,12 @@ and 1 when it refused. `judge prepare` and `learn prepare` exit 0 when they wrot
|
|
|
57
61
|
with lint's own code when the spec is not ready, and `judge prepare` exits 1 when a station could
|
|
58
62
|
not build its packet. All four exit 2 on a usage error.
|
|
59
63
|
|
|
64
|
+
`hyperspec triage status` exits 0 when every finding is answered and every answer holds against
|
|
65
|
+
the draft, and 1 when not; `triage answer` 0 when it wrote the answer and 1 when it refused it;
|
|
66
|
+
`triage import` 0 when it imported and 1 when the review holds nothing to answer; `triage reply` 0
|
|
67
|
+
when the reply is ready to send and 1 when a finding is still unanswered. All four exit 2 on a
|
|
68
|
+
usage error.
|
|
69
|
+
|
|
60
70
|
The recipe commands use the same numbers: 0 ok, 1 a check failed or the child regressed, 2
|
|
61
71
|
usage or unreadable input, 3 pending, when `regenerate` has stages waiting for a runner.
|
|
62
72
|
`regenerate` also exits 1 when a stage it ran reported a failing verdict, or none. A stage it
|
|
@@ -145,9 +155,10 @@ npx @supersuit/hyperspec init story.hyperspec.md --profile writing --form "short
|
|
|
145
155
|
|
|
146
156
|
The skeleton fails until every placeholder is real and its four open questions (whose voice,
|
|
147
157
|
who speaks, who reads, what changes) are answered. The blocks, every field, and which test
|
|
148
|
-
each rule reports under are in [WRITING.md](WRITING.md).
|
|
149
|
-
nothing to warn ship in `examples/writing/`: an essay for new managers,
|
|
150
|
-
two characters whose voices a judge can tell apart. Each comes with a
|
|
158
|
+
each rule reports under are in [WRITING.md](WRITING.md). Three complete specs that pass with
|
|
159
|
+
nothing to warn ship in `examples/writing/`: an essay for new managers, a short story with
|
|
160
|
+
two characters whose voices a judge can tell apart, and a four-lesson course. Each comes with a
|
|
161
|
+
draft written to it.
|
|
151
162
|
|
|
152
163
|
### Marking materials
|
|
153
164
|
|
|
@@ -193,23 +204,53 @@ it did in 0.4. The folder shape, every feature, and every finding are in
|
|
|
193
204
|
|
|
194
205
|
### Checking a draft
|
|
195
206
|
|
|
196
|
-
Once a draft exists, `check` holds it to its spec with
|
|
207
|
+
Once a draft exists, `check` holds it to its spec with nine stations, none of which calls a
|
|
197
208
|
model or touches the network: `form` (length and required parts), `terms` (every word in the new
|
|
198
209
|
optional `writing.audience.terms` is defined where it first appears), `claims` (the claims
|
|
199
210
|
ledger still matches the draft, and every claim has a source), `quotes` (in nonfiction, every quotation of four
|
|
200
|
-
words or more is word for word in a marked quote
|
|
201
|
-
|
|
202
|
-
(
|
|
211
|
+
words or more is word for word in a marked quote; `writing.quotes.examples` marks example
|
|
212
|
+
phrasings such as "write the update for Dana" as examples rather than quotations), `private` (no run of eight words from a
|
|
213
|
+
private segment), `dna` (the draft's measured style beside its scope's, as warnings), `links`
|
|
214
|
+
(well-formed, and relative links resolve), `sequence` (for a work read in order; see below) and
|
|
215
|
+
`triage` (every reader's finding answered, and every answer held to the draft; see below).
|
|
203
216
|
|
|
204
217
|
```bash
|
|
205
218
|
npx @supersuit/hyperspec check essay.hyperspec.md --draft essay/draft.md
|
|
206
219
|
```
|
|
207
220
|
|
|
208
221
|
It lints the spec first, prints each station's pass, fail or skip, and appends one line to the
|
|
209
|
-
spec's runs ledger with a verdict.
|
|
222
|
+
spec's runs ledger with a verdict. Every example ships a draft that passes. What each station
|
|
210
223
|
checks and cannot check, and every finding, are in
|
|
211
224
|
[WRITING.md](WRITING.md#checking-a-draft).
|
|
212
225
|
|
|
226
|
+
### Sequential works
|
|
227
|
+
|
|
228
|
+
A course, a primer or a textbook promises something no single piece can check: Lesson 5 uses only
|
|
229
|
+
words Lessons 1 to 4 defined. Add `sequence:` to `writing.form` and the `sequence` station checks
|
|
230
|
+
it across the whole work: every lesson carries its sections ("After this lesson you can", "New
|
|
231
|
+
terms", "Try this" by default), every term is defined in exactly one lesson, no lesson uses a term
|
|
232
|
+
before the lesson that defines it (code, the part's closing teaser and words the reader already
|
|
233
|
+
knows are exempt), each lesson defines the terms the outline promises, and a pointer to a later
|
|
234
|
+
lesson is a warning. Name the quiz heading as `quiz:` and every quiz is held to it too: every
|
|
235
|
+
defined term tested by some question, no question using a term from a lesson after the one it is
|
|
236
|
+
tagged with, and every answer one of its question's options. List the work's files and `check`
|
|
237
|
+
needs no `--draft`:
|
|
238
|
+
|
|
239
|
+
```yaml
|
|
240
|
+
sequence:
|
|
241
|
+
files:
|
|
242
|
+
- course/part-*.md
|
|
243
|
+
outline: course/outline.md
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
npx @supersuit/hyperspec check course.hyperspec.md
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The parts are read in order, a finding names the part and its line, and a new part matching the
|
|
251
|
+
pattern is picked up without touching the spec. Every key, how a lesson is read, and every finding
|
|
252
|
+
are in [WRITING.md](WRITING.md#sequential-works).
|
|
253
|
+
|
|
213
254
|
### Judging a draft and learning from edits
|
|
214
255
|
|
|
215
256
|
The rest of a spec's checks are judgments: whether each goal condition holds, where a reader gets
|
|
@@ -237,6 +278,32 @@ style rule". It never edits the spec. Both examples ship their packets and hand-
|
|
|
237
278
|
verdicts. The packet shapes, every station's rules and findings, and the learn tally are in
|
|
238
279
|
[WRITING.md](WRITING.md#judging-a-draft).
|
|
239
280
|
|
|
281
|
+
### A reader panel, and answering what it found
|
|
282
|
+
|
|
283
|
+
A draft gets pressure-tested before it ships: several readers read it, each through their own
|
|
284
|
+
lens, and say what works, what to improve, what is missing and what to remove. The `panel` judge
|
|
285
|
+
makes that part of the run. It writes one packet per reader, the ones `writing.panel` lists or by
|
|
286
|
+
default a skeptic, a newcomer and an expert, and always the audience's own reader as `buyer`,
|
|
287
|
+
since a panel that never includes the person the piece is for tests everything but that. Every
|
|
288
|
+
item a reader lists quotes the draft word for word, so a review of a stale copy is refused.
|
|
289
|
+
|
|
290
|
+
Each thing a reader would change becomes a finding in `triage.jsonl`, beside the runs ledger, and
|
|
291
|
+
so does each point of an outside review brought in with `triage import`. Every finding gets one
|
|
292
|
+
answer: `taken` (with the passage of the draft that now does it), `kept` (with the reason),
|
|
293
|
+
`already-true` (with the passage that already did it) or `open` (a decision for you). `check` fails
|
|
294
|
+
while a finding is unanswered or an answer's passage is no longer in the draft, and warns on an
|
|
295
|
+
open one. `triage reply` turns the answers into a plain-text reply to the reviewer, for you to send.
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
npx @supersuit/hyperspec judge record story/judge/panel-skeptic.packet.json --verdict story/sample-verdicts/panel-skeptic.verdict.json
|
|
299
|
+
npx @supersuit/hyperspec triage status story.hyperspec.md --draft story/draft.md
|
|
300
|
+
npx @supersuit/hyperspec triage answer story.hyperspec.md panel-skeptic-aeb09835 open --draft story/draft.md --reason "the author's call"
|
|
301
|
+
npx @supersuit/hyperspec triage reply story.hyperspec.md --draft story/draft.md
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
The triage file, every answer's rule, how a review is read, and every finding are in
|
|
305
|
+
[WRITING.md](WRITING.md#triage-1).
|
|
306
|
+
|
|
240
307
|
## The format
|
|
241
308
|
|
|
242
309
|
A hyperspec is a markdown file with a YAML frontmatter block: `decisions`, `requirements`,
|
package/SPEC.md
CHANGED
|
@@ -97,7 +97,7 @@ examples:
|
|
|
97
97
|
- path: examples/minimal.hyperspec.md
|
|
98
98
|
why: the smallest spec that passes all nine tests
|
|
99
99
|
resume:
|
|
100
|
-
next_action: collect adopter issues on 0.
|
|
100
|
+
next_action: collect adopter issues on 0.9, the panel and triage included, and cut 0.10 from them
|
|
101
101
|
feedback:
|
|
102
102
|
issues: https://github.com/SupersuitUp/hyperspec/issues
|
|
103
103
|
fork: MIT; fork it for your own purposes and say so in your SPEC
|
|
@@ -109,7 +109,7 @@ improvement:
|
|
|
109
109
|
|
|
110
110
|
A person writing for another person leaves most of the specification unsaid, because the other person fills the gaps from shared context. An agent has none of that context, so it fills every gap with the average, and the average is what reads as middling. Hyperspecification is writing down the gaps. It is a level of detail that would feel like overkill between two people and is exactly enough for an agent: every decision the agent would otherwise guess is either decided, delegated with the rule for deciding it, or marked open, so the work stops instead of guessing.
|
|
111
111
|
|
|
112
|
-
**Version 0.
|
|
112
|
+
**Version 0.9.0** (2026-09-29)
|
|
113
113
|
|
|
114
114
|
## What makes a spec a hyperspec
|
|
115
115
|
|