Docs: record the spec-follows-code regime across the working docs

This commit is contained in:
2026-07-02 22:33:05 +03:00
parent e42a535726
commit fb4b42a1a7
13 changed files with 76 additions and 59 deletions
+19 -13
View File
@@ -37,8 +37,11 @@ Review all changes in scope. If changes span multiple patterns below, apply all
3. **Fix directly; don't ask first.** When you find an issue covered by these instructions, 3. **Fix directly; don't ask first.** When you find an issue covered by these instructions,
fix it in place rather than reporting it and waiting. Ask the user only when the fix is fix it in place rather than reporting it and waiting. Ask the user only when the fix is
genuinely ambiguous or several valid approaches exist with real trade-offs. When guidelines genuinely ambiguous or several valid approaches exist with real trade-offs. When guidelines
conflict, prefer in this order: **SOUL.md philosophy > `docs/spec/` behavioral contract > conflict, prefer in this order: **SOUL.md philosophy > `docs/spec/` behavioral record >
`docs/architecture/` patterns > local cleanup**. These instructions are not strictly `docs/architecture/` patterns > local cleanup**. (The spec is descriptive — the code
leads. A spec/code mismatch is fixed by updating the stale spec section, not by
reverting the code; only flag the code when it contradicts recorded _rationale_, not
merely an unrewritten section.) These instructions are not strictly
prohibitive — if a guideline has a valid reason to be bypassed, mention it in the summary. prohibitive — if a guideline has a valid reason to be bypassed, mention it in the summary.
### Code Quality ### Code Quality
@@ -178,12 +181,15 @@ role`) or the rule it demonstrates. - **Positional sub-section cross-refs.** Cit
(whole-spec drag/simplify) — never re-inlining the model/parse/writeBack prologue. The (whole-spec drag/simplify) — never re-inlining the model/parse/writeBack prologue. The
family has grown by copy-paste twice (eng-council; arch 08). family has grown by copy-paste twice (eng-council; arch 08).
17. **Spec tracks the surfaces it mandates** (`docs/spec/`): a diff that **removes, moves, or 17. **Spec tracks the surfaces it describes** (`docs/spec/`): a diff that **adds, removes,
renames a user-facing surface** — where a message, control, or affordance lives — updates the moves, or renames a user-facing surface** — a feature, message, control, or affordance
`docs/spec/` section describing it, not only the `docs/architecture/` pattern doc. The spec is updates the `docs/spec/` section describing it (adding a section for new behavior), not
the behavioral contract; an arch-doc-only update leaves it describing a surface that no longer only the `docs/architecture/` pattern doc. The spec is the behavioral record and the code
exists. An arch-only update once left spec §03E mandating an editor-pane error message after it leads; an arch-doc-only update leaves the spec describing a product that no longer exists.
had moved to the preview (eng-council). An arch-only update once left spec §03E mandating an editor-pane error message after it had
moved to the preview (eng-council); a run of feature commits (2026-06-25 → 06-30: the
/learn/ section, the composition wireframe, editor scaffolds) once landed with zero spec
coverage (eng-council, 2026-07).
### Output ### Output
@@ -206,7 +212,7 @@ role`) or the rule it demonstrates. - **Positional sub-section cross-refs.** Cit
Update relevant docs if the feature is significant: Update relevant docs if the feature is significant:
- **`docs/spec/`** — if product behavior changed (this is a contract; change deliberately). - **`docs/spec/`** — if product behavior changed (descriptive record; update it to match what shipped — see #17).
- **`docs/architecture/`** — if a new pattern, navigation map, or decision rule emerged. - **`docs/architecture/`** — if a new pattern, navigation map, or decision rule emerged.
- **`docs/IMPLEMENTATION-PLAN.md`** — mark milestone progress. - **`docs/IMPLEMENTATION-PLAN.md`** — mark milestone progress.
Use the `/doc-update` skill for session-discovered gaps. The list is not exclusive. Use the `/doc-update` skill for session-discovered gaps. The list is not exclusive.
@@ -226,7 +232,7 @@ If `package.json` changed:
### Alignment Check ### Alignment Check
- **SOUL.md** — philosophy (must not violate without good reason). - **SOUL.md** — philosophy (must not violate without good reason).
- **`docs/spec/`** — behavioral contract. - **`docs/spec/`** — behavioral record.
- **`docs/architecture/`** — the relevant pattern doc. - **`docs/architecture/`** — the relevant pattern doc.
--- ---
@@ -245,7 +251,7 @@ Usually not required unless the bug revealed incorrect docs, or the fix changes
### Alignment Check ### Alignment Check
- **SOUL.md** philosophy; **`docs/spec/`** behavioral contract; **`docs/architecture/`** patterns. - **SOUL.md** philosophy; **`docs/spec/`** behavioral record; **`docs/architecture/`** patterns.
--- ---
@@ -287,9 +293,9 @@ Update JSDoc/inline comments if signatures or behavior changed.
## Reference Documents ## Reference Documents
| Document | Purpose | | Document | Purpose |
| ------------------------------------------------------------------- | ----------------------------------------- | | ------------------------------------------------------------------- | ---------------------------------------- |
| [SOUL.md](../../../SOUL.md) | Project philosophy and core values | | [SOUL.md](../../../SOUL.md) | Project philosophy and core values |
| [AGENTS.md](../../../AGENTS.md) | AI onboarding and project context | | [AGENTS.md](../../../AGENTS.md) | AI onboarding and project context |
| [docs/spec/](../../../docs/spec/) | Behavioral contract_what_ the app does | | [docs/spec/](../../../docs/spec/) | Behavioral record_what_ the app does |
| [docs/architecture/](../../../docs/architecture/00-overview.md) | Architecture playbook — _how_ it's built | | [docs/architecture/](../../../docs/architecture/00-overview.md) | Architecture playbook — _how_ it's built |
| [docs/IMPLEMENTATION-PLAN.md](../../../docs/IMPLEMENTATION-PLAN.md) | Milestone sequence and scope | | [docs/IMPLEMENTATION-PLAN.md](../../../docs/IMPLEMENTATION-PLAN.md) | Milestone sequence and scope |
+6 -5
View File
@@ -30,9 +30,10 @@ For documentation organization, see **[CLAUDE.md](../../../CLAUDE.md)** and the
## The three documentation layers (know which one a gap belongs to) ## The three documentation layers (know which one a gap belongs to)
- **`docs/spec/`** — the _what_: behavioral contract (what the app does, acceptance points). - **`docs/spec/`** — the _what_: behavioral record (what the app does, acceptance points).
This is a **contract**. Only change it when product behavior genuinely changes, and do so The code leads; the spec is kept rewritten to match what shipped. If the session added or
deliberately — never as a casual "fill a doc gap" edit. A how-detail does NOT belong here. changed user-facing behavior, name the spec section that describes it — or write it — as
part of this pass. A how-detail does NOT belong here.
- **`docs/architecture/`** — the _how_: the patterns behind each layer (state, persistence, - **`docs/architecture/`** — the _how_: the patterns behind each layer (state, persistence,
modals, routing, rendering, inference, relationships). Most navigation maps and decision modals, routing, rendering, inference, relationships). Most navigation maps and decision
rules land here. rules land here.
@@ -60,8 +61,8 @@ not do Y"). If you can't state it concisely, it may be too implementation-specif
Map each gap to the right document: Map each gap to the right document:
| Gap type | Target document | | Gap type | Target document |
| ------------------------------------------------- | ----------------------------------------------------------------------------- | | ------------------------------------------------- | --------------------------------------------------------------------------------- |
| Product behavior, capabilities, acceptance points | `docs/spec/` (the relevant 0010 section) — **contract; change deliberately** | | Product behavior, capabilities, acceptance points | `docs/spec/` (the relevant 0010 section) — **record; keep it matching the code** |
| State / Zustand stores | `docs/architecture/01-state-and-stores.md` | | State / Zustand stores | `docs/architecture/01-state-and-stores.md` |
| Persistence, IndexedDB, localStorage, migrations | `docs/architecture/02-persistence.md` | | Persistence, IndexedDB, localStorage, migrations | `docs/architecture/02-persistence.md` |
| Modals, dialog lifecycle | `docs/architecture/03-modal-system.md` | | Modals, dialog lifecycle | `docs/architecture/03-modal-system.md` |
+9 -6
View File
@@ -11,9 +11,10 @@ a local library of **snippets** (saved Vega-Lite specs), edits each as JSON with
validation and a live chart preview, and reuses **datasets** across many snippets. Fully validation and a live chart preview, and reuses **datasets** across many snippets. Fully
local, offline-capable, no account. local, offline-capable, no account.
It is a **spec-driven rebuild** on an architecture adapted from its sibling project Syto. It is a rebuild on an architecture adapted from its sibling project Syto. **`docs/spec/`**
The authoritative behavioral contract is **`docs/spec/`** (sections 0010). Implement _to (sections 0010) is the behavioral record: the code leads and the spec is kept rewritten
the spec_; do not port legacy code. to match — a user-facing change isn't done until its spec section describes it. Do not
port legacy code.
### Technical Stack ### Technical Stack
@@ -74,7 +75,7 @@ src/
│ └── infrastructure/ # IndexedDB, localStorage, Monaco, settings adapters │ └── infrastructure/ # IndexedDB, localStorage, Monaco, settings adapters
styles/ # Global CSS (tokens, base) styles/ # Global CSS (tokens, base)
docs/ docs/
├── spec/ # Authoritative behavioral specification (0010) — the WHAT ├── spec/ # Behavioral specification (0010) — the WHAT (record; code leads)
├── architecture/ # Architecture playbook (0011) — the HOW (self-contained) ├── architecture/ # Architecture playbook (0011) — the HOW (self-contained)
│ └── visual-specimen.html # Standalone token sandbox + reusable-primitive catalog │ └── visual-specimen.html # Standalone token sandbox + reusable-primitive catalog
├── exploration/ # Point-in-time records (research, reviews, scope memos) — not maintained ├── exploration/ # Point-in-time records (research, reviews, scope memos) — not maintained
@@ -116,8 +117,10 @@ npm run format # Prettier
trimming IBM Plex to the latin subsets dropped Cyrillic — capability for an trimming IBM Plex to the latin subsets dropped Cyrillic — capability for an
internationally-usable app. We ship every script subset and precache them for offline; internationally-usable app. We ship every script subset and precache them for offline;
`unicode-range` means the browser only downloads what a glyph needs anyway.) `unicode-range` means the browser only downloads what a glyph needs anyway.)
- **Spec is the contract** — when in doubt, read `docs/spec/`. If the spec is wrong or - **Spec follows code** — `docs/spec/` is the descriptive record of behavior; the code
silent, raise it; change the spec deliberately rather than drifting from it. leads. When in doubt about existing behavior, read the spec. When you ship user-facing
behavior, update the matching spec section in the same session; if spec and app
disagree, the spec is stale — rewrite it deliberately, never drift silently.
- **Core-first** — for each feature, build the pure `src/core/` logic with tests before UI. - **Core-first** — for each feature, build the pure `src/core/` logic with tests before UI.
- **Session wrap-up** — when the user signals the session is wrapping, run the review - **Session wrap-up** — when the user signals the session is wrapping, run the review
pass before any commit: `/doc-update` in-session first (flush unrecorded rationale), pass before any commit: `/doc-update` in-session first (flush unrecorded rationale),
+6 -4
View File
@@ -5,8 +5,9 @@ See @AGENTS.md for project overview, architecture rules, and the AI developer pr
## Documentation Index ## Documentation Index
- **[SOUL.md](SOUL.md)** — project philosophy and identity. _Read first._ - **[SOUL.md](SOUL.md)** — project philosophy and identity. _Read first._
- **[docs/spec/](docs/spec/)** — authoritative behavioral specification (sections 0010): - **[docs/spec/](docs/spec/)** — behavioral specification (sections 0010): the **what**.
the **what**. This is the contract; implement to it. Descriptive, kept current with the code: the code leads; on conflict amend the spec,
never drift silently. User-facing behavior ships with its spec section.
- **[docs/architecture/](docs/architecture/00-overview.md)** — architecture playbook - **[docs/architecture/](docs/architecture/00-overview.md)** — architecture playbook
(0011): the **how** (state, persistence, modals, routing, rendering, inference, (0011): the **how** (state, persistence, modals, routing, rendering, inference,
relationships, vega-editor techniques, visual design, interaction & feedback, learning relationships, vega-editor techniques, visual design, interaction & feedback, learning
@@ -31,8 +32,9 @@ See @AGENTS.md for project overview, architecture rules, and the AI developer pr
## Quick Orientation ## Quick Orientation
- Astrolabe is a **spec-driven rebuild** — the behavior is fixed in `docs/spec/`; the - Astrolabe is a **spec-recorded rebuild** — the architecture is adapted from Syto, and
architecture is adapted from Syto. Implement to the spec; don't port legacy code. `docs/spec/` records the behavior as built. Build deliberately, record in the spec;
don't port legacy code.
- **`src/core/` is portable and tested hardest.** Browser specifics live in - **`src/core/` is portable and tested hardest.** Browser specifics live in
`src/app/infrastructure/`. UI is React + Zustand. `src/app/infrastructure/`. UI is React + Zustand.
- **Editor is Monaco**, charts render via **vega-embed**, storage is **IndexedDB**. - **Editor is Monaco**, charts render via **vega-embed**, storage is **IndexedDB**.
+3 -2
View File
@@ -4,8 +4,9 @@ A browser-based **snippet manager for [Vega-Lite](https://vega.github.io/vega-li
visualizations**. Author chart specs as JSON, watch them render live, and keep a personal, visualizations**. Author chart specs as JSON, watch them render live, and keep a personal,
searchable library — local, offline-capable, no account. searchable library — local, offline-capable, no account.
> Astrolabe is a **spec-driven rebuild** on an architecture adapted from its sibling > Astrolabe is a rebuild on an architecture adapted from its sibling project Syto. The
> project Syto. The authoritative behavioral contract lives in [`docs/spec/`](docs/spec/). > behavioral record lives in [`docs/spec/`](docs/spec/) — the code leads; the spec is
> kept rewritten to match.
> See [SOUL.md](SOUL.md) for the philosophy and [docs/IMPLEMENTATION-PLAN.md](docs/IMPLEMENTATION-PLAN.md) > See [SOUL.md](SOUL.md) for the philosophy and [docs/IMPLEMENTATION-PLAN.md](docs/IMPLEMENTATION-PLAN.md)
> for the build sequence. > for the build sequence.
+5 -5
View File
@@ -79,12 +79,12 @@ clever.
## Technical Philosophy ## Technical Philosophy
### Spec-Driven, Clean Implementation ### Spec-Recorded, Clean Implementation
The behavioral contract lives in `docs/spec/`. Astrolabe is a deliberate rebuild on a The behavioral record lives in `docs/spec/`. Astrolabe is a deliberate rebuild on a
robust architecture (adapted from Syto): we implement _to the spec_, not by porting old robust architecture (adapted from Syto): behavior is designed deliberately and recorded
code. When the spec and convenience conflict, the spec wins or the spec changes — never in the spec, not ported from old code. The code leads; the spec is rewritten to match
silent drift. what ships — never silent drift.
### Portable Core, Thin Browser Shell ### Portable Core, Thin Browser Shell
+3 -2
View File
@@ -1,7 +1,8 @@
# Astrolabe — Incremental Implementation Plan # Astrolabe — Incremental Implementation Plan
> A spec-driven rebuild of Astrolabe on Syto's architecture. The authoritative > A rebuild of Astrolabe on Syto's architecture. The behavioral record is
> behavioral contract is `docs/spec/` (sections 0010). > `docs/spec/` (sections 0010) — the code leads, and the spec is kept
> rewritten to match.
> >
> **The M0M6 build is complete** — the milestone map below is the record. Remaining > **The M0M6 build is complete** — the milestone map below is the record. Remaining
> work is post-M6 enhancement, tracked in the **live backlog** and owned in detail by > work is post-M6 enhancement, tracked in the **live backlog** and owned in detail by
+3 -1
View File
@@ -22,7 +22,9 @@ about user-facing widgets. At that overlap, one rule keeps them from drifting:
and never contradict it.** A playbook bullet may _name_ the behavior in one clause and cite and never contradict it.** A playbook bullet may _name_ the behavior in one clause and cite
the spec, then spend its words on the _how_ (the role, the keys, the focus move) and the the spec, then spend its words on the _how_ (the role, the keys, the focus move) and the
_why_ (the council/canon citation). When a playbook bullet and the spec disagree, the _why_ (the council/canon citation). When a playbook bullet and the spec disagree, the
**spec wins** and the bullet is the bug. Restatement is the leak: two docs describing the **spec wins** and the bullet is the bug — both describe the shipped code, so if the spec
section is itself stale, rewrite it to match the app, then cite it (the code leads; the
spec records). Restatement is the leak: two docs describing the
same behavior in their own words drift into contradiction; one cites the other instead. same behavior in their own words drift into contradiction; one cites the other instead.
## How to use this playbook ## How to use this playbook
+2 -2
View File
@@ -284,8 +284,8 @@ export interface UserSettings {
formatting: { dateFormat: 'smart' | 'iso' | 'custom'; customDateFormat: string }; formatting: { dateFormat: 'smart' | 'iso' | 'custom'; customDateFormat: string };
} }
// Defaults must match the authoritative spec §07 table exactly — that is the // The spec §07 table records these defaults — keep the two matching; this is
// contract; this is just where it's encoded. // just where they're encoded.
const DEFAULTS: UserSettings = { const DEFAULTS: UserSettings = {
version: CURRENT_SETTINGS_VERSION, version: CURRENT_SETTINGS_VERSION,
editor: { editor: {
@@ -351,7 +351,7 @@ detection + normalization + the dedupe/rename/id-reassign helpers; `core/export-
- browser IO (`infrastructure/file-transfer.ts`). The pure helpers are unit-tested - browser IO (`infrastructure/file-transfer.ts`). The pure helpers are unit-tested
hardest; `transfer.ts` only orchestrates (read stores → call core → commit → hardest; `transfer.ts` only orchestrates (read stores → call core → commit →
notify). The behavioral contract is spec §08. notify). The behavior is recorded in spec §08.
Three rules a future change must keep: Three rules a future change must keep:
@@ -6,7 +6,7 @@
> borrowing and the gotchas worth avoiding, so we don't rediscover them from scratch in > borrowing and the gotchas worth avoiding, so we don't rediscover them from scratch in
> M1/M2. > M1/M2.
> >
> It is a **reference**, not a contract. The behavioral contract is still [`docs/spec/`](../spec/); > It is a **reference**, not a contract. The behavioral record is still [`docs/spec/`](../spec/);
> the patterns are still docs [01](01-state-and-stores.md)[07](07-naming-and-relationships.md). > the patterns are still docs [01](01-state-and-stores.md)[07](07-naming-and-relationships.md).
> This doc is the bridge: "here is how the canonical implementation does the editor/renderer > This doc is the bridge: "here is how the canonical implementation does the editor/renderer
> plumbing, and here is what we keep vs. improve." > plumbing, and here is what we keep vs. improve."
+1 -1
View File
@@ -1,6 +1,6 @@
# 09 · Data Model & Persistence # 09 · Data Model & Persistence
This section defines the persistent entities of Astrolabe and how they relate. It is the authoritative data contract: an implementer recreating the app should store equivalent records with these fields and meanings. Types are given abstractly (string, number, boolean, ISO-timestamp string, string[], object, "JSON value") so they map onto any stack. "JSON value" means any valid JSON shape — object, array, string, number, boolean, or null. This section defines the persistent entities of Astrolabe and how they relate. It is the data record of the shipped app: an implementer recreating the app should store equivalent records with these fields and meanings. Types are given abstractly (string, number, boolean, ISO-timestamp string, string[], object, "JSON value") so they map onto any stack. "JSON value" means any valid JSON shape — object, array, string, number, boolean, or null.
All data lives entirely in the browser. There is no server, account, or sync. Records survive page reload and remain available offline (see _Application Shell & Navigation_). To move data between browsers or devices, use _Import & Export_. All data lives entirely in the browser. There is no server, account, or sync. Records survive page reload and remain available offline (see _Application Shell & Navigation_). To move data between browsers or devices, use _Import & Export_.
+1
View File
@@ -8,6 +8,7 @@ A UX/behavioral specification of **Astrolabe**, a browser-based snippet manager
- Each subsequent file is one feature area and can be read on its own; they cross-reference each other by title. - Each subsequent file is one feature area and can be read on its own; they cross-reference each other by title.
- Every section describes intended behavior plus testable acceptance points ("The user can…", "When X, the system…"). - Every section describes intended behavior plus testable acceptance points ("The user can…", "When X, the system…").
- Section numbers and lettered headings (e.g. `§03G`, `§09B`) are **stable anchors** — code comments reference them. Extend by appending the next letter/number; never renumber existing ones. - Section numbers and lettered headings (e.g. `§03G`, `§09B`) are **stable anchors** — code comments reference them. Extend by appending the next letter/number; never renumber existing ones.
- The spec is **descriptive**: it records what the shipped app does. The code leads — when the app and a section here disagree, the section is stale; rewrite it to match (deliberately) rather than treating it as a veto on the code.
## What this spec deliberately omits ## What this spec deliberately omits