This commit is contained in:
2026-07-30 00:34:18 +06:00
commit 54c14a20be
33 changed files with 2730 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
# Ideas — parked, not dropped
One file per idea, self-contained enough to resume cold. Nothing here is committed to; presence is not
permission to build. An idea file exists so picking the thread back up costs **one read instead of one
re-derivation** — the whole justification for writing it while the context is still in hand.
## What goes where
| It is… | Where |
|---|---|
| an engine feature you might build (webmentions, gemtext, galleries) | `docs/exploration.md` catalog line, `/leaf` for a verdict |
| that same feature, but with a discussion worth not repeating | an idea file here, linked from the catalog line |
| the harness, agent workflow, token cost, tooling, process | here — `exploration.md` is engine-only |
| a decision already made | `docs/decisions.md` |
| a known code flaw deliberately unfixed | Latent list in `docs/state.md` |
| a durable fact, number, or link | `reference/` |
## Format
Five headings, present tense, terse. Copy an existing file. Required first lines:
```
# <title>
Status: parked | active | adopted → <where> | dropped: <one-line why>
Raised: YYYY-MM-DD
```
Keep `dropped` files — a one-line reason is the cheapest defence against relitigating it in four
months.
## Reading discipline
Exploratory scratch code may live here too; `verify.sh` never formats, vets, builds or budgets it, so
it does not have to compile.
Out of agent context by default, **this index included**. A file is opened when the human names that
idea, not otherwise: not swept, not listed to see what is here, not cited unasked. This index is for
you, not the agent; `verify.sh` keeps it honest without reading it into context.
## Index
- [specs-as-secondary-artifacts.md](specs-as-secondary-artifacts.md) — optional per-feature specs, derived by default, plus the named-test convention. **parked**
- [engine-design-review.md](engine-design-review.md) — open design decisions for a multi-type site; items graduate to ADRs one at a time. **parked**
- [token-conservation.md](token-conservation.md) — cut agent token cost without losing output quality. **parked**
+50
View File
@@ -0,0 +1,50 @@
# Engine design review — open items
Status: parked
Raised: 2026-07-28
One review, many decisions. Each item below graduates independently: when one is settled it becomes an
ADR (or a change to its owning doc) and is struck from this list. When the list empties, delete the
file. Graduated so far: site root external to the engine repo (ADR-0011), Effect as the sixth
primitive (ADR-0012), the cache validity model (ADR-0013), declared content types (ADR-0014),
NFC normalisation and slug derivation (ADR-0015), sequence position (ADR-0016), the settings cascade
(ADR-0017), taxonomies and feeds (ADR-0018), template composition (ADR-0019), feature locality (ADR-0027).
## Why it came up
The harness was written for a generic blog engine and then aimed at a site hosting blog posts,
webcomics, art, literary writing, standalone pages and IndieWeb status notes, with a featureset meant
to keep evolving. Several things that are cheap to decide now get expensive once content exists or the
first URL is published.
## Decide before Arc 1 writes code
**Pagination URL shape.** Undecided and permanent — `/posts/page/2/` versus a query parameter. ADR-0008
settled the bundle shape only, and ADR-0016 settled that a slug may contain slashes; this is the last
open piece of the permalink space.
## Decide during Arc 12, as the code arrives
**UI chrome strings and Bengali collation.** i18n covers content variants, not chrome ("Next chapter",
"Read more") — a small message catalog, decided before templates multiply. Separately, byte sort is
wrong for Bengali indexes: adopt collation, or decide explicitly that ordering is date-only.
## Cheap, whenever
**A `check` command in the engine.** Missing required fields per type, image without alt, broken
internal link, dangling `series` reference, orphaned asset, slug collision, non-normalised filename,
alias colliding with a live URL. A walk over already-loaded bundles. Explicitly *not* `verify.sh`:
that gate answers "is the engine sound", this answers "is my content sound", and it runs against a
site root the engine repo cannot see.
**Search as a static artifact.** A prebuilt index file shipped with the site needs no running service
— the most sovereign option available, and it satisfies ADR-0010 trivially because the index is
derived. An Effect (ADR-0012) builds it.
**No-JS reading experience.** Server-rendered prev/next always present; keyboard navigation and
prefetch as enhancement only. Decide before the comic reader exists, not after.
## Dropped
Binary assets in git. Now purely a decision about the site repo, outside the engine repo entirely, so
the harness has no stake in it.
+87
View File
@@ -0,0 +1,87 @@
# Specs as secondary artifacts, and named tests
Status: parked
Raised: 2026-07-28
## Why it came up
The harness is deliberately not an SDD framework: the goal is to maintain content and trust the harness
to keep the code minimal and maintainable, rather than to author requirements for every change. But two
things are missing that SDD would have given for free — a place to put a well-defined spec when one
already exists, and any trace from a code change back to the behaviour it was supposed to produce.
Proposal: per-feature specs as **secondary** artifacts. ADRs, `state.md` and the engine-wide contracts
stay primary. A spec may be written first (true SDD for a well-defined feature) or generated after the
fact from what was requested and what was built. Either way it can then be edited, and the edit is
implemented — flowing upward into the harness where it touches anything the harness owns.
## What is already established
- The harness has no per-feature artifact. A plan lives in the conversation; what survives is an ADR
plus a `state.md` delta. There is no way to ask later "which behaviour was this code meant to have".
- Tests are mandatory for `cmd/` and `internal/` changes but nothing ties a test to the rule it verifies.
`content-model.md` says a bundle key excludes language, and that a bundle supplying both `about.md`
and `about.en.md` is rejected — nothing checks a test exists for either.
- One fact, one place is enforced throughout (`docs/README.md` authority table). Specs must not become a
fourth copy of decisions.
## The non-overlapping slot
The only content a spec should hold is what nothing else does:
| Artifact | Holds |
|---|---|
| ADR | why a load-bearing choice was made, permanently |
| `state.md` | what exists right now |
| `architecture.md`, `content-model.md` | engine-wide shape and contract |
| **spec** | **per-feature observable behaviour: given X, the engine does Y** |
Acceptance criteria, in other words — which is also exactly the traceability gap. So the cheapest useful
spec is a list of criteria whose names are the test names, and the named-test convention below is the
subset of this proposal that can ship on its own.
## The rule that stops it rotting: two states, one owner each
A generated spec describes what exists; an edited spec describes what should exist. Flipping between
those per edit, with nothing marking which, is how spec systems rot — after three round trips nobody
knows whether a clause is a record or a requirement. So each spec carries a status and it cycles:
- **`derived`** — describes what exists. The code wins; a mismatch is a spec bug, fixed silently.
- **`authored`** — a human edited it, or wrote it first. The spec wins; a mismatch is unimplemented work.
The next implement pass brings the code into line and flips it back to `derived`.
`verify.sh` can surface `authored` specs as a warning — pending requirements become visible state rather
than a silent backlog. This mirrors the existing "if `state.md` disagrees with the code, the code wins"
rule, which works precisely because the direction is never ambiguous.
## Two things to get right or it is worse than nothing
**A derived spec must not paraphrase the code.** If it restates the implementation it carries no
information, costs tokens every feature, and goes stale instantly. Its value is the half the code cannot
hold: the request as made, the behaviour at the edges, what was deliberately not done. Capture the
request, not the diff.
**Not every change earns a spec.** A spec per one-line tweak is overhead. The natural threshold is the
one already enforced: a change that must ship a test is a change with observable behaviour worth pinning,
and the spec's criteria are that test's names. Changes below that line get an ADR or nothing.
## Upward flow needs no new machinery
An edited spec is just another request, so the existing conflict check (`CLAUDE.md` rule 9) applies
unchanged: contradicts an ADR or an engine contract → hard conflict, stop and surface; is a load-bearing
choice → it produces an ADR; is plain new behaviour → code plus spec, nothing else. "Flows upward" means
the spec is an *entry point* to the loop, not a parallel process.
## Cheapest next step
Two independent pieces, in order:
1. **Named tests, alone.** A line in `conventions.md`: a rule stated in an engine contract earns a test
named after it — `TestBundleKeyExcludesLanguage`, `TestDuplicateVariantRejected`. Zero
infrastructure, most of the traceability, and it makes the spec step later almost free because the
criteria already exist as test names.
2. **`specs/<feature>.md`**, one file per feature with a `Status:` line, an index like `ideas/`, excluded
from the Go gates the way `ideas/` and `reference/` are, read on demand and never swept.
Open question if this is adopted: whether a spec is ever deleted. Suggest not — a `derived` spec for a
shipped feature is the closest thing to living documentation of behaviour, and it is cheap to keep.
+49
View File
@@ -0,0 +1,49 @@
# Token conservation
Status: parked
Raised: 2026-07-28
## Why it came up
Development pace is limited by session and usage limits, not by typing speed. Cutting token cost
per feature buys more features per session. The goal is explicitly *conserve tokens without
lowering output quality* — not "be terse and worse".
## What is already established
Do not re-derive these.
- **Turn count dominates, not file size.** The whole context is re-sent on every tool call, so a
six-call verification sequence costs roughly 6× the context. Batching is the biggest lever.
- **`CLAUDE.md` is the most expensive file per byte in the repo** — it is re-sent every turn.
- **Agent prose is a large, entirely self-inflicted cost.** The target is density, not brevity: same
information, fewer words. Length follows content; padding, restatement, hedging and rhetorical
closers do not.
- Two accepted rules cost tokens on purpose and are worth keeping: hard rule 8 (docs ship with the
change) and the topic-ownership read floor. The ownership table is what keeps the floor cheap —
it sends you to one doc instead of a grep sweep.
## The six mechanisms, ranked by saving
1. Batch tool calls — one Bash call per phase, not per command.
2. Prose density in reports and replies — cut restatement and flourish, keep every finding, number and
caveat. Biggest win, costs nothing. Not a length cap: truncating information is not a saving.
3. Line ceiling on `CLAUDE.md` in `budgets.env`, gated like any other budget.
4. Targeted reads — `grep -n` plus `Read offset/limit`; whole-file reads only for the doc that
owns a rule being asserted.
5. Evidence proportional to risk — one case for a behaviour change, a full matrix only for a gate
or a security boundary.
6. Never re-read after `Edit`; run `verify.sh` once per feature, at the end.
## Open question — needs the human
**Subagents for fan-out search.** Dispatching "find every place X appears" to a subagent keeps its
file dumps out of the main context: you pay for the conclusion, not the search. A real multiplier
on exploration-heavy work. Currently disallowed unless explicitly requested, so it is a policy
call, not a judgment call.
## Cheapest next step
Apply 16 as one batched change: `CLAUDE.md` (efficiency rule), `SKILL.md` (report cap, evidence
proportionality), `budgets.env` + `verify.sh` (`CLAUDE.md` line ceiling). Trips the `HARNESS.md`
coupling gate by design. Estimated one feature-sized change.