@supersuit/hyperspec 0.4.0 → 0.6.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 +143 -0
- package/README.md +50 -2
- package/SPEC.md +5 -5
- package/WRITING.md +510 -17
- package/bin/hyperspec.mjs +177 -2
- package/examples/writing/dna/essay-new-managers-teach/features.json +56 -0
- package/examples/writing/dna/essay-new-managers-teach/goldens/README.md +14 -0
- package/examples/writing/dna/essay-new-managers-teach/goldens/close.md +9 -0
- package/examples/writing/dna/essay-new-managers-teach/goldens/opening.md +9 -0
- package/examples/writing/dna/essay-new-managers-teach/goldens/status.md +10 -0
- package/examples/writing/dna/essay-new-managers-teach/scope.md +11 -0
- package/examples/writing/essay/claims.jsonl +9 -0
- package/examples/writing/essay/draft.md +82 -0
- package/examples/writing/essay/materials/interview-notes.md.segments.jsonl +2 -2
- package/examples/writing/essay.hyperspec.md +32 -13
- package/examples/writing/story/claims.jsonl +9 -0
- package/examples/writing/story/draft.md +267 -0
- package/examples/writing/story.hyperspec.md +20 -5
- package/package.json +1 -1
- package/src/check.mjs +245 -0
- package/src/dna.mjs +474 -0
- package/src/stations/claims.mjs +150 -0
- package/src/stations/dna.mjs +126 -0
- package/src/stations/form.mjs +115 -0
- package/src/stations/index.mjs +27 -0
- package/src/stations/links.mjs +275 -0
- package/src/stations/private.mjs +117 -0
- package/src/stations/quotes.mjs +168 -0
- package/src/stations/terms.mjs +131 -0
- package/src/stations/util.mjs +99 -0
- package/src/writing-exports.mjs +8 -3
- package/src/writing-fields.mjs +197 -1
- package/src/writing-template.mjs +8 -0
- package/examples/writing/essay/goldens/close.md +0 -2
- package/examples/writing/essay/goldens/opening.md +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,148 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 (2026-09-29)
|
|
4
|
+
|
|
5
|
+
A spec can now check a draft. Until this release hyperspec could tell you whether a writing spec
|
|
6
|
+
was ready; it could not tell you whether the piece written from it met the spec. `hyperspec
|
|
7
|
+
check` runs seven deterministic stations against a draft: the length and required parts, the
|
|
8
|
+
terms the reader needs defined, the claims ledger, quotations, private material, the writer's
|
|
9
|
+
measured style, and links. None of them calls a model or touches the network, so the same draft
|
|
10
|
+
and spec always give the same answer. Each run leaves one line in the spec's runs ledger saying
|
|
11
|
+
whether the draft passed first time, improved, or did not, and why.
|
|
12
|
+
|
|
13
|
+
**No behavior change for lint.** Every spec without `writing.audience.terms` passes and fails
|
|
14
|
+
exactly as it did in 0.5.0, and no lint finding id changed. That field is the one schema
|
|
15
|
+
addition, and it is optional.
|
|
16
|
+
|
|
17
|
+
- `hyperspec check <spec> --draft <file> [--json] [--only a,b]` needs a writing spec
|
|
18
|
+
(`profile: writing`) and lints it first: a spec that fails lint, or is blocked on an open
|
|
19
|
+
decision, runs no station and exits with lint's code. Then it runs every station in a fixed
|
|
20
|
+
order, `form, terms, claims, quotes, private, dna, links`, and prints each one's `pass`, `fail`
|
|
21
|
+
with findings, or `skip` with the reason. Warnings print under their station and never fail it.
|
|
22
|
+
Exit 0 when every station that ran passed, 1 when one failed, 2 on usage (no spec, no
|
|
23
|
+
`--draft`, an unreadable draft, a spec without the writing profile, an `--only` that names no
|
|
24
|
+
known station); under `--json` a usage error is one document, `{ spec, draft, error }`.
|
|
25
|
+
`--only` runs a subset, still in the fixed order. A finding names the draft line it points at
|
|
26
|
+
where there is one, quotes at most 80 characters of the draft, and never prints an absolute
|
|
27
|
+
path. A byte order mark at the start of the draft is ignored. A station that throws becomes one
|
|
28
|
+
failing finding, `station-<name>-crashed`, and the rest still run.
|
|
29
|
+
- `form`: word count against `writing.form.length` (only `unit: words` is measured; another unit
|
|
30
|
+
skips the station), and every `required_parts` entry present as an ATX heading of that text
|
|
31
|
+
(indented up to three spaces, closing `#`s allowed), or as a line starting `part:`, outside
|
|
32
|
+
code blocks.
|
|
33
|
+
- `terms`: every term in the new optional `writing.audience.terms`, other than those in `knows`,
|
|
34
|
+
is defined at its first appearance: in that sentence or the next, the term followed within six
|
|
35
|
+
words by `is`, `means`, `refers to` or a colon, or by a parenthesis. A mechanical proxy for a
|
|
36
|
+
definition, and documented as one. No `terms` list: skip.
|
|
37
|
+
- `claims`: every claim in the JSONL ledger at `writing.sources.ledger` (`text`, `source`,
|
|
38
|
+
optional `span`) still appears in the draft word for word, and has a real source; unsourced
|
|
39
|
+
claims warn instead under `unsourced_claim: warn`, and point at the draft line where the claim
|
|
40
|
+
appears. A missing ledger fails. The ledger is the list of claims: the station does not decide
|
|
41
|
+
what counts as one.
|
|
42
|
+
- `quotes`: every double-quoted span of four words or more appears word for word in a `quote` or
|
|
43
|
+
`story` segment of a marked material, never a private one; when the sentence names a quote
|
|
44
|
+
segment's speaker, by the full name or by its first word (when that word has two or more
|
|
45
|
+
letters and is not a common function word such as "the"), the span must come from that
|
|
46
|
+
speaker. A spec with `fiction: true` skips the station, since a character's dialogue is
|
|
47
|
+
invented rather than quoted.
|
|
48
|
+
- `private`: no run of eight words from a `private` segment appears in the draft. Segments of four
|
|
49
|
+
to seven words are checked whole; shorter ones are counted in one warning and never quoted.
|
|
50
|
+
- `dna`: with a current `writing.dna.scope_dir`, the draft is measured the way goldens are and
|
|
51
|
+
each feature compared with the scope's, from v ÷ 1.5 to the larger of v × 1.5 and v + 5; drift,
|
|
52
|
+
and an em dash where the scope has none (pointing at the first one), are warnings. No scope
|
|
53
|
+
folder: skip.
|
|
54
|
+
- `links`: inline, reference and bare links are well-formed http, https or mailto (a bare
|
|
55
|
+
`https://` with no host fails); relative links resolve to a file beside the draft; a `/` link
|
|
56
|
+
warns, since there is no site root to resolve it against; a full or collapsed reference needs
|
|
57
|
+
its definition. A bare `[label]` is a link only when its label is defined, so `[sic]`, `[x]` and
|
|
58
|
+
`[1]` are text. No network access.
|
|
59
|
+
- The runs ledger: each check appends `{ at, kind: "check", draft, draft_sha256, spec_sha256,
|
|
60
|
+
stations, verdict }` to `improvement.ledger`, with `draft` relative to the spec's folder. A run
|
|
61
|
+
with `--only` adds `partial: true`, is `not-improved` with the reason `partial run: <stations>`,
|
|
62
|
+
and is ignored by later verdicts. A full run is compared with the last full line for the same
|
|
63
|
+
draft: `one-shot` when there is none and every station passes; `improved` when that line failed
|
|
64
|
+
and every station passes now, with `change` naming exactly the stations that failed then and
|
|
65
|
+
pass now; otherwise `not-improved`, with a `reason` that says which case it is, such as "no
|
|
66
|
+
change since the last passing check" or "spec changed; failing stations: terms". The lines keep
|
|
67
|
+
lint's test 9 passing.
|
|
68
|
+
- New optional field `writing.audience.terms`: a list of real strings when present (test 1,
|
|
69
|
+
`writing-audience-terms`, naming a scalar that is not a list, an empty list, and each entry that
|
|
70
|
+
is not a string, is empty or is a placeholder). Absent, nothing changes.
|
|
71
|
+
- The worked examples each ship a draft that passes every station, with its claims ledger:
|
|
72
|
+
`examples/writing/essay/draft.md` and `examples/writing/story/draft.md`. Both specs now list
|
|
73
|
+
`audience.terms`, and their `required_parts` are the drafts' headings. The essay's interview
|
|
74
|
+
quotes now name their speaker `dana, an engineering manager`, and the essay links the survey
|
|
75
|
+
summary it cites. A test runs `check` on both. WRITING.md gains "Checking a draft": each station, what it cannot check, a findings table
|
|
76
|
+
per station held by a test to the ids the stations raise, and the ledger line.
|
|
77
|
+
|
|
78
|
+
## 0.5.0 (2026-09-29)
|
|
79
|
+
|
|
80
|
+
Scoped writer DNA. A writer does not have one voice: the same person writes differently for a
|
|
81
|
+
theology journal and a landing page. So a writer's voice is now kept per scope, a form, an
|
|
82
|
+
audience and a purpose, as a folder of goldens: real passages a person approved, each with a note
|
|
83
|
+
on the move it teaches and where it came from. A golden feeds only work that shares its scope, so
|
|
84
|
+
a passage that is right for one kind of writing never teaches its moves to another. hyperspec
|
|
85
|
+
measures each scope's style from its goldens (sentence and paragraph length, punctuation,
|
|
86
|
+
pronouns, signature words), counts and never judges, and still calls no model.
|
|
87
|
+
|
|
88
|
+
**No behavior change for existing specs.** Scoped DNA is opt-in through a new optional field,
|
|
89
|
+
`writing.dna.scope_dir`. A spec without it passes and fails exactly as it did in 0.4.0, and no
|
|
90
|
+
finding id changed: every id below is new.
|
|
91
|
+
|
|
92
|
+
- `hyperspec dna init <scope-dir> --writer W --form F --audience A --purpose P` writes a scope
|
|
93
|
+
folder: `scope.md` (writer, form, audience, purpose, optional notes) and a `goldens/` folder
|
|
94
|
+
holding a README on the golden file shape. It refuses to overwrite an existing `scope.md`, never
|
|
95
|
+
replaces a `goldens/README.md` that is already there, and
|
|
96
|
+
exits 2 with a plain message on a missing flag, a flag whose value is a placeholder, or a
|
|
97
|
+
parent folder that does not exist. Paths print as you gave them.
|
|
98
|
+
- A golden is one `.md` file directly in `goldens/`, other than `README.md`: frontmatter `why`
|
|
99
|
+
(the move it teaches), `approved_by` (a person; an approver starting `agent:` is refused,
|
|
100
|
+
because golden means a human approved it) and `source` are required, `approved_on` is optional,
|
|
101
|
+
and the body is the passage, verbatim. A `goldens/` folder that resolves outside its scope, such
|
|
102
|
+
as a symlink to another scope's goldens, is refused under test 5, naming where it leads.
|
|
103
|
+
- `hyperspec dna measure <scope-dir> [--json]` checks every golden and writes
|
|
104
|
+
`<scope-dir>/features.json`: the scope, each golden's path and SHA-256, and the features. If
|
|
105
|
+
the scope or any golden fails a check it writes nothing and exits 1, so a hollow or borrowed
|
|
106
|
+
golden is never measured in. The same goldens always produce the same bytes.
|
|
107
|
+
- The features: word count; sentence length in words (mean, median, 90th percentile); paragraph
|
|
108
|
+
length in sentences and in words; per-1000-word rates of commas, semicolons, colons, em dashes,
|
|
109
|
+
en dashes, exclamation marks, question marks, parentheses and quotation marks; contraction,
|
|
110
|
+
first-person singular, first-person plural and second-person rates; mean word length; and up to
|
|
111
|
+
15 signature words. Sentences and paragraphs are split the same way `segments init` splits
|
|
112
|
+
them.
|
|
113
|
+
- With `writing.dna.scope_dir`, `lint` checks that `scope.md` matches the spec's writer, form,
|
|
114
|
+
audience and purpose (test 1); that every golden the spec lists is one of the scope's goldens,
|
|
115
|
+
after following any symlink, and never a passage in a subfolder, in `README.md` or in another
|
|
116
|
+
kind of file (test 5); that every golden in the folder has its `why` (test 6), a person's
|
|
117
|
+
approval and a source (test 4) and a passage (test 1); and that `features.json` is exactly what
|
|
118
|
+
`dna measure` would write now (test 6). The stale finding names what differs: goldens added,
|
|
119
|
+
removed or changed, a changed `scope.md` field, an unknown format version, or a number edited by
|
|
120
|
+
hand. A `scope_dir` that is present but a placeholder fails test 1.
|
|
121
|
+
- New finding ids, all starting `writing-dna-`: `scope-dir`, `scope-missing`,
|
|
122
|
+
`scope-file-<field>` (a scope's `scope.md` lacks writer, form, audience or purpose),
|
|
123
|
+
`scope-mismatch-<field>`, `goldens-missing`, `goldens-empty`, `goldens-outside`,
|
|
124
|
+
`golden-unreadable`, `golden-frontmatter`, `golden-empty`, `golden-approved-by`,
|
|
125
|
+
`golden-approved-by-agent`, `golden-source`, `golden-leak`, `golden-why`, `features-missing` and
|
|
126
|
+
`features-stale`. Every existing id is unchanged; in particular a spec whose own
|
|
127
|
+
`writing.dna.scope` lacks a field still reports `writing-dna-scope-form` (and `-audience`,
|
|
128
|
+
`-purpose`) as in 0.4.0. Every message names the scope folder as the spec wrote it and the
|
|
129
|
+
golden by its path inside the folder, never a folder on your machine. WRITING.md lists every one
|
|
130
|
+
with its test.
|
|
131
|
+
- `hyperspec init --profile writing` shows `scope_dir: TODO` in the `dna` block, which fails until
|
|
132
|
+
it names a scope folder or is deleted.
|
|
133
|
+
- Two new exports from `@supersuit/hyperspec/writing`: `readScope`, which reads a scope folder
|
|
134
|
+
and returns `{ scope, goldens, findings }` without throwing, and `measureFeatures`, which takes
|
|
135
|
+
an array of passages and returns the features `dna measure` writes.
|
|
136
|
+
- The essay example takes its voice from a scope folder,
|
|
137
|
+
`examples/writing/dna/essay-new-managers-teach/`, with three goldens and a measured
|
|
138
|
+
`features.json`. Its two goldens moved there from `examples/writing/essay/goldens/`, and a third
|
|
139
|
+
was added. The story example keeps its goldens in the spec with no scope folder, and still
|
|
140
|
+
passes.
|
|
141
|
+
- WRITING.md gains a Scoped DNA section: why a writer's DNA is scoped, the folder shape, the
|
|
142
|
+
golden file, both commands with their output, what each feature measures and what it is for,
|
|
143
|
+
staleness, naming a scope in a spec, every finding with its test, and the exports. README and
|
|
144
|
+
SPEC.md point at it.
|
|
145
|
+
|
|
3
146
|
## 0.4.0 (2026-09-29)
|
|
4
147
|
|
|
5
148
|
Marking materials. Before a writing spec can pass, every material it draws on (a brain dump, a
|
package/README.md
CHANGED
|
@@ -26,13 +26,16 @@ improvement ledger. Every test is defined in [SPEC.md](SPEC.md).
|
|
|
26
26
|
| `hyperspec init <file> [--title T] [--kind K]` | Write a new hyperspec skeleton. Refuses to overwrite an existing file. |
|
|
27
27
|
| `hyperspec init <file> --profile writing [--title T] [--form F] [--fiction]` | Write a writing-spec skeleton, every block shown with placeholders. |
|
|
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
|
+
| `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
|
+
| `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. |
|
|
29
32
|
| `hyperspec recipe check <output-or-recipe>` | Check that a recipe records everything the standard asks for. |
|
|
30
33
|
| `hyperspec recipe approve <recipe> --by <slug>` | Record who approved the output. |
|
|
31
34
|
| `hyperspec reproduce <recipe> [--restore]` | Re-check every hash the recipe recorded. Never runs a model. |
|
|
32
35
|
| `hyperspec regenerate <recipe> --out <path> --clicker <slug> <one change> [--run cmd]` | Make a child recipe from a parent and one named change, rerunning only the stages it reaches. |
|
|
33
36
|
| `hyperspec compare <child-recipe> --doctor cmd` | Grade a child and its parent through one doctor against one spec. |
|
|
34
37
|
|
|
35
|
-
Every command except `init` and `
|
|
38
|
+
Every command except `init`, `segments init` and `dna init` takes `--json`. `hyperspec --help` prints every flag.
|
|
36
39
|
|
|
37
40
|
## Exit codes
|
|
38
41
|
|
|
@@ -40,6 +43,10 @@ Every command except `init` and `segments init` takes `--json`. `hyperspec --hel
|
|
|
40
43
|
test fails, 3 when every test passes but a decision is still open (blocked), and 2 on a usage
|
|
41
44
|
error or a file that cannot be read, has broken frontmatter, or is not a hyperspec.
|
|
42
45
|
|
|
46
|
+
`hyperspec check` exits 0 when every station it ran passed, 1 when one failed, and 2 on a usage
|
|
47
|
+
error, a draft that cannot be read, or a spec without `profile: writing`. A spec that is not ready to check against exits with lint's
|
|
48
|
+
own code, 1 or 3, and no station runs.
|
|
49
|
+
|
|
43
50
|
The recipe commands use the same numbers: 0 ok, 1 a check failed or the child regressed, 2
|
|
44
51
|
usage or unreadable input, 3 pending, when `regenerate` has stages waiting for a runner.
|
|
45
52
|
`regenerate` also exits 1 when a stage it ran reported a failing verdict, or none. A stage it
|
|
@@ -130,7 +137,7 @@ The skeleton fails until every placeholder is real and its four open questions (
|
|
|
130
137
|
who speaks, who reads, what changes) are answered. The blocks, every field, and which test
|
|
131
138
|
each rule reports under are in [WRITING.md](WRITING.md). Two complete specs that pass with
|
|
132
139
|
nothing to warn ship in `examples/writing/`: an essay for new managers, and a short story with
|
|
133
|
-
two characters whose voices a judge can tell apart.
|
|
140
|
+
two characters whose voices a judge can tell apart. Each comes with a draft written to it.
|
|
134
141
|
|
|
135
142
|
### Marking materials
|
|
136
143
|
|
|
@@ -152,6 +159,47 @@ segment. The file format, the labels, and every finding are in
|
|
|
152
159
|
[WRITING.md](WRITING.md#marking-materials). A tool of your own can run the same check with
|
|
153
160
|
`import { readSegments } from "@supersuit/hyperspec/writing"`.
|
|
154
161
|
|
|
162
|
+
### Scoped DNA
|
|
163
|
+
|
|
164
|
+
A writer sounds different in a theology essay and on a landing page, so a writer's voice is kept
|
|
165
|
+
per scope (a form, an audience and a purpose), and each scope is a folder of goldens. A golden is a real
|
|
166
|
+
passage a person approved, with a note on the move it teaches and where it came from, and it
|
|
167
|
+
feeds only work that shares its scope.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
mkdir -p dna
|
|
171
|
+
npx @supersuit/hyperspec dna init dna/essay-new-managers-teach --writer example-author --form essay --audience "new managers" --purpose teach
|
|
172
|
+
npx @supersuit/hyperspec dna measure dna/essay-new-managers-teach
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`dna init` writes `scope.md` and a `goldens/` folder holding only a README. Add one file per
|
|
176
|
+
golden, then `dna measure` checks each golden and writes `features.json`: sentence and paragraph length, punctuation,
|
|
177
|
+
pronouns and signature words, measured and never judged. Name the folder in a spec as
|
|
178
|
+
`writing.dna.scope_dir` and `lint` checks that the scope matches the spec, that no golden comes
|
|
179
|
+
from another scope, and that the measurements are current. Without `scope_dir`, a spec lints as
|
|
180
|
+
it did in 0.4. The folder shape, every feature, and every finding are in
|
|
181
|
+
[WRITING.md](WRITING.md#scoped-dna); `readScope` and `measureFeatures` are exported from
|
|
182
|
+
`@supersuit/hyperspec/writing`.
|
|
183
|
+
|
|
184
|
+
### Checking a draft
|
|
185
|
+
|
|
186
|
+
Once a draft exists, `check` holds it to its spec with seven stations, none of which calls a
|
|
187
|
+
model or touches the network: `form` (length and required parts), `terms` (every word in the new
|
|
188
|
+
optional `writing.audience.terms` is defined where it first appears), `claims` (the claims
|
|
189
|
+
ledger still matches the draft, and every claim has a source), `quotes` (in nonfiction, every quotation of four
|
|
190
|
+
words or more is word for word in a marked quote), `private` (no run of eight words from a
|
|
191
|
+
private segment), `dna` (the draft's measured style beside its scope's, as warnings) and `links`
|
|
192
|
+
(well-formed, and relative links resolve).
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
npx @supersuit/hyperspec check essay.hyperspec.md --draft essay/draft.md
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
It lints the spec first, prints each station's pass, fail or skip, and appends one line to the
|
|
199
|
+
spec's runs ledger with a verdict. Both examples ship a draft that passes. What each station
|
|
200
|
+
checks and cannot check, and every finding, are in
|
|
201
|
+
[WRITING.md](WRITING.md#checking-a-draft).
|
|
202
|
+
|
|
155
203
|
## The format
|
|
156
204
|
|
|
157
205
|
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.6, the check command included, and cut 0.7 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.6.0** (2026-09-29)
|
|
113
113
|
|
|
114
114
|
## What makes a spec a hyperspec
|
|
115
115
|
|
|
@@ -220,7 +220,7 @@ Each row lists every condition under which `hyperspec lint` fails that test. A w
|
|
|
220
220
|
| 8 its adopters can push back on it | `feedback.issues` or `feedback.fork` missing |
|
|
221
221
|
| 9 it improves itself | `improvement.ledger` missing; a ledger path that exists and is not a readable file; if the ledger file exists, a line that is not a JSON object, a `verdict` outside one-shot, improved or not-improved, `improved` without `change`, `not-improved` without `reason`. A declared ledger that does not exist yet is a warning |
|
|
222
222
|
|
|
223
|
-
A profile adds its own conditions to these rows. The writing profile's are in [WRITING.md](WRITING.md#the-test-mapping), including the checks on each material's segments file: every material marked, every segment labeled from the closed set and matching its material word for word, the marking current (tests 1 and 4), and no spine claim citing a private or question segment (test 5).
|
|
223
|
+
A profile adds its own conditions to these rows. The writing profile's are in [WRITING.md](WRITING.md#the-test-mapping), including the checks on each material's segments file: every material marked, every segment labeled from the closed set and matching its material word for word, the marking current (tests 1 and 4), and no spine claim citing a private or question segment (test 5). A writing spec that names a writer-DNA scope folder with `writing.dna.scope_dir` is also checked against it: the scope matches the spec (test 1), every golden has a person's approval and a source (test 4), no golden comes from outside the scope (test 5), and every golden has its why and the scope's measured features are current (test 6). `scope_dir` is optional, and without it nothing changes. The writing profile also has an optional `writing.audience.terms`, the words a piece uses that its reader may not know: when present it must list real terms (test 1), and `hyperspec check` reads it to require each term's definition where the draft first uses it. Without it nothing changes.
|
|
224
224
|
|
|
225
225
|
## Exit codes
|
|
226
226
|
|
|
@@ -236,7 +236,7 @@ A profile adds its own conditions to these rows. The writing profile's are in [W
|
|
|
236
236
|
Every run of a skill that works from a hyperspec writes one line to the ledger named in `improvement.ledger`, one JSON object per line, with a `verdict`:
|
|
237
237
|
|
|
238
238
|
- **one-shot**: no intervention, nothing to learn.
|
|
239
|
-
- **improved**: the skill, the spec template, or a component library changed, and the line carries `change`, naming what changed.
|
|
239
|
+
- **improved**: the skill, the spec template, or a component library changed, and the line carries `change`, naming what changed. On a `kind: "check"` line, which `hyperspec check` writes, it means the draft now passes every station after the last full check of it failed, and `change` names those stations.
|
|
240
240
|
- **not-improved**: nothing changed, and the line carries `reason`, a reason a later session can argue with, such as "the correction was about this piece only" or "the fix belongs to a shipped skill and was filed as an issue".
|
|
241
241
|
|
|
242
242
|
Silence is not a verdict. A run that learned nothing has to say so and why, and a ledger line with none of the three verdicts fails the ninth test.
|
|
@@ -245,7 +245,7 @@ Silence is not a verdict. A run that learned nothing has to say so and why, and
|
|
|
245
245
|
|
|
246
246
|
A profile adds the rules for one kind of work on top of the nine tests. A spec opts in with a top-level `profile:` naming it. A profile never adds a tenth test: every finding it raises reports under one of the nine, with an id that starts with the profile's name, and the score stays out of nine. `lint` prints one more line for a profiled spec, how many of the profile's blocks are complete. A `profile` this linter does not know is a warning under test 7, and none of its rules are checked.
|
|
247
247
|
|
|
248
|
-
One profile ships: `writing`, for essays, chapters, letters, stories and anything else an agent drafts for a person to read. Its blocks, its fields, which test each rule reports under, `hyperspec init --profile writing`,
|
|
248
|
+
One profile ships: `writing`, for essays, chapters, letters, stories and anything else an agent drafts for a person to read. Its blocks, its fields, which test each rule reports under, `hyperspec init --profile writing`, marking materials with `hyperspec segments init`, and scoped writer DNA with `hyperspec dna init` and `hyperspec dna measure` are in [WRITING.md](WRITING.md).
|
|
249
249
|
|
|
250
250
|
## Recipes
|
|
251
251
|
|