Skip to content

Commit 8bf9c03

Browse files
committed
[guard.docs.rho.D8+] a construction-status page is the most rot-prone file in a repo, because it is what people write instead of measuring
STATUS.md would have been true for about a day. Gate 6 now checks the one part of it that can be checked mechanically — the facet inventory — in BOTH directions, and the two directions fail differently: a facet directory with no row -> UNDERSTATES the system (someone shipped and did not say). A reader cannot catch an omission. a row naming no directory -> OVERSTATES it (renamed or deleted, still advertised). A reader cannot catch this either, and this is the direction that becomes a lie. Keyed on the real path fragment `facets/<dir>/` rather than on prose: "the Fields facet" is not checkable, and a check keyed on wording would convict whoever rewrites a sentence — which is the backwards gate this repo already argued against when the physics README gate was built. RED PROOF, both directions, through scripts/lib/mutate.mjs so the mutation is asserted to have changed the bytes before any verdict is read: dropping `facets/field-wields/` -> exit 1 "has no row in"; renaming `facets/bond-atlas/` to a facet that does not exist -> exit 1 "does not exist on disk"; restored -> exit 0, STATUS.md byte-identical. Also: the four documents now declare their own division of labour at the top of ARCHITECTURE.md, by ROT RATE rather than by topic — architecture rots when a layer boundary moves, the spec when a contract changes, STATUS on any commit, ROADMAP when the terminal state changes. That is the reason they are four files and not one: a document that mixes a yearly fact with a per-commit fact is stale on the day it is written, and the per-commit half is what gets believed. Deployment status is now stated in exactly ONE place (STATUS.md) with the short version repeated at the top of ARCHITECTURE.md, because that question — "is any of this live?" — is the one a reader asks first and the one this repo answered wrongly by accident for weeks.
1 parent 6e4b1b5 commit 8bf9c03

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

‎ARCHITECTURE.md‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@
22

33
This is the WHY and the growth map. For the WHAT — types, wire schemas, state
44
machines, failure model, named constants — read `SPEC.md`; this file does not
5-
restate it. Verified against `HEAD` `54c24d4`, 2026-08-11. The previous version
5+
restate it. **Four documents, four rot rates, one home per fact:**
6+
7+
| document | answers | rots when |
8+
|---|---|---|
9+
| `ARCHITECTURE.md` | why the layers are cut where they are | a layer boundary moves |
10+
| `SPEC.md` | the interfaces, flows and failure model | a contract changes |
11+
| `STATUS.md` | what is actually built, and what is a seam with nothing writing to it | any commit |
12+
| `ROADMAP.md` | how these seams reach the terminal state without a rewrite | the terminal state changes |
13+
14+
**Deployment status lives in exactly one place — `STATUS.md`.** Short version, so
15+
nobody has to guess: NOT DEPLOYED, no auth, no public URL, three hand-started
16+
processes. Verified against `HEAD` `54c24d4`, 2026-08-11. The previous version
617
of this file (removed here) was written 25 commits earlier, at `545f9f2`
718
(2026-08-10 20:30) — before either of the two migrations that this document is
819
mostly about existed. It described an `/embed` endpoint that returns "a

‎SPEC.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ N: 8901-endpoints=2 consumers · facet-callsites=11 · field_cube-writers(py)=1
44
spec-budget: 600 lines / one session
55
staleness-predicate: `python3 ~/.claude/skills/software-spec/scripts/spec_lint.py SPEC.md --rerun`
66
INTERFACE: `contracts/iface.pyi` (Python half) · `contracts/iface.d.ts` (TS half)
7+
BUILD STATE: `STATUS.md` (what is shipped vs a seam with no writer) · `ROADMAP.md` (the phases and their rewrite tripwires). This spec describes the contracts, NOT how much of them is wired — asking one document to be both is how a spec starts lying about a system that has moved.
78
FIGURE-2: §4 = the two stubs + the three STATE×EVENT tables + JOIN LEDGER + CONSTANT LEDGER + failure cells. Prose outside §4 is WHY.
89

910
## 0 · MEASUREMENT

‎scripts/check_docs_facts.mjs‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,53 @@ for (const relFile of COMMAND_DOC_FILES) {
310310
}
311311
}
312312

313+
// ─────────────────────────────────────────────────────────────────────────
314+
// 3. STATUS.md's FACET TABLE vs the facets on disk — BOTH directions
315+
//
316+
// A construction-status document is the single most rot-prone artifact in a
317+
// repo, because it is the one people write instead of measuring. This check
318+
// makes the facet inventory the part that cannot drift: a facet directory with
319+
// no row is UNDOCUMENTED (someone shipped and did not say), and a row naming a
320+
// directory that does not exist is a STALE CLAIM (something was renamed or
321+
// removed and the status page still advertises it).
322+
//
323+
// Both directions matter and they fail differently: the first understates the
324+
// system, the second overstates it. Only one of those gets caught by a reader.
325+
// ─────────────────────────────────────────────────────────────────────────
326+
{
327+
const FACET_DIR = 'src/app.frontend.facets.molstar-rdkit.editable/facets';
328+
let dirs = [];
329+
try {
330+
dirs = fs.readdirSync(path.join(ROOT, FACET_DIR), { withFileTypes: true })
331+
.filter(d => d.isDirectory() && !d.name.startsWith('_'))
332+
.map(d => d.name);
333+
} catch (e) {
334+
violate('STATUS.md', 0, `cannot read ${FACET_DIR} (${e.message}) — this check is `
335+
+ 'BLIND, which is not the same as passing');
336+
}
337+
if (dirs.length) {
338+
const statusText = read('STATUS.md');
339+
// A row must reference the facet by its real path fragment, not by a
340+
// prose name: `facets/field-wells/` is checkable, "the Fields facet" is
341+
// not, and a check keyed on prose would convict on rewording.
342+
for (const d of dirs) {
343+
if (!statusText.includes(`facets/${d}/`)) {
344+
violate('STATUS.md', 0, `facet \`${FACET_DIR}/${d}/\` has no row in `
345+
+ `STATUS.md — an undocumented facet makes the status page understate `
346+
+ `the system, and nobody notices an omission`);
347+
}
348+
}
349+
for (const m of statusText.matchAll(/facets\/([a-z0-9-]+)\//g)) {
350+
if (!dirs.includes(m[1])) {
351+
violate('STATUS.md', 0, `STATUS.md claims a facet \`facets/${m[1]}/\` that `
352+
+ `does not exist on disk — a stale claim OVERSTATES the system, which `
353+
+ `is the direction a reader cannot catch`);
354+
}
355+
}
356+
info.push(`STATUS.md facet table: ${dirs.length} facet directories, both directions checked`);
357+
}
358+
}
359+
313360
// ─────────────────────────────────────────────────────────────────────────
314361
// REPORT
315362
// ─────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)