unknown-knowledge 2.1.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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +167 -0
- package/cli/.gitkeep +0 -0
- package/cli/commands/init-copy.js +90 -0
- package/cli/commands/init.js +386 -0
- package/cli/init-copy.js +24 -0
- package/cli/init.js +24 -0
- package/cli/kit.manifest.yaml +256 -0
- package/cli/lib/copy-payload.js +334 -0
- package/cli/lib/generate-wrappers.js +162 -0
- package/package.json +36 -0
- package/payload/adapter-fixtures/README.md +53 -0
- package/payload/adapter-fixtures/html/EXPECTED.yaml +50 -0
- package/payload/adapter-fixtures/html/sample.html +38 -0
- package/payload/adapter-fixtures/md/EXPECTED.yaml +65 -0
- package/payload/adapter-fixtures/md/sample.md +32 -0
- package/payload/adapter-fixtures/pdf/EXPECTED.yaml +45 -0
- package/payload/adapter-fixtures/pdf/sample.pdf +0 -0
- package/payload/adapter-fixtures/txt/EXPECTED.yaml +31 -0
- package/payload/adapter-fixtures/txt/sample.txt +18 -0
- package/payload/docs/README.md +102 -0
- package/payload/docs/boundaries.md +60 -0
- package/payload/docs/ci-wiring.md +109 -0
- package/payload/docs/steward-guide.md +238 -0
- package/payload/engine/audit.js +34 -0
- package/payload/engine/commands/audit.js +289 -0
- package/payload/engine/commands/derive.js +334 -0
- package/payload/engine/commands/ingest.js +124 -0
- package/payload/engine/commands/log-entry.js +85 -0
- package/payload/engine/commands/phoenix.js +206 -0
- package/payload/engine/commands/preflight.js +530 -0
- package/payload/engine/commands/resolve.js +1678 -0
- package/payload/engine/commands/survey-map.js +351 -0
- package/payload/engine/commands/validate-values.js +315 -0
- package/payload/engine/commands/validate.js +1426 -0
- package/payload/engine/derive.js +34 -0
- package/payload/engine/ingest.js +34 -0
- package/payload/engine/lib/anchor-signatures.js +126 -0
- package/payload/engine/lib/boot.js +39 -0
- package/payload/engine/lib/call-numbers.js +133 -0
- package/payload/engine/lib/cli.js +147 -0
- package/payload/engine/lib/coverage.js +849 -0
- package/payload/engine/lib/decomposition.js +225 -0
- package/payload/engine/lib/derived.js +494 -0
- package/payload/engine/lib/engine-refusal.js +40 -0
- package/payload/engine/lib/exit-codes.js +14 -0
- package/payload/engine/lib/extractor-kinds.js +955 -0
- package/payload/engine/lib/format-adapters.js +802 -0
- package/payload/engine/lib/id-grammars.js +178 -0
- package/payload/engine/lib/iso-date.js +55 -0
- package/payload/engine/lib/kit-root.js +101 -0
- package/payload/engine/lib/load-stores.js +1624 -0
- package/payload/engine/lib/log-entry.js +196 -0
- package/payload/engine/lib/phoenix.js +628 -0
- package/payload/engine/lib/scoring.js +150 -0
- package/payload/engine/lib/suppressions.js +172 -0
- package/payload/engine/lib/time-verdicts.js +282 -0
- package/payload/engine/lib/usage-error.js +14 -0
- package/payload/engine/lib/validate-record.js +504 -0
- package/payload/engine/log-entry.js +34 -0
- package/payload/engine/phoenix.js +39 -0
- package/payload/engine/preflight.js +34 -0
- package/payload/engine/resolve.js +34 -0
- package/payload/engine/survey-map.js +34 -0
- package/payload/engine/validate-values.js +34 -0
- package/payload/engine/validate.js +34 -0
- package/payload/extractor-fixtures/.gitkeep +0 -0
- package/payload/extractor-fixtures/README.md +29 -0
- package/payload/extractor-fixtures/swift/strings-keys/EXPECTED.yaml +8 -0
- package/payload/extractor-fixtures/swift/strings-keys/sample.strings +15 -0
- package/payload/extractor-fixtures/swift/swift-const-array/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/swift/swift-const-array/sample.swift +21 -0
- package/payload/extractor-fixtures/swift/swift-enum/EXPECTED.yaml +8 -0
- package/payload/extractor-fixtures/swift/swift-enum/sample.swift +30 -0
- package/payload/extractor-fixtures/swift/yaml-keys/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/swift/yaml-keys/sample.yaml +23 -0
- package/payload/extractor-fixtures/swift/yaml-map-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/swift/yaml-map-keys/sample.yaml +15 -0
- package/payload/extractor-fixtures/ts/dir-modules/EXPECTED.yaml +12 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/alpha.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/beta.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/gamma.widget.ts +1 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/helpers/format.ts +3 -0
- package/payload/extractor-fixtures/ts/dir-modules/sample-modules/widgets.test.ts +2 -0
- package/payload/extractor-fixtures/ts/json-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/json-keys/sample.json +5 -0
- package/payload/extractor-fixtures/ts/json-map-keys/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/json-map-keys/sample.json +13 -0
- package/payload/extractor-fixtures/ts/ts-const-array/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/ts/ts-const-array/sample.ts +13 -0
- package/payload/extractor-fixtures/ts/ts-enum/EXPECTED.yaml +7 -0
- package/payload/extractor-fixtures/ts/ts-enum/sample.ts +11 -0
- package/payload/extractor-fixtures/ts/ts-object-keys/EXPECTED.yaml +6 -0
- package/payload/extractor-fixtures/ts/ts-object-keys/sample.tsx +23 -0
- package/payload/extractor-fixtures/ts/ts-union/EXPECTED.yaml +5 -0
- package/payload/extractor-fixtures/ts/ts-union/sample.ts +9 -0
- package/payload/hooks/pre-commit +37 -0
- package/payload/hooks/reverse-lookup +66 -0
- package/payload/package.json +3 -0
- package/payload/protocol/.gitkeep +0 -0
- package/payload/protocol/AGENTS.md +239 -0
- package/payload/protocol/derived-layer.md +174 -0
- package/payload/protocol/new-kind-pipeline.md +179 -0
- package/payload/protocol/registry-warrant.md +162 -0
- package/payload/protocol/skills/kb-build.md +303 -0
- package/payload/protocol/skills/knowledge-audit.md +183 -0
- package/payload/protocol/skills/knowledge-bootstrap.md +229 -0
- package/payload/protocol/skills/knowledge-reflect.md +397 -0
- package/payload/schemas/catalog.schema.json +32 -0
- package/payload/schemas/decision-entry.schema.json +122 -0
- package/payload/schemas/finding.schema.json +77 -0
- package/payload/schemas/gap.schema.json +52 -0
- package/payload/schemas/graduation-categories.schema.json +64 -0
- package/payload/schemas/knowledge-leaf.schema.json +194 -0
- package/payload/schemas/miss.schema.json +45 -0
- package/payload/schemas/ontology-concept.schema.json +115 -0
- package/payload/schemas/phoenix-event.schema.json +76 -0
- package/payload/schemas/registry.schema.json +57 -0
- package/payload/schemas/rules.schema.json +14 -0
- package/payload/schemas/survey-scope.schema.json +23 -0
- package/payload/templates/decisions/_catalog.yaml +7 -0
- package/payload/templates/decisions/_registries/graduation-categories.yaml +42 -0
- package/payload/templates/decisions/phoenix-event.yaml +74 -0
- package/payload/templates/decisions/reflect-mint-proposal.yaml +100 -0
- package/payload/templates/decisions/registry-minting.yaml +58 -0
- package/payload/templates/decisions/trust-graduation.yaml +120 -0
- package/payload/templates/decisions/trust-revocation.yaml +106 -0
- package/payload/templates/knowledge/_catalog.yaml +9 -0
- package/payload/templates/knowledge/_registries/anchor.yaml +42 -0
- package/payload/templates/knowledge/_registries/authority-tiers.yaml +32 -0
- package/payload/templates/knowledge/_registries/domains.yaml +43 -0
- package/payload/templates/knowledge/_registries/form.yaml +38 -0
- package/payload/templates/knowledge/_registries/jurisdictions.yaml +20 -0
- package/payload/templates/knowledge/_registries/operations.yaml +18 -0
- package/payload/templates/knowledge/_registries/stage.yaml +53 -0
- package/payload/templates/knowledge/_rules.yaml +6 -0
- package/payload/templates/new-kind/README.md +107 -0
- package/payload/templates/new-kind/descriptor.example.yaml +18 -0
- package/payload/templates/new-kind/fixture/EXPECTED.yaml +6 -0
- package/payload/templates/new-kind/fixture/demo-anchor.list +2 -0
- package/payload/templates/new-kind/fixture/sample.list +7 -0
- package/payload/templates/new-kind/parser.example.js +98 -0
- package/payload/templates/ontology/_catalog.yaml +6 -0
- package/payload/templates/ontology/_rules.yaml +6 -0
- package/payload/wrappers/cursor.mdc +15 -0
- package/payload/wrappers/pointer.md +10 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# AGENTS.md — navigation contract + runtime loop (PRD §7)
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`ontology/…`, `engine/…`, `protocol/…`). In the kit repo
|
|
5
|
+
> itself these live under `payload/`. Commands are written to run from the
|
|
6
|
+
> **repo root** with the kit dir at its default name `unknown-knowledge/`;
|
|
7
|
+
> substitute your chosen kit dir name if it differs.
|
|
8
|
+
|
|
9
|
+
You are a coding agent in a repo seeded with the unknown-knowledge kit: three
|
|
10
|
+
YAML stores that map the system, a deterministic engine that checks the map,
|
|
11
|
+
and this protocol. This file is the platform-agnostic contract — per-platform
|
|
12
|
+
wrapper files are thin pointers here. Follow it on every request.
|
|
13
|
+
|
|
14
|
+
Two `--root` conventions, stated once:
|
|
15
|
+
|
|
16
|
+
- Every store-reading CLI (`resolve.js`, `preflight.js`, `validate.js`,
|
|
17
|
+
`validate-values.js`, `audit.js`, `survey-map.js`) takes `--root` as the
|
|
18
|
+
**repo root** (default: cwd). The stores are auto-located at
|
|
19
|
+
`<root>/unknown-knowledge/`; source-of-truth pointers resolve against the
|
|
20
|
+
repo root (§9.1).
|
|
21
|
+
- `log-entry.js` takes `--root` as the **kit dir** (the directory containing
|
|
22
|
+
`logs/`), e.g. `--root unknown-knowledge`.
|
|
23
|
+
|
|
24
|
+
## The SSOT contract — the map is never the fact
|
|
25
|
+
|
|
26
|
+
Stores hold **claims and pointers**; source files hold **facts**. Prose in
|
|
27
|
+
any store — summaries, definitions, even `enumerates` values — is navigation,
|
|
28
|
+
never truth. The rules that follow from this:
|
|
29
|
+
|
|
30
|
+
- **Always follow the pointer and read the source.** Never answer from a
|
|
31
|
+
concept's prose or its `enumerates` values; they exist so the engine can
|
|
32
|
+
diff them against the artifact, not so you can skip the read.
|
|
33
|
+
- **Reference by concept ID and path, never by copied value.** Anything you
|
|
34
|
+
write into a store or a log carries `K-NNN` / `D-NNN` / leaf accession
|
|
35
|
+
(`L-NNNNNN`) and
|
|
36
|
+
file paths — copying a value out of source into prose mints a second,
|
|
37
|
+
uncheckable claim.
|
|
38
|
+
- **Trust is per-run.** A verdict is valid for the run that computed it;
|
|
39
|
+
never cache or carry one across sessions (D-011 — a stale "trusted" is a
|
|
40
|
+
false all-clear).
|
|
41
|
+
|
|
42
|
+
## Store navigation contract
|
|
43
|
+
|
|
44
|
+
Three stores, one navigational grammar: **`_catalog.yaml` → `_rules.yaml` →
|
|
45
|
+
entries** (`classes/*.yaml`, tree leaves, `entries/*.yaml`). Enter through
|
|
46
|
+
the catalog, honor the rules file, then read the entry the catalog names —
|
|
47
|
+
never grep the store tree cold, and never raw-traverse the repo (triage
|
|
48
|
+
`engine/survey-map.js` output instead).
|
|
49
|
+
|
|
50
|
+
| Store | Truth anchor | Points | Write gate |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| `ontology/` | the artifact (code) | inward — `source-of-truth` into the repo | proposal-first; updates travel with the code change |
|
|
53
|
+
| `knowledge/` | the world | outward — `citations` to external evidence | human-only; the kb-build skill is the sole write path |
|
|
54
|
+
| `decisions/` | the team | sideways — typed refs to concepts & leaves | gated append-mostly; see the authoring path below |
|
|
55
|
+
|
|
56
|
+
Cross-reference semantics (knowledge leaves, §3.2):
|
|
57
|
+
|
|
58
|
+
- **`class-elsewhere` is a redirect — follow it.** The content lives at the
|
|
59
|
+
target accession; the leaf you found is a signpost, not an answer.
|
|
60
|
+
- **`see-also` is context.** Related material; consult when useful, never a
|
|
61
|
+
substitute for the leaf you resolved.
|
|
62
|
+
- **`including` is standing room.** Candidate topics parked under a heading —
|
|
63
|
+
not authoritative, never citable as fact.
|
|
64
|
+
|
|
65
|
+
All cross-store references travel by ID (`used-by`, `confusable-with`,
|
|
66
|
+
`rationale`, `relates-to`, cross-refs) — content is never embedded across
|
|
67
|
+
store lines. A `confusable-with` entry on a resolved concept is an explicit
|
|
68
|
+
disambiguation: confirm you have the right concept before acting on it.
|
|
69
|
+
|
|
70
|
+
**`knowledge/derived/` is engine output, not a store.** Browse trees and the
|
|
71
|
+
resolution index are regenerated by `engine/derive.js` and deleting them loses
|
|
72
|
+
nothing. Two rules when you read one: never hand-edit a derived file, and
|
|
73
|
+
**never cite a synthesized call number** (`SPO/ODD/REF·L-000117`) — it is a
|
|
74
|
+
display string naming a position in one projection, it differs between trees,
|
|
75
|
+
and the citable half is the accession inside it. See
|
|
76
|
+
`protocol/derived-layer.md`.
|
|
77
|
+
|
|
78
|
+
## The runtime loop (every request)
|
|
79
|
+
|
|
80
|
+
`RESOLVE → PREFLIGHT → GATHER → ACT → RECORD`
|
|
81
|
+
|
|
82
|
+
### 1. RESOLVE — request terms → concepts
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
node unknown-knowledge/engine/resolve.js "export format" --json --root .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Query terms are positional (joined into one query); results come scored with
|
|
89
|
+
`source-of-truth` pointers, `confusable-with` disambiguation, and knowledge
|
|
90
|
+
entry points. Exit 0 = the lookup ran (hits or none); exit 2 = it never ran —
|
|
91
|
+
stop, that is an engine failure, not an empty result.
|
|
92
|
+
|
|
93
|
+
**Zero resolution is a normal outcome** (common in month one — bootstrap is
|
|
94
|
+
deliberately non-exhaustive). Proceed **without store claims**: fall back to
|
|
95
|
+
search within the paths `survey-scope.yaml` includes, and append a
|
|
96
|
+
`retrieval-miss` finding (RECORD, below) only when the topic plausibly should
|
|
97
|
+
be mapped — an unmapped area the scope excludes is expected, not a miss.
|
|
98
|
+
|
|
99
|
+
### 2. PREFLIGHT — deterministic verdicts on what you resolved
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
node unknown-knowledge/engine/preflight.js --concepts K-101,K-102 --json --root .
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
One verdict per concept — `trusted` / `quarantined` / `unknown` — computed by
|
|
106
|
+
engine code, never by your judgment. Store-wide failures degrade every
|
|
107
|
+
requested verdict to `unknown`. Exit codes: 0 all trusted, 1 quarantines
|
|
108
|
+
present, 2 engine failure / check-never-ran. What you DO with a verdict is
|
|
109
|
+
the conduct policy below. Add `--log --today <YYYY-MM-DD>` so quarantine
|
|
110
|
+
findings auto-append (one fragment per quarantined concept).
|
|
111
|
+
|
|
112
|
+
With an empty/omitted `--concepts`, preflight validates store health only and
|
|
113
|
+
exits on the store verdict — the zero-resolution branch still preflights.
|
|
114
|
+
|
|
115
|
+
### 3. GATHER — read the fact, not the map
|
|
116
|
+
|
|
117
|
+
Follow each resolved concept's `source-of-truth` pointer and **read the
|
|
118
|
+
file**. One targeted read per fact. Knowledge leaves: read the leaf body and
|
|
119
|
+
follow `class-elsewhere` redirects. Never substitute a summary, an
|
|
120
|
+
`enumerates` list, or a leaf heading for the artifact.
|
|
121
|
+
|
|
122
|
+
### 4. ACT — execute, then attribute before committing
|
|
123
|
+
|
|
124
|
+
Do the work. Before committing, reverse-look-up every file you changed:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
node unknown-knowledge/engine/resolve.js --paths src/registry/export-formats.ts,src/types/color-space.ts --json --root .
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This lists every concept whose pointer covers a changed path (folder pointers
|
|
131
|
+
match nested files). **Update those concepts in the same commit** — the store
|
|
132
|
+
change rides your normal PR — and re-run both validators filtered to them:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
node unknown-knowledge/engine/validate.js --concepts K-101,K-108 --root .
|
|
136
|
+
node unknown-knowledge/engine/validate-values.js --concepts K-101,K-108 --root .
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Exit 0 = clean; exit 1 = findings — fix the store or the code before
|
|
140
|
+
committing; exit 2 = the check never ran — stop. These validators are
|
|
141
|
+
blocking-grade; `engine/audit.js` is advisory (proposals for review) and is
|
|
142
|
+
never a gate.
|
|
143
|
+
|
|
144
|
+
Where the client has wired the seeded hooks (`hooks/pre-commit`,
|
|
145
|
+
`hooks/reverse-lookup`), both of these run automatically: the pre-commit hook
|
|
146
|
+
runs the blocking validation before the commit exists, and the reverse-lookup
|
|
147
|
+
hook runs the `--paths` lookup over the staged diff. Each is a thin wrapper
|
|
148
|
+
around the command above and exits with its code, unchanged — so a wired repo
|
|
149
|
+
enforces this step mechanically rather than depending on you to remember it.
|
|
150
|
+
Run the commands yourself anyway: seeing the findings before the commit is
|
|
151
|
+
cheaper than being refused by it, and a hook the client never wired enforces
|
|
152
|
+
nothing.
|
|
153
|
+
|
|
154
|
+
### 5. RECORD — append findings when a trigger fires
|
|
155
|
+
|
|
156
|
+
See capture obligations below. Findings, misses, and gaps are appended via
|
|
157
|
+
`engine/log-entry.js` — never by hand-editing YAML.
|
|
158
|
+
|
|
159
|
+
## Conduct-on-verdict policy (D-011)
|
|
160
|
+
|
|
161
|
+
> **CLIENT-EDITABLE.** Verdicts are deterministic engine facts; what a
|
|
162
|
+
> session does about one is policy in this markdown, which you (the client)
|
|
163
|
+
> own. The table below is the recommended default — quarantine-and-continue.
|
|
164
|
+
> A stricter shop may edit `quarantined` to fail-stop. What is NOT editable:
|
|
165
|
+
> the engine's verdicts, exit codes, and evidence — and a policy edit must
|
|
166
|
+
> never tell an agent to bypass a gate or trust quarantined claims.
|
|
167
|
+
|
|
168
|
+
| Verdict / outcome | Conduct (recommended default) |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `trusted` | Proceed. The verdict is fresh this run; never cache it. |
|
|
171
|
+
| `quarantined` | **Quarantine-and-continue**: continue the task, but do NOT trust the concept's claims — gather from the source artifact directly (falling back to survey-scoped search if the pointer itself is the problem), and make sure the quarantine finding was appended (run preflight with `--log --today <date>`; it does this for you). |
|
|
172
|
+
| `unknown` | Treat as unverified — draft/proposed concepts and store-wide degradations land here. Work from the source artifact; do not present store claims as checked. |
|
|
173
|
+
| exit 2 — engine failure / check-never-ran | **STOP.** A check that never ran is a blocking defect, never a silent pass. Report the engine error; do not proceed as if preflight passed. |
|
|
174
|
+
|
|
175
|
+
## Gate rules
|
|
176
|
+
|
|
177
|
+
- **All store mutations beyond logging are human-gated.** Agents draft;
|
|
178
|
+
humans approve through the normal PR gate. Logging (`logs/`) is the one
|
|
179
|
+
agent-writable surface, and only via `engine/log-entry.js`.
|
|
180
|
+
- **Ontology** edits are proposal-first and travel with the code change they
|
|
181
|
+
describe (ACT step). **Knowledge** is written only through the kb-build
|
|
182
|
+
skill — cited, human-gated. **Decisions** follow the authoring path below.
|
|
183
|
+
- **Never wire a parser you authored into the validator in the same session**
|
|
184
|
+
(D-005). Unextractable anchors go to the miss-log; the governed path is
|
|
185
|
+
`protocol/new-kind-pipeline.md`.
|
|
186
|
+
- **Never bypass a gate to go green**: do not delete or edit findings to
|
|
187
|
+
unblock a merge, do not hand-edit log YAML, do not skip the ACT re-run,
|
|
188
|
+
do not pass `--no-verify` or unwire a hook to get a commit through,
|
|
189
|
+
treat `audit.js` output as advisory (never blocking), and do not carry a
|
|
190
|
+
cached verdict. Autonomy is graduated per change-category by recorded decision
|
|
191
|
+
(category `trust`), never assumed.
|
|
192
|
+
|
|
193
|
+
## Capture obligations — the five triggers
|
|
194
|
+
|
|
195
|
+
Append a finding whenever one fires; capture is cheap and judgment-free
|
|
196
|
+
(consolidation happens later, in reflect). The `trigger` vocabulary is closed
|
|
197
|
+
(`schemas/finding.schema.json`):
|
|
198
|
+
|
|
199
|
+
| Trigger | Signal |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `correction` | the user states the agent / a store is wrong |
|
|
202
|
+
| `recurrence` | the same thing is asked for repeatedly |
|
|
203
|
+
| `retrieval-struggle` | found, but slowly or indirectly (resolver missed; aliases lacking) |
|
|
204
|
+
| `retrieval-miss` | could not find it at all (and the topic plausibly belongs in scope) |
|
|
205
|
+
| `quarantine` | engine-attributed: preflight flagged a concept and the session proceeded degraded (auto-appended by `preflight.js --log`) |
|
|
206
|
+
|
|
207
|
+
Append with the helper — `--date` is mandatory and injected, never wall-clock:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
node unknown-knowledge/engine/log-entry.js create --log findings --date 2026-07-08 \
|
|
211
|
+
--root unknown-knowledge \
|
|
212
|
+
--entry '{"trigger":"correction","summary":"correction: K-101 src/registry/export-formats.ts","consulted":{"concepts":["K-101"]}}'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Each finding's `consulted:` refs ARE the consultation trail. Sibling logs,
|
|
216
|
+
same helper: `--log misses` (anchors no extractor kind can read) and
|
|
217
|
+
`--log gaps` (requests no protocol/skill could route).
|
|
218
|
+
|
|
219
|
+
**Capture content policy (§3.4 — not optional):** summaries carry concept IDs
|
|
220
|
+
and file paths only — **never verbatim user text, quoted session content, or
|
|
221
|
+
secrets**. The `session` field is an opaque ID. Committed fragments are
|
|
222
|
+
permanent git history in this repo and are reviewable content like any other
|
|
223
|
+
PR change.
|
|
224
|
+
|
|
225
|
+
## Decisions-authoring path (§3.5)
|
|
226
|
+
|
|
227
|
+
When your work surfaces a decision — a trade-off taken, a graduation of
|
|
228
|
+
trust, a scope call — it gets recorded, not lost in a PR description:
|
|
229
|
+
|
|
230
|
+
1. **Draft** a decision entry in `decisions/entries/` with a provisional
|
|
231
|
+
date-suffixed id (`D-2026-07-08-<slug>`), `status: proposed`, and
|
|
232
|
+
`relates-to` refs to the concepts/leaves/decisions it touches.
|
|
233
|
+
2. **Propose** it through the normal PR gate — anyone (agent or human) may
|
|
234
|
+
draft a proposed entry; that IS the decisions store's write path.
|
|
235
|
+
3. **Human gate**: the steward assigns the final `D-NNN` at acceptance
|
|
236
|
+
(minted within range, never renumbered once published). Status moves
|
|
237
|
+
`proposed → accepted → addressed → archived` (plus `rejected` /
|
|
238
|
+
`superseded`); transitions never rewrite `context`/`decision` — the store
|
|
239
|
+
is append-mostly, and supersession chains must resolve and stay acyclic.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# The derived layer: browse trees, call numbers, and the recall gate (UCS-1158)
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`knowledge/…`, `engine/…`, `protocol/…`). In the kit repo
|
|
5
|
+
> itself these live under `payload/`.
|
|
6
|
+
|
|
7
|
+
Everything discovery-shaped in this store is **derived**: computed from the flat
|
|
8
|
+
set of leaves, written into one directory, and thrown away without loss.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
knowledge/
|
|
12
|
+
├── _registries/ # governed vocabularies — AUTHORED
|
|
13
|
+
├── design-system/… # leaves — AUTHORED
|
|
14
|
+
└── derived/ # engine output — DISPOSABLE
|
|
15
|
+
├── index.json # the resolution index
|
|
16
|
+
├── tree.domain-form.md # browse tree, steward ordering
|
|
17
|
+
└── tree.form-domain.md # browse tree, agent ordering
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Regenerate it with the `derive` surface:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
node unknown-knowledge/engine/derive.js --root . --today 2026-08-16 --write
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Two verbs, and the read-only one is the default — the same shape `phoenix` uses:
|
|
27
|
+
|
|
28
|
+
| Verb | Effect | Exit |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `--check` (default) | compare the layer on disk against what the store projects | 0 up to date / 1 findings |
|
|
31
|
+
| `--write` | replace the directory with what the store projects | 0 written |
|
|
32
|
+
|
|
33
|
+
## Deleting it loses nothing
|
|
34
|
+
|
|
35
|
+
That is the design claim, and it is enforced rather than promised:
|
|
36
|
+
|
|
37
|
+
- **Nothing authored lives here.** No field, no id, no decision. Every byte is a
|
|
38
|
+
function of the leaves.
|
|
39
|
+
- **Nothing reads it back.** The loader skips `derived/` by name. Browse trees
|
|
40
|
+
are markdown under `knowledge/`, exactly like leaves, so the name is the only
|
|
41
|
+
thing distinguishing engine output from a record — and if the walk descended,
|
|
42
|
+
a generated tree would fail the leaf schema and the store's health would
|
|
43
|
+
depend on a directory whose whole contract is that it is disposable.
|
|
44
|
+
- **Regeneration is byte-identical.** Delete the directory, re-run `--write`,
|
|
45
|
+
and the bytes match. A round-trip test asserts exactly that; it fails the
|
|
46
|
+
moment something unreproducible starts living here.
|
|
47
|
+
- **A file no axis generates is a finding.** `derived-unexpected` fires on
|
|
48
|
+
anything in the directory the engine did not produce, because a regeneration
|
|
49
|
+
would delete it.
|
|
50
|
+
|
|
51
|
+
Never hand-edit a derived file. `--check` reports it as `derived-stale`, and the
|
|
52
|
+
next `--write` overwrites it.
|
|
53
|
+
|
|
54
|
+
### Commit it, or ignore it — both work
|
|
55
|
+
|
|
56
|
+
The kit does not decide this for you, because the two choices trade off real
|
|
57
|
+
things and the answer is local:
|
|
58
|
+
|
|
59
|
+
- **Commit it** and browse trees are readable on the forge, and a reviewer sees
|
|
60
|
+
a reclassification's effect in the diff. The cost is that every PR touching a
|
|
61
|
+
leaf also touches the trees, and a contributor who forgets to regenerate lands
|
|
62
|
+
a stale artifact — which `derive --check` catches in CI.
|
|
63
|
+
- **Ignore it** (`knowledge/derived/` in `.gitignore`) and the store's history
|
|
64
|
+
stays free of generated churn. The cost is that a reader has to run the
|
|
65
|
+
command to browse.
|
|
66
|
+
|
|
67
|
+
Either way nothing is lost, because nothing here is authored. If you commit it,
|
|
68
|
+
run `derive --check --today <date>` in CI so a stale tree is a failed build
|
|
69
|
+
rather than a misleading document.
|
|
70
|
+
|
|
71
|
+
## Plural browse trees
|
|
72
|
+
|
|
73
|
+
The store projects along **two axes**, from one flat set of leaves:
|
|
74
|
+
|
|
75
|
+
| Axis | Ordering | For |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `domain-form` | domain → form | stewards — subject matter first, the way a person holds a library in their head |
|
|
78
|
+
| `form-domain` | form → domain | agents — kind of knowledge first, narrowed by subject afterwards |
|
|
79
|
+
|
|
80
|
+
Plural is the point. The store's first life filed each leaf at one position in
|
|
81
|
+
one tree, and that position was also its identity — so a leaf in the wrong place
|
|
82
|
+
stayed there, because moving it broke every citation to it. Accession identity
|
|
83
|
+
removed that cost, and the derived layer spends the refund: a projection commits
|
|
84
|
+
to nothing, so there can be as many as there are useful reading orders.
|
|
85
|
+
|
|
86
|
+
A third axis is one row in `AXES` (`engine/lib/derived.js`). Nothing else names
|
|
87
|
+
an axis.
|
|
88
|
+
|
|
89
|
+
### Stale and draft leaves are annotated, never hidden
|
|
90
|
+
|
|
91
|
+
A demoted leaf appears in every tree it belongs in, wearing its reason:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
- **frontend/** (2)
|
|
95
|
+
- **runbook/** (1)
|
|
96
|
+
- `ENG/FRO/RUN·L-000171` Visual regression triage playbook — **demoted** (stage, time)
|
|
97
|
+
- stage: stage "draft" is pre-promotion — no moderator has certified this leaf's citations
|
|
98
|
+
- time: verified 154 day(s) ago, past the 90-day limit for volatile knowledge
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Hiding it would make the tree lie by omission: a steward would read an empty
|
|
102
|
+
shelf as "we know nothing about this", when the truth is "what we know has
|
|
103
|
+
rotted" — opposite calls to action. Demotion sorts a leaf last within its node
|
|
104
|
+
and does nothing else.
|
|
105
|
+
|
|
106
|
+
Both demotions come from the surfaces that already own them — `timeVerdict` and
|
|
107
|
+
`isPrePromotionStatus` — so a leaf cannot read stale in a tree and trusted in
|
|
108
|
+
the resolver.
|
|
109
|
+
|
|
110
|
+
**Time verdicts need `--today`.** Staleness is measured from an injected date,
|
|
111
|
+
never the wall clock. Without `--today` the time verdicts are `skipped` and every
|
|
112
|
+
artifact says so in its header; it is never a silent pass. Stage demotion needs
|
|
113
|
+
no date and still applies.
|
|
114
|
+
|
|
115
|
+
## Call numbers are display strings, never identities
|
|
116
|
+
|
|
117
|
+
A call number names a leaf's position in one projection:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
SPO/ODD/REF·L-000117 in the domain-first tree
|
|
121
|
+
REF/SPO/ODD·L-000117 the SAME leaf, in the form-first tree
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Cite the accession id. Never a call number.** A call number is the most
|
|
125
|
+
tempting thing in this layer to paste into a `see-also` — compact, readable,
|
|
126
|
+
positional, everything the retired dotted notation was. If that paste ever
|
|
127
|
+
resolved, the accession inversion would reverse itself one convenient citation at
|
|
128
|
+
a time, and references would break on reclassification again.
|
|
129
|
+
|
|
130
|
+
It cannot resolve, and the defense is structural:
|
|
131
|
+
|
|
132
|
+
1. **The grammar refuses it.** The middle dot (`·`) appears in no id space, and
|
|
133
|
+
a test checks every synthesized call number against every grammar in
|
|
134
|
+
`ID_GRAMMARS` — so a new id space that accepted them would fail the day it
|
|
135
|
+
was added.
|
|
136
|
+
2. **Nothing accepts one.** Citations are `leaf-ref`, accession-only. A call
|
|
137
|
+
number in a citation field is both a `pattern-mismatch` and an
|
|
138
|
+
`unresolved-ref`.
|
|
139
|
+
3. **The accession travels inside it.** The tempting thing to paste contains the
|
|
140
|
+
correct thing to paste.
|
|
141
|
+
|
|
142
|
+
The same leaf reads differently on each axis, and that is deliberate: a call
|
|
143
|
+
number describes a position, and a leaf holds one per projection. A string that
|
|
144
|
+
looked stable while changing meaning between trees would be worse than one that
|
|
145
|
+
visibly reorders.
|
|
146
|
+
|
|
147
|
+
## Embedding recall: the slot and the gate
|
|
148
|
+
|
|
149
|
+
Probabilistic recall has **exactly one architectural position**, declared in
|
|
150
|
+
`engine/lib/derived.js` as `RECALL_SLOT`:
|
|
151
|
+
|
|
152
|
+
| Property | Value | Why |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `location` | `derived` | recall lives in the disposable layer and nowhere else — deleting `derived/` deletes every probabilistic artifact the system has ever computed |
|
|
155
|
+
| `consulted` | `after-deterministic-exhausted` | recall runs only when the deterministic layer returns nothing; consulting it earlier would let a similarity score outrank a declared edge |
|
|
156
|
+
| `output` | `proposals` | it may propose |
|
|
157
|
+
| `citable` | `false` | a proposal is never a citation |
|
|
158
|
+
| `persistable` | `false` | a proposal never enters the store |
|
|
159
|
+
|
|
160
|
+
**The implementation is out of scope, deliberately.** This ticket ships the slot
|
|
161
|
+
and the gate; model selection and semantic search are not built here. What the
|
|
162
|
+
slot does is fix the position so it cannot be occupied somewhere worse. An
|
|
163
|
+
embedding cached in frontmatter would be a guess sitting in the same file as
|
|
164
|
+
cited facts, indistinguishable to every later reader — which is precisely the
|
|
165
|
+
failure the three constraints above prevent.
|
|
166
|
+
|
|
167
|
+
`gateProposal()` refuses **every** proposal, by construction. There is no
|
|
168
|
+
argument that admits one. A future recall implementation calls it, gets a
|
|
169
|
+
refusal, and the only route into the store remains the ordinary one: a human
|
|
170
|
+
reads the proposal and authors an ordinary leaf with citations, which a moderator
|
|
171
|
+
promotes. At that point the record is knowledge, and the probabilistic step is
|
|
172
|
+
history rather than provenance.
|
|
173
|
+
|
|
174
|
+
Nothing probabilistic persists or is cited without that gate.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# The new-kind pipeline (PRD §5.2) — the trust boundary
|
|
2
|
+
|
|
3
|
+
> Paths in this document are client-relative — relative to the vendored kit
|
|
4
|
+
> root after init (`schemas/…`, `templates/…`, `engine/…`, `protocol/…`). In
|
|
5
|
+
> the kit repo itself these live under `payload/`.
|
|
6
|
+
|
|
7
|
+
An extractor **kind** is a small deterministic recipe (~30-line parser) that
|
|
8
|
+
reads a value set out of a reified anchor. The shipped kind library covers the
|
|
9
|
+
common shapes (PRD §5.1); everything else surfaces as a **miss** — an anchor no
|
|
10
|
+
shipped kind can read. This document is the governed path from a miss to a new
|
|
11
|
+
kind. It is a trust boundary, not a convenience path: a subtly wrong parser
|
|
12
|
+
produces a false all-clear, which is worse than no check.
|
|
13
|
+
|
|
14
|
+
> **Hard rule (D-005): validators execute only vendored, versioned,
|
|
15
|
+
> test-covered code — never code authored in the session that runs it.**
|
|
16
|
+
> A kind drafted in a session is NEVER wired into the validator in that same
|
|
17
|
+
> session. It enters via the GATE step: a PR carrying the parser, its fixture
|
|
18
|
+
> tests, and a demo run, merged after human review. Agents draft; humans gate;
|
|
19
|
+
> code validates.
|
|
20
|
+
|
|
21
|
+
Before drafting any parser, weigh the alternative of **reifying the anchor
|
|
22
|
+
into a standard shape** (product principle 6): when a fact can't be extracted
|
|
23
|
+
because the code never reified it, the right proposal is often a registry/enum
|
|
24
|
+
in the code — pushing the system toward being describable — not a bespoke
|
|
25
|
+
parser.
|
|
26
|
+
|
|
27
|
+
## Entry point: the miss-log
|
|
28
|
+
|
|
29
|
+
The pipeline consumes `logs/misses/` — the demand-driven extractor backlog.
|
|
30
|
+
A miss entry is **one file per entry** (`logs/misses/<date>-<hex8>.yaml`,
|
|
31
|
+
D-010) so concurrent sessions never merge-conflict, written via the
|
|
32
|
+
append/transition helper (`engine/log-entry.js`), never by hand-editing YAML.
|
|
33
|
+
|
|
34
|
+
Fields, per `schemas/miss.schema.json`:
|
|
35
|
+
|
|
36
|
+
| Field | Req. | Meaning |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `schema-version` | yes | integer ≥ 1; stamped by the helper (§3.5, additive-only evolution) |
|
|
39
|
+
| `date` | yes | ISO date the miss was recorded (injected — never wall-clock) |
|
|
40
|
+
| `path` | yes | root-relative path of the anchor no kind can read |
|
|
41
|
+
| `shape` | yes | shape description — enough for this pipeline to draft a parser; paths and structure only, never file contents verbatim |
|
|
42
|
+
| `session` | no | opaque platform/session hint — an ID, never quoted session content |
|
|
43
|
+
| `status` | yes | `open → proposed → resolved / rejected`; re-open-not-duplicate |
|
|
44
|
+
| `verified` | — | stamped by the transition helper when the entry resolves (validator re-run passed); removed on re-open |
|
|
45
|
+
| `reason` | — | required on rejection; travels only with `rejected` |
|
|
46
|
+
| `occurrences` | — | re-open dates: recurrences re-open the same entry, never duplicate |
|
|
47
|
+
|
|
48
|
+
Lifecycle invariants. The schema gate (`engine/lib/validate-record.js`)
|
|
49
|
+
enforces exactly two of them on any fragment, hand-edited or not, matching
|
|
50
|
+
what the transition helper enforces on its write path — on these two the
|
|
51
|
+
gates cannot disagree:
|
|
52
|
+
`verified` ⇔ status `resolved`, both directions; `rejected` ⇒ non-empty
|
|
53
|
+
`reason`, and `reason` travels only with `rejected`.
|
|
54
|
+
The rest is **helper-only**: only the transition helper's write path drops
|
|
55
|
+
`verified`/`reason` on re-open and appends the re-open date to `occurrences`
|
|
56
|
+
— a hand-edited fragment missing an occurrence entry still validates clean,
|
|
57
|
+
which is one more reason fragments are written via the helper, never by hand.
|
|
58
|
+
|
|
59
|
+
**Capture content policy (§3.4):** miss entries carry concept IDs and file
|
|
60
|
+
paths only — never verbatim user text, quoted session content, or secrets.
|
|
61
|
+
Committed fragments are permanent git history.
|
|
62
|
+
|
|
63
|
+
## The six steps
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
1. SURVEY read-only: the bootstrap/reflect agent inventories anchor shapes
|
|
67
|
+
2. MATCH configure concepts from the shipped kind library
|
|
68
|
+
3. DRAFT for each miss: agent writes the parser
|
|
69
|
+
+ a test fixture (sample file → expected values, following
|
|
70
|
+
the shipped extractor-fixture template, D-009)
|
|
71
|
+
+ a demo run against the live anchor it was drafted for
|
|
72
|
+
4. GATE human review — fast, because the claim is mechanical
|
|
73
|
+
5. INTEGRATE parser lands as versioned, tested code (client zone of their repo;
|
|
74
|
+
kit library if the vendor harvests it for future inits)
|
|
75
|
+
6. RE-RUN concepts depending on the new kind emit last
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 1. SURVEY — inventory anchor shapes (read-only)
|
|
79
|
+
|
|
80
|
+
The bootstrap/reflect agent triages the survey-map artifact (never
|
|
81
|
+
raw-traverses the repo) and inventories the anchor shapes concepts point at.
|
|
82
|
+
Anchors with a shipped kind proceed to MATCH. Anchors with **kind-shaped
|
|
83
|
+
evidence but no kind** — a real registry the library can't read — become miss
|
|
84
|
+
entries, written via the helper (verified working invocation; `--date` is
|
|
85
|
+
mandatory and injected, never wall-clock):
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
node engine/log-entry.js create --log misses --date 2026-07-08 \
|
|
89
|
+
--entry '{"path":"config/regions.txt","shape":"plain-text list, one region code per line, # comments"}'
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
SURVEY consumes the misses already in the backlog too — never minting a
|
|
93
|
+
sibling for a known anchor:
|
|
94
|
+
|
|
95
|
+
- a recurrence of a **still-open** miss needs no transition and gets none:
|
|
96
|
+
`open → open` is illegal (the helper hard-errors), because the open entry
|
|
97
|
+
*is* the standing demand signal. The helper offers no occurrences-append
|
|
98
|
+
for open entries; the agent simply leaves the entry as-is and moves on.
|
|
99
|
+
- a recurrence of a **resolved or rejected** miss **re-opens the same entry**
|
|
100
|
+
(`transition --to open`), which appends the date to `occurrences` and drops
|
|
101
|
+
the stale `verified`/`reason`.
|
|
102
|
+
|
|
103
|
+
### 2. MATCH — configure from the shipped library first
|
|
104
|
+
|
|
105
|
+
Every anchor that a shipped kind *can* read gets an `enumerates` descriptor
|
|
106
|
+
(`kind` / `source` / `values`, plus `symbol`/`emit` where the kind needs them)
|
|
107
|
+
against the shipped library. Only what remains unmatched justifies DRAFT —
|
|
108
|
+
and even then, weigh reification (principle 6) before a bespoke parser.
|
|
109
|
+
|
|
110
|
+
### 3. DRAFT — parser + fixture + demo run
|
|
111
|
+
|
|
112
|
+
For each miss that survives MATCH, the agent drafts, from the shipped template
|
|
113
|
+
(`templates/new-kind/`, see its README):
|
|
114
|
+
|
|
115
|
+
1. **the parser** — a pure, deterministic function: source text in, value set
|
|
116
|
+
out; hard-errors loudly on anything it can't parse, and declares a
|
|
117
|
+
**syntactic envelope**, hard-erroring when out-of-envelope sentinels appear
|
|
118
|
+
in the matched span — a confident wrong parse is a false all-clear, the
|
|
119
|
+
D-005/D-012 failure class;
|
|
120
|
+
2. **a test fixture** — sample file → expected values, following the shipped
|
|
121
|
+
extractor-fixture template (D-009);
|
|
122
|
+
3. **a demo run** against the live anchor the miss recorded (`path`), with the
|
|
123
|
+
output attached to the PR.
|
|
124
|
+
|
|
125
|
+
The draft NEVER runs inside the validator in this session (D-005). The miss
|
|
126
|
+
entry transitions `open → proposed` when the draft PR exists.
|
|
127
|
+
|
|
128
|
+
### 4. GATE — human review
|
|
129
|
+
|
|
130
|
+
A human reviews the PR. The review is fast because the claim is mechanical:
|
|
131
|
+
parser + fixture + demo-run output — does the fixture cover the envelope, does
|
|
132
|
+
the demo run reproduce the live anchor's values, is the envelope honest about
|
|
133
|
+
what it rejects? Rejection transitions the miss `proposed → rejected` with a
|
|
134
|
+
`reason` (rejections record the reason, §8). A rejected miss that recurs
|
|
135
|
+
re-opens (`rejected → open`) — the backlog keeps the demand signal.
|
|
136
|
+
|
|
137
|
+
### 5. INTEGRATE — versioned, tested code
|
|
138
|
+
|
|
139
|
+
The merged parser lands as versioned, test-covered code in the client zone of
|
|
140
|
+
their repo (the vendor harvests it into the kit library only for *future*
|
|
141
|
+
inits — seeded-once, D-001). It is now vendored code the validator may
|
|
142
|
+
execute: this preserves D-014 (the engine never imports/evals/spawns repo
|
|
143
|
+
*content* at validate time — a new kind enters the engine's own reviewed code,
|
|
144
|
+
it is never dynamically loaded from the store or the scanned tree).
|
|
145
|
+
|
|
146
|
+
### 6. RE-RUN — dependent concepts emit last
|
|
147
|
+
|
|
148
|
+
Concepts whose `enumerates` descriptors depend on the new kind are (re)emitted
|
|
149
|
+
and validated last, once the kind is merged. A green validator re-run
|
|
150
|
+
transitions the miss `proposed → resolved`; the helper stamps `verified` with
|
|
151
|
+
the run date. A later regression or recurrence re-opens the same entry
|
|
152
|
+
(`resolved → open`, dropping `verified`, appending to `occurrences`).
|
|
153
|
+
|
|
154
|
+
## Miss lifecycle ↔ pipeline steps
|
|
155
|
+
|
|
156
|
+
| Transition | When |
|
|
157
|
+
|---|---|
|
|
158
|
+
| *(created `open`)* | SURVEY records an unextractable anchor |
|
|
159
|
+
| `open → proposed` | DRAFT produced parser + fixture + demo run; PR open |
|
|
160
|
+
| `proposed → resolved` (+ `verified`) | GATE approved, INTEGRATE merged, RE-RUN passed |
|
|
161
|
+
| `proposed → rejected` (+ `reason`) | GATE rejected the draft |
|
|
162
|
+
| `resolved → open` / `rejected → open` | recurrence — same entry re-opens, `occurrences` appended; `verified`/`reason` dropped |
|
|
163
|
+
|
|
164
|
+
These are exactly the legal transitions the helper enforces; any other move is
|
|
165
|
+
a hard error that leaves the fragment untouched.
|
|
166
|
+
|
|
167
|
+
## Drafting template
|
|
168
|
+
|
|
169
|
+
`templates/new-kind/` ships the drafting skeleton — six files: a
|
|
170
|
+
framework-agnostic parser module (whose CLI is the demo-run tool), a
|
|
171
|
+
descriptor example, a fixture pair (`fixture/sample.list` →
|
|
172
|
+
`fixture/EXPECTED.yaml`), a stand-in demo anchor
|
|
173
|
+
(`fixture/demo-anchor.list`), and a README that walks the demo run. Together
|
|
174
|
+
these cover the three DRAFT artifacts above (parser, fixture, demo run).
|
|
175
|
+
The template README also records one manual walkthrough of the
|
|
176
|
+
template against its own fixture (an honest seam: a documented manual
|
|
177
|
+
exercise, not CI — the kit's CI pins the template artifacts against each
|
|
178
|
+
other and replays the walkthrough's CLI runs so the transcripts can't rot
|
|
179
|
+
apart, but exercising a draft against a *live* anchor is always manual).
|