Captures the durable learnings from the 2026-07-25 whole-repo documentation reconciliation as a knowledge-track learning, plus the vocabulary it introduced. New learning — conventions/reconciling-drifted-docs-tense-tiering-and-a-supersession-ledger.md: - Tier docs by TENSE, not only by content type. claude-md-content-tiering.md established "descriptions drift, rules don't" and tiered by content type; that axis could not say what to do with 41 completed plans, which are neither rules nor current descriptions. Present-tense docs are defects when stale; past-tense records are supposed to be stale and get annotated, never rewritten. - Ledger AND inline notes, because each covers the other's failure: a ledger alone is a pointer you may not follow, inline notes alone give no changelog view. Prefer annotation patterns the repo already uses. - Record what was NOT reversed, or a ledger of only reversals makes every old doc look suspect and settled decisions get re-litigated. - Separate "docs are wrong" from "code is wrong" — route code-side findings to a recommendations doc so a docs diff stays reviewable. - Verify against the artifact that decides behaviour: the Makefile for commands (including macro-generated targets a grep misses), the build script for outputs, imports for source-vs-output, branch history for whether a plan shipped. An audit that never withdraws a finding has not been checking itself — one finding here was withdrawn after reading package.json. - Audit the state that actually runs: a fresh worktree checks out the submodule PIN, which lagged real HEAD and would have hidden a whole merged feature. Three structural lessons in "Why This Matters": - An index describing another document's role is a factual claim that can rot, and it is worse than the stale document itself — it defeats the reader's judgement before it engages. This was the tree's single most misleading line. - Wrong beats absent again, now for commands: README's server runbook documented every remote-* target without the -test/-prod suffix guard-env requires. deploy-cycle.md had it right — the defect was a second copy drifting. - Promoting a doc to "the authoritative list of X" creates a completeness obligation it did not have as prose, and nothing enforces it. - A removal is not finished when the code is gone, but when every consumer and every description of it is gone — travel-memories left a compose service behind, hidden by a cached Docker image. Local state can mask a breakage indefinitely, so "it works here" is not evidence. Overlap with conventions/claude-md-content-tiering.md scored MODERATE (2 of 5 dimensions: same root-cause thesis, overlapping files; different tiering axis and different prevention), so a new doc was written rather than folding into it. Flagged in the Related section as a consolidation candidate if a third documentation learning appears. CONCEPTS.md — new Documentation cluster (Historical record, Superseded decision, Plan status) and one flagged ambiguity recording that a present-tense historical record is not a claim about the current system. These three are now referenced by CLAUDE.md and both doc READMEs, so they needed defining. Discoverability check: no edit needed — CLAUDE.md's entry-point table already surfaces docs/solutions/ with its frontmatter fields and CONCEPTS.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
72 lines
6.6 KiB
Markdown
72 lines
6.6 KiB
Markdown
# Concepts
|
|
|
|
Shared domain vocabulary for this project — entities, named processes, and status concepts with project-specific meaning. Seeded with core domain vocabulary, then accretes as ce-compound and ce-compound-refresh process learnings; direct edits are fine. Glossary only, not a spec or catch-all.
|
|
|
|
## Relationships
|
|
|
|
A **Trip** owns its **Entries** and **Stories**. Exactly one Trip is the **Active Trip** at a time; it is the one surfaced on the home page and the target for new posts. Entries and Stories are always scoped to a Trip — they do not exist independently.
|
|
|
|
## Trip
|
|
|
|
### Trip
|
|
A single journey the blog is organised around — the top-level content entity. A Trip aggregates its Entries and Stories and carries its own metadata (title, start/end dates, cover image, route GPX files). Each Trip renders as one consolidated **Trip page** showing an inline map, a filtered feed, and inline stats; the journal, map, stats, and story views are not separate pages.
|
|
|
|
### Active Trip
|
|
The one Trip currently featured — set in a single site-config value and read by the home page and the posting pipeline, which derives the write target for new Entries from it at submit time. Switching the Active Trip is that one setting; there is no separate post-form target to keep in sync.
|
|
|
|
### Published / Draft
|
|
A Trip's visibility state. A **Published** Trip is listed publicly and reachable by anyone; a **Draft** Trip is hidden from anonymous visitors in the public trip list, while the signed-in owner still sees it (marked "Draft") and can flip it back. The owner toggles this per Trip from the trip list.
|
|
|
|
Unpublishing the **Active Trip** additionally drops it from the public home page, which falls back to its between-trips landing. The toggle is owner-only; a Draft is a visibility control, not privacy — a Draft Trip's Entries, Stories, and media stay reachable by direct link.
|
|
|
|
### Entry
|
|
A single dated journal post within a Trip — the atomic unit of the day-to-day travel log.
|
|
*Avoid:* daily, journal post
|
|
|
|
The Trip's journal section is labelled "Journal" and lives in the Trip's `dailies` container, so an Entry is colloquially "a daily"; in templates and page metadata the same thing is called an `entry`. Entries carry a date, optional location and coordinates, weather, and photos, and are ordered by date within a Trip.
|
|
|
|
### Story
|
|
A long-form, designed narrative piece within a Trip — hero image plus scrollytelling/gallery sections — distinct from the short, dated Entry. Stories are curated set pieces; Entries are the running log.
|
|
|
|
### Container
|
|
A Trip's non-routable holder of child pages — one for Entries, one for Stories. A Container's own URL is deliberately inert (it renders no page of its own), while its children stay individually reachable and are aggregated onto the Trip page. Retiring a view must never delete its Container: the folder half is load-bearing data even when the page half is gone.
|
|
|
|
## Repos & deployment
|
|
|
|
### Content repo
|
|
The repository holding everything the site serves — pages, configuration, accounts, the theme. It has its own remote and its own release cadence: pushing it triggers production to pull via webhook, independent of the Outer repo.
|
|
|
|
### Outer repo
|
|
The dev-environment repository — tests, docs, scripts, container build — that nests the Content repo and records a Pin to an exact Content-repo commit, expressing "this dev-env state expects this content/theme state."
|
|
|
|
### Pin
|
|
The Outer repo's recorded Content-repo commit (also "pointer bump" for the act of updating it). Routine content churn never moves it; it is bumped once at the end of a cross-repo feature, to a commit already published on the Content repo's main branch. A stale Pin during normal work is expected, not an error.
|
|
|
|
### Env tree
|
|
A server's per-host configuration overlay. Once it exists, Grav's Admin writes **all** config edits there rather than into the shared configuration — so server-side Admin edits are server-only, invisible to content sync, and can hold live secrets. Diagnosing config on a server means checking both the shared configuration and the Env tree, with the Env tree winning at runtime.
|
|
|
|
### Remote-only plugin
|
|
One of the project's three plugin-management categories, alongside GPM-managed (declared in the shared install list and restored by the standard install flow) and custom-in-repo (code tracked in the Content repo). A Remote-only plugin is installed explicitly on servers and restored by **no** standard flow — if its code goes missing it stays missing until someone reinstalls it deliberately, even while its configuration persists in the Env tree.
|
|
|
|
## Documentation
|
|
|
|
### Historical record
|
|
A document that states what was decided or built at a past moment, not what is true now — plans, specs, milestone scopes, and session write-ups. Its going out of date is expected and is what makes it a record; it is corrected only by annotation, never by rewriting, because the value is the reasoning at the time.
|
|
|
|
Distinguished from *current documentation*, which asserts how the system is today and is simply wrong when it drifts. A Historical record often reads in present tense, so the distinction is carried by an explicit marker rather than by tone.
|
|
|
|
### Superseded decision
|
|
Something the project planned or built and then deliberately reversed, recorded so the reversal is discoverable from the document that still describes the original. Each one names what was planned, what replaced it, when, and why.
|
|
|
|
The record exists because a reversal is otherwise invisible: the old document keeps asserting the old thing, and the reasoning that killed it lives only in whoever remembers. A Superseded decision is the standing answer to "may I re-create this?" — usually no, and often the prohibition is also a hard rule.
|
|
|
|
### Plan status
|
|
The single recorded state of a plan, carried on the plan itself rather than in a separate tracker. **Deferred** and **Abandoned** are deliberately distinct: Deferred means still wanted but not now, Abandoned means decided against, kept so the decision is not re-litigated.
|
|
|
|
A status that lags reality is worse than no status, because it is trusted — so it moves when the work lands, not later.
|
|
|
|
## Flagged ambiguities
|
|
|
|
- "daily" / "entry" / "journal post" all refer to the same concept (a dated journal post). Canonical term: **Entry**. The section/folder is named "dailies" and the nav label is "Journal" — these name the *collection*, not a different entity.
|
|
- A **Historical record** written in present tense is **not** a claim about the current system. Staleness there is correct; staleness in current documentation is a defect. When the two disagree, the code decides, and the gap is recorded as a **Superseded decision**.
|