rename the project to khosra, initialise the module
Naming is free before a module is published, a URL is shared, or a binary is deployed; every day it waits costs more. Swept every form: module path, binary, cmd/ directory, KHOSRA_SITE, the feature-loop skill directory, and the prose in earlier ADRs — which describe this project under its old name, not a different project. Recorded as ADR-0030. go mod init lands here rather than with the first feature because the module path is what the rename is about. x/text and yaml.v3 are required but not yet imported, so both are indirect and no direct dependency is claimed yet.
This commit is contained in:
@@ -12,7 +12,7 @@ whatever builds it. What exists is `state.md`'s job. Never build a `[spec]` sect
|
||||
|
||||
## The site root
|
||||
|
||||
The engine is pointed at a site root outside this repository (`-site <dir>`, or `ATELIER_SITE`), with
|
||||
The engine is pointed at a site root outside this repository (`-site <dir>`, or `KHOSRA_SITE`), with
|
||||
its own git history (ADR-0011). Nothing in the engine repo is content. `templates/` in the site root
|
||||
overrides the defaults the binary embeds, so a bare root still renders.
|
||||
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ goes through an ADR, not a diff.
|
||||
- `net/http`, `html/template`, `log/slog`, `os`, `io/fs`, `embed`. Routing is `http.ServeMux` with Go
|
||||
1.22+ patterns — `GET /{section}/{slug}/` and `{path...}` for multi-segment slugs — so no router
|
||||
library is needed. No web framework, ORM, or config library — flags plus environment variables, parsed in one place. The site root
|
||||
(`-site`, `ATELIER_SITE`) is the only required setting; default templates are `embed`ded so a bare
|
||||
(`-site`, `KHOSRA_SITE`) is the only required setting; default templates are `embed`ded so a bare
|
||||
site root renders (ADR-0011).
|
||||
- New dependency = ADR + human approval + `scripts/allowed-deps.txt`. `verify.sh` enforces it.
|
||||
- Prefer 40 lines of obvious code over a dependency doing it in one call — unless the 40 lines would be
|
||||
@@ -16,7 +16,7 @@ goes through an ADR, not a diff.
|
||||
|
||||
## Package layout
|
||||
```
|
||||
cmd/atelier/ main, flag parsing, explicit wiring — the only place things are assembled
|
||||
cmd/khosra/ main, flag parsing, explicit wiring — the only place things are assembled
|
||||
internal/content/ bundles, frontmatter, slugs, queries — knows the disk, not HTTP
|
||||
internal/render/ markdown, transforms, templates — knows content, not HTTP
|
||||
internal/web/ handlers, routing, headers, caching — knows both, exposes neither
|
||||
@@ -26,7 +26,7 @@ Dependencies point inward. `internal/content` imports nothing from the others; `
|
||||
and is imported by nothing. A feature under `internal/ext/` may import `internal/content` and
|
||||
`internal/render`, and must not import `internal/web`, `cmd/`, or **another feature** — sibling imports
|
||||
are what make an agent's read set compound (ADR-0027). Every `internal/ext/*` package carries a `doc.go`;
|
||||
`verify.sh` fails without one. Routes reach `web` by assembly in `cmd/atelier/wire.go`, so `web` never
|
||||
`verify.sh` fails without one. Routes reach `web` by assembly in `cmd/khosra/wire.go`, so `web` never
|
||||
learns features exist. No `utils`, `helpers`, `common`, `shared`, `manager`, `base`,
|
||||
`impl`, `core` — a package name not describing a domain is a smell. Flat until a package exceeds
|
||||
`FILE_LOC_WARN`; do not pre-partition, and a single-file package therefore warns at the same point it
|
||||
|
||||
+43
-2
@@ -116,7 +116,7 @@ Revisit if: the engine can no longer boot and serve correctly with every externa
|
||||
Date: 2026-07-28 · Status: accepted
|
||||
Decision: the engine is pointed at a **site root** — a directory outside this repository, versioned in
|
||||
its own git repo — holding `content/`, `static/`, and optionally `templates/` overriding the defaults
|
||||
the binary embeds. Selected by `-site <dir>` or `ATELIER_SITE`. This repository contains engine source
|
||||
the binary embeds. Selected by `-site <dir>` or `KHOSRA_SITE`. This repository contains engine source
|
||||
only; no content, ever, not even an example.
|
||||
Why: content is the database, and a database does not live in the application's repo. Mixing them
|
||||
interleaves "fixed a typo in a poem" with "extracted the resolver" in one history, makes every typo a
|
||||
@@ -298,7 +298,7 @@ Revisit if: it starts accumulating design decisions — then split it into a ref
|
||||
## ADR-0027 — Feature locality: one directory, no sibling imports, a mandatory `doc.go`
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: a feature is one directory under `internal/ext/<name>/` from its first use, plus one line in
|
||||
`cmd/atelier/wire.go` — the only file that knows every feature. No `internal/ext` package may import
|
||||
`cmd/khosra/wire.go` — the only file that knows every feature. No `internal/ext` package may import
|
||||
another. Every one carries a `doc.go` stating, in four lines: what it contributes, which cascade keys it
|
||||
reads, which theme-contract fields it adds, and what it deliberately does not do. A feature may import
|
||||
`internal/content` and `internal/render`; never `internal/web`, never `cmd/`, never a sibling.
|
||||
@@ -313,3 +313,44 @@ inward (earning it under the counters) or stay duplicated until the third use, w
|
||||
rather than a new one. Expensive — `wire.go` absorbs all the coupling on purpose and will look
|
||||
repetitive; and this buys cheap *features*, not cheap spine changes, which still need the core read.
|
||||
Revisit if: `wire.go` becomes hard to read, which means the registry from `extensions.md` is due.
|
||||
|
||||
## ADR-0028 — Pagination lives in the path: `/{section}/page/2/`
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: page two of a listing is `/{section}/page/2/`; page one is the bare listing URL and never
|
||||
`/page/1/`, which permanently redirects to it. Tag listings compose the same way:
|
||||
`/tags/{tag}/page/2/`. `page` is therefore a reserved segment inside a section.
|
||||
Why: a query parameter is not a permalink — it reads as ephemeral, is dropped by careless sharing, and
|
||||
splits caching by URL shape rather than by content. Putting it in the path keeps every listing page
|
||||
linkable and cacheable on the same terms as a bundle.
|
||||
Consequence: cheap — one more resolver case, and every paginated listing is a first-class URL. Expensive
|
||||
— no bundle may be slugged `page` inside a paginated section, and changing the page size renumbers pages,
|
||||
so page URLs are stable only while the size is.
|
||||
Revisit if: never for the shape. Page size is a separate setting and changing it is a URL event.
|
||||
|
||||
## ADR-0029 — A bundle that fails to parse is skipped loudly, not fatal
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: a bundle whose frontmatter or filename cannot be parsed is logged at error level with its path
|
||||
and line, excluded from the site, and does not stop startup or any request. The `check` command reports
|
||||
the same failures as errors, and that is where a non-zero exit belongs.
|
||||
Why: `conventions.md` says startup failure is fatal and loud, and separately that request-time failure
|
||||
degrades. A single mistyped colon in one post is not a startup failure — treating it as one means one
|
||||
typo takes the whole site down, which is the worst possible failure mode for a personal site published
|
||||
from a text editor. Fatal is right for a broken site root or an unreadable directory, not for one file.
|
||||
Consequence: cheap — the site always serves whatever is valid, and the author sees the error in the log
|
||||
and in `check`. Expensive — a silently absent page is a real failure mode, so the log line must name the
|
||||
file and the reason plainly, and `check` must exist early enough to be the place you look.
|
||||
Revisit if: skipped bundles start going unnoticed in practice — then `check` runs in CI, rather than the
|
||||
engine becoming fatal.
|
||||
|
||||
## ADR-0030 — The project is named khosra
|
||||
Date: 2026-07-30 · Status: accepted
|
||||
Decision: the engine is `khosra`. Module path `khosra`, binary `khosra`, command directory
|
||||
`cmd/khosra/`, environment variable `KHOSRA_SITE`, feature-loop skill `khosra-feature-loop`. The former
|
||||
name `atelier` appears nowhere, including in earlier ADRs, which describe this project under its old
|
||||
name rather than a different project.
|
||||
Why: naming is the author's, and it is free now — before a module is published, a URL is shared, or a
|
||||
binary is deployed. Every day it waits, it costs more.
|
||||
Consequence: cheap now, and permanent-ish once the module path is fetched by anything. Expensive later —
|
||||
a module rename after publication needs a redirect or a major-version bump, and a deployed binary name
|
||||
appears in service files and container tags.
|
||||
Revisit if: never. Renaming again costs strictly more than this did.
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ type Extension struct {
|
||||
}
|
||||
```
|
||||
|
||||
`cmd/atelier/wire.go` holds the only list of enabled extensions. Enabling or disabling one is a
|
||||
`cmd/khosra/wire.go` holds the only list of enabled extensions. Enabling or disabling one is a
|
||||
one-line diff and a rebuild. Removing one leaves no trace elsewhere — that property is the test of
|
||||
whether the contract is right.
|
||||
|
||||
|
||||
+6
-2
@@ -5,8 +5,12 @@ If this file disagrees with the code, the code is right and this file is a bug.
|
||||
|
||||
## Inventory
|
||||
|
||||
No Go source, no `go.mod`. The harness is installed; the engine is unwritten. This repo holds engine
|
||||
source only — the site root is external and passed with `-site` (ADR-0011).
|
||||
| File | Purpose | LOC |
|
||||
|---|---|---|
|
||||
| `go.mod` | module `khosra`; `x/text` and `yaml.v3` required, not yet imported | 8 |
|
||||
|
||||
No Go source yet. This repo holds engine source only — the site root is external and passed with `-site`
|
||||
(ADR-0011).
|
||||
|
||||
Dependencies: none.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user