-site (or KHOSRA_SITE) opens the site root through content.OpenSite, so every
read keeps the os.Root guarantee. A path is a bundle key: /{section}/{slug}/
serves, the slashless form redirects permanently to it (ADR-0008), anything
unknown is 404. Render failure logs and returns a bare 500 rather than leaking a
template or filesystem detail.
internal/render holds goldmark plus the embedded reference theme (ADR-0026):
base.html with a redefinable "main" block, and one stylesheet inlined through
.Style. Serving it at an asset route would have been a second routing case for no
gain, and static serving belongs to a later entry.
Evidence beyond the tests: the binary against a real site root returns 200 with
<h1>About</h1> and the rendered body, 301 from /pages/about to /pages/about/, and
404 for /nope/. A Bengali variant is scanned but not yet reachable — that is the
next entry.
theme-contract.md gains a "Live today" section listing the six fields and two
named templates a theme may now rely on; the rest stays marked as shape.
3.3 KiB
State
Verified against: HEAD on 2026-07-30 — update this line every change.
If this file disagrees with the code, the code is right and this file is a bug.
Inventory
| File | Purpose | LOC |
|---|---|---|
go.mod |
module khosra; x/text, yaml.v3 direct |
8 |
internal/content/content.go |
site root → bundles: os.Root open, walk, frontmatter split, key/lang derivation, NFC, collision drop, key index |
245 |
internal/render/render.go |
goldmark + the embedded reference theme; Page is what templates receive |
92 |
internal/render/templates/ |
reference theme: base.html, theme.css (ADR-0026) |
— |
internal/web/web.go |
one routing case: path → bundle key, canonical trailing slash, 404, degrade on render failure | 62 |
cmd/khosra/main.go |
flags, wiring, startup — the only place things are assembled | 50 |
*_test.go |
table-driven; symlink escape, permalink, redirect, 404 | 245 |
Serves a bundle at /{section}/{slug}/. This repo holds engine source only — the site root is external
and passed with -site (ADR-0011).
Dependencies: none.
Counters — the earn-it authority
Never anticipate a threshold. Increment when the code lands, then check whether the extraction is due this change.
| Counter | Now | Extraction due at | What it buys |
|---|---|---|---|
| Render transforms | 0 | 3 | Stage pipeline (ordered func(ctx,*Page) error) |
| Routing cases | 1 | 2 | Resolver extraction |
| Collection pages | 0 | 1 | Query primitive |
| Views / output formats | 1 | 2 | View layer (contract per theme-contract.md) |
| Effects | 0 | 2 | Effect runner + trigger wiring (change / schedule / demand) |
| Extensions | 0 | 3 | Extension registry + wire file (extensions.md) |
| Interface implementations | — | 2 | The interface itself |
| Non-stdlib dependencies | 3 direct | budget in scripts/budgets.env |
— |
Allowlisted, in use: goldmark is not yet imported. Allowlist: goldmark (markdown), golang.org/x/text (NFC, ADR-0015),
gopkg.in/yaml.v3 (frontmatter, ADR-0020).
Latent items — known, deliberately unfixed
Do not fix these mid-feature. They become features when the human says so. An arc does not close with an untriaged item: at each arc boundary every row is fixed, scheduled into an arc, or accepted with a stated reason. A list nothing drains is a graveyard of known defects.
| Item | Why it waits | Trigger to fix |
|---|---|---|
| No mechanical check that the counters are correct | The coupling gate makes forgetting them impossible, which is the real failure mode; checking values needs code to count | 3rd transform or 2nd route |
| No mechanical gate on the untrusted boundary (ADR-0003) | Nothing untrusted exists yet | The comment path, Arc 3 — a test that untrusted input reaches no shortcode or template evaluation |
Open questions blocking Arc 1
None. Every decision the engine needs before Arc 1 and before the first deploy is recorded.
Every ADR in decisions.md is accepted; none is open or proposed.
Build queue
Working plan lives in .scratch/build-queue.md, which is deliberately not committed — git log is the
record of what actually landed. If that file is absent, read the log and rebuild the plan from it.
Arc retro log
One line per completed arc: what it cost, what it taught, what it made unnecessary.
- (empty)