Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/2026-08-26-execution-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Three design calls worth recording:
Two known deviations, both already in the deferral register (`docs/open-items.md`):

- `contextStore` is a module-level mutable singleton, which
`docs/knowledge/variables-and-declarations.md:22` bans. Accepted because threading a store handle through
`docs/knowledge/harvested/variables-and-declarations.md:22` bans. Accepted because threading a store handle through
builder → runtime → every step would be a wide API change for no observable gain; logged in the design's
Deviation Ledger for Phase 10. Tests build their own `new ContextStore()` rather than asserting through the
singleton, which is shared by every file in a `bun test` run.
Expand Down
2 changes: 1 addition & 1 deletion .changeset/2026-08-27-configuration-review-pass-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ which is the whole of the `etc/core.api.md` diff:
- `Clock.sleep(ms, signal)` becomes `Clock.sleep(durationMs, signal)`. A bare `ms` is a unit with no concept
attached, and the report carried it two lines above `composeSignal(userSignal, timeoutMs)` — the same
package stating the same kind of quantity two different ways
(`docs/knowledge/naming-conventions.md:36`).
(`docs/knowledge/harvested/naming-conventions.md:36`).
- `Configuration.getDuration(key, fallback)` becomes `getDuration(key, fallbackMs)`. The accessor returns
and accepts milliseconds, and said so only in prose while its own private collaborator is named
`parseDurationMs`.
Expand Down
8 changes: 8 additions & 0 deletions .claude/skills/ci-preflight/run-ci.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ const STEPS = [
tier: 'install',
fix: 'bun install (then commit the updated bun.lock)',
},
{
// First of the gates, mirroring ci.yml: pure Node over Markdown, no build,
// so a corpus mistake reports in seconds rather than after the pipeline.
id: 'verify:knowledge-structure',
ci: 'Knowledge-corpus structure check',
cmd: 'bun run verify:knowledge-structure',
tier: 'gate',
},
{id: 'typecheck', ci: 'Typecheck', cmd: 'bun run typecheck', tier: 'build'},
{
id: 'lint',
Expand Down
250 changes: 178 additions & 72 deletions .claude/skills/knowledge-lookup/SKILL.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ jobs:
- name: Install (frozen lockfile)
run: bun install --frozen-lockfile

# First of the gates: pure Node over Markdown, no build, no dist/, so a
# corpus mistake reports in seconds instead of after the whole pipeline.
# Keeps docs/knowledge/'s two trees apart — no hand-written entry under
# harvested/, whose `<sub>` shas digest whole source files and so cannot
# record an edit; the next harvest would delete it silently. The companion
# drift report is deliberately NOT here: 16 of the 47 sources are a
# sibling styleguide repository that no CI checkout has.
- name: Knowledge-corpus structure check
run: bun run verify:knowledge-structure

- name: Typecheck
run: bun run typecheck

Expand Down
59 changes: 46 additions & 13 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ bun run verify:seam-1 # zero runtime dependencies in EVERY package,
bun run verify:sse-37 # no serde dependency and no reconnect path in core SSE
bun run verify:runtime-floor # tsconfig target vs package engines.node consistency
bun run verify:test-partition # the five files that keep tests/ and tests/node-conformance/ apart
bun run verify:knowledge-structure # docs/knowledge/'s two trees stay separate (see below)
bun run verify:reproducible-build # two clean builds of one source tree agree, dist/ and tarball (NFR-12)
bun run test:scripts # the gates' OWN tests (node --test scripts/*.test.mjs)
bun run audit # bun audit --audit-level=high --prod
Expand All @@ -134,10 +135,10 @@ bun run audit # bun audit --audit-level=high --prod
work is done — `bun run test` passing is not sufficient evidence.

`test:scripts` tests the *gates themselves* — the knowledge CLI, `verify-seam-1.mjs`, `verify-sse-37.mjs`,
`verify-test-partition.mjs`. Phase 10 made it a blocking CI step, closing `docs/open-items.md` H13. It was
not one before, and the proof that it should have been is that `knowledge.test.mjs` had been failing on
`main` since `36c3f96` with nobody noticing. A gate whose own logic degrades still exits 0, so nothing else
in the run would.
`verify-knowledge-structure.mjs`, `verify-test-partition.mjs`. Phase 10 made it a blocking CI step, closing
`docs/open-items.md` H13. It was not one before, and the proof that it should have been is that
`knowledge.test.mjs` had been failing on `main` since `36c3f96` with nobody noticing. A gate whose own logic
degrades still exits 0, so nothing else in the run would.

### HARD RULE — the `tests/` partition

Expand Down Expand Up @@ -179,41 +180,73 @@ passes. The gate checks this too.

## Documentation hierarchy

Four distinct trees, easy to confuse:
Five distinct trees, easy to confuse — `docs/knowledge/` being two of them:

| Path | Role |
|---|---|
| `docs/product-spec/` | **Normative.** Numbered requirements (`HTTP-7`, `SEAM-1`, `RETRY-13`, `NFR-5`, …). The source of truth. |
| `docs/sdk-design-nodejs/` | How each spec area maps to idiomatic TypeScript. Non-normative but binding by convention. |
| `docs/knowledge/` | Harvested styleguide + spec knowledge, topic-indexed (`INDEX.md`). Cited as "styleguide 6.7", "ch08". |
| `docs/knowledge/harvested/` | Harvested styleguide + spec knowledge, topic-indexed (`INDEX.md`). Cited as "styleguide 6.7", "ch08". Generated; never hand-edited. |
| `docs/knowledge/notes/` | What the implementation found, hand-written, role `review`. Overrides a harvested entry. |
| `docs/superpowers/specs/` + `plans/` | Per-phase design doc, task-by-task implementation plan, and a requirement-coverage checklist. |

`docs/product-spec/appendix-c-consolidated-normative-requirement-index.md` is the fastest way to locate a
requirement ID.

### Querying `docs/knowledge/`

`docs/knowledge/` is 39 topic files — never read a topic file whole when a filtered query
answers the question. `bun run knowledge` parses the corpus into entries and filters them; a requirement-ID
`docs/knowledge/` is two trees and 39 topics — never read a topic file whole when a filtered query
answers the question. `bun run knowledge` parses both trees into entries and filters them; a requirement-ID
query returns ~170 tokens against a ~5700-token file read.

```bash
bun run knowledge --req HTTP-13,HTTP-14,HTTP-15 # a whole task's IDs in one call (exact-token)
bun run knowledge --origin note --brief # start of a phase: everything the implementation found
bun run knowledge --prefix HTTP --section rules # an audit group: a whole ID family, uncapped
bun run knowledge --chapter 6 interface class # a "styleguide 6.7" citation
bun run knowledge --section conflicts --brief # open design-vs-styleguide calls; 6 entries corpus-wide
```

Different filters AND together, values within one filter OR; `--help` lists the rest. Each result carries its
`<sub>` provenance line — the citation for test-file headers and deferral notes, though styleguide paths are
absolute to a sibling repo and need their machine prefix stripped first. **A `--req` hit is not proof of
knowledge:** 255 of 645 IDs are named only by an appendix-B conformance roll-up, tagged `[appendix-B roll-up]`
in output; 386 have a substantive entry and 4 are cited nowhere at all (`--coverage` breaks this down). 15 of
the 39 topics carry no requirement ID at all and are reachable only via `--topic`/`--chapter`
absolute to a sibling repo and need their machine prefix stripped first — and a stable key, `<topic>/<8 hex>`,
digested from the entry text, which is how a note names the rule it overrides. **A `--req` hit is not proof of
knowledge:** 256 of 645 IDs are named only by an appendix-B conformance roll-up, tagged `[appendix-B roll-up]`
in output; 385 have a substantive entry and 4 are cited nowhere at all (`--coverage` breaks this down). 15 of
the 38 harvested topics carry no requirement ID at all and are reachable only via `--topic`/`--chapter`
(`--list-topics`). Every count in this paragraph moves when the corpus is edited, so
`scripts/knowledge.test.mjs` pins all four against the live corpus and its failure message names the two docs
to update alongside. No CI step gates corpus *content*; CI does run the CLI's own suite (`test:scripts`),
which parses the real corpus. The `.claude/skills/knowledge-lookup` skill carries the full workflow.

**Two trees, and the split is a CI gate.** `docs/knowledge/README.md` is the contract; the short version is
that `harvested/` is `knowledge-harvest`'s output and is never hand-edited, because a `<sub>` sha digests the
whole source file rather than the entry — an edit inside an entry changes no sha, and the next harvest
regenerates or duplicates it. Record what the implementation found in `docs/knowledge/notes/<topic>.md`
instead: role `review`, a manual `sha:` marker, and a backticked `<topic>/<8 hex>` key naming the harvested
rule, which makes that rule print `[overridden by notes/…]` in every query result.

`bun run verify:knowledge-structure` (blocking, in CI) keeps the trees apart: no `review` or invented role
under `harvested/`, no `Superseded` entry there, every harvested entry carrying a `<sub>` that cites one of
the three source roots `SOURCES.md` names, every note carrying `review`, and no `.md` stranded at the root of
`docs/knowledge/` — the CLI reads the two trees only, so a file there is invisible rather than wrong, and that
is exactly where a `--corpus`-less harvest run lands.

`bun run knowledge:drift` is the hand-run companion, deliberately not in CI. It reports source drift
(`OK` / `DRIFT` / `NOT VERIFIABLE` / `UNREADABLE` per `SOURCES.md` row) and stale note citations (a key no
entry carries any more). Not a gate: the styleguide root is a sibling repository at an absolute path, so 16 of
the 47 sources are absent from any CI checkout, and drift is normal — a design chapter a phase edits to record
an outcome *should* drift, and the fix is a re-harvest.

**A register is not harvested.** `docs/sdk-design-nodejs/10-deliberate-deviations-from-the-reference-contract.md`
and `docs/open-items.md` are ledgers that every phase appends to, so any harvest of one is a stale fraction of
it. Read them directly; `notes/deliberate-deviations.md` is the pointer. When you re-harvest, point the skill
at the harvested tree — `--corpus docs/knowledge/harvested` — and hand-move any `supersede` entry it emits
into `notes/`.

**Citations into the corpus** are written `docs/knowledge/harvested/<topic>.md:<line>`. `docs/superpowers/`
is the exception: its plans and specs are dated records of what was true when they were written, are never
retro-edited, and so still carry pre-split paths.

## Requirement-ID conventions (enforced by review, not tooling)

- Every source file opens with `// SPDX-License-Identifier: MIT` on **line 1** (NFR-13).
Expand Down
8 changes: 5 additions & 3 deletions docs/deviations.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ linked the two, and the numbering they share had no stated owner):
`file:line` evidence, and records which of §10's claims did not survive contact with the code.
- **A new deviation is recorded in neither.** It goes in the owning phase spec's own `## Deviation Ledger (for
Phase 10)` section; §10 is the consolidated **output** of those, not their intake.
- **Do not confuse either with `docs/knowledge/deliberate-deviations.md`.** Despite the near-identical name it
is a harvested corpus topic file queried by `bun run knowledge`, derived from an older revision of §10 and
currently stale. It is `knowledge-harvest`'s output and is never hand-edited as a ledger.
- **The corpus no longer carries a copy.** `docs/knowledge/deliberate-deviations.md` was a harvested topic
file derived from an older revision of §10 — a third of the register, mis-anchored, two entries false. It
was dropped on 2026-08-31: a register accumulates rows and a harvest of it is one stale revision, so §10 is
read directly. What remains under the corpus is a pointer, `docs/knowledge/notes/deliberate-deviations.md`,
which says exactly that.

Audited 2026-08-29 against `25-phase-10-deviation-reconciliation` @ `d8217af`; the audit's own changes landed
on that branch as `27fb81f`, which is the tree this file describes.
Expand Down
31 changes: 31 additions & 0 deletions docs/knowledge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# docs/knowledge/

Two trees, one query surface. `bun run knowledge` reads both; nothing else should read either by hand.

| Tree | Holds | Rule |
| --- | --- | --- |
| `harvested/` | What the source documents say. Roles `spec`, `design`, `styleguide`. | Generated by the `knowledge-harvest` skill. **Never hand-edited.** |
| `notes/` | What the implementation found. Role `review`, a manual `sha:` marker. | Hand-written. A note overrides the harvested entry it names. |

**Why `harvested/` is never hand-edited.** A `<sub>` line's sha digests the whole *source file*, not the
entry, so every entry harvested from one document carries the same value and an edit to an entry's text
changes no sha. The next harvest cannot see the edit: it regenerates the original text, or writes a
duplicate. A correction made in place is therefore scheduled for silent deletion. Make it in `notes/`.

**How a note names its target.** Every entry has a stable key, `<topic>/<8 hex>`, digested from the entry's
own text. A note cites that key; the CLI resolves it, tags the harvested entry `[overridden by notes/…]`,
and `bun run knowledge --key <key>` looks one up. The key changes exactly when the rule's text does — so a
re-harvest that rewords a rule breaks the citation on purpose, and `bun run knowledge:drift` reports it.

**A register is not harvested.** `docs/sdk-design-nodejs/10-deliberate-deviations-from-the-reference-contract.md`
and `docs/open-items.md` are ledgers every phase appends to; any harvest of one is a stale fraction of it.
Read them directly. `notes/deliberate-deviations.md` is the pointer.

**Gates.** `bun run verify:knowledge-structure` is blocking in CI and keeps the two trees apart.
`bun run knowledge:drift` is a hand-run report over source shas and note citations; it never fails a build.

Re-harvesting: `--corpus docs/knowledge/harvested`, always. The skill's default is this directory, which no
query reads — the structure gate rejects a topic file stranded here for that reason. A `supersede`
resolution the harvest emits must be moved to `notes/` by hand, or the gate rejects it too.

The workflow for reading and writing all of this is `.claude/skills/knowledge-lookup/SKILL.md`.
Loading
Loading