init
This commit is contained in:
@@ -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**
|
||||
@@ -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 1–2, 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.
|
||||
@@ -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.
|
||||
@@ -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 1–6 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.
|
||||
Reference in New Issue
Block a user