diff --git a/CHANGELOG.md b/CHANGELOG.md index 55dfa15..eeacecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Entries are newest-first. Dates are UTC, ISO 8601 (§14). Versioning policy: bum for upstream skill changes, registry updates (§2.1, §15.1), factual corrections to normative content, and brand/identity changes. +- **v1.47 (2026-08-09):** **§17.1 and §17.2 rewritten — progress reports become a labelled-row block.** The format §17.1 has carried since the section was written packed every figure into three dense lines: a single unlabelled bar, then all milestones pipe-separated on one line, then MVP and PRD sharing a third. Only one of those numbers — the PRD total — ever got a bar, so the milestones and the MVP were reported as bare percentages while the least granular figure got the only visual. Reading it meant parsing a run-on line to find the milestone you cared about, and comparing two milestones meant comparing two integers rather than two bars. The replacement gives **every track its own row, its own 20-cell bar, and its own percentage**, in a fixed order: milestone rows `M0`…`Mn` ascending, then `MVP`, then `TODO`, then `PLAN`, then `PRD`. **`TODO` and `PLAN` are new tracks** — the old format had no way to report against a plan document or a task list at all, so work driven by either was reported against a PRD that did not exist. **Only applicable rows are emitted**, and this is a rule rather than a convenience: the milestone rows match the milestones the plan actually defines (`M0`–`M4` in the template is an illustration, not a required set), `TODO`/`PLAN`/`PRD` appear only when the task is driven by such an artifact, and `MVP` is always present. Padding the block out with fabricated 0% rows is forbidden — a track that does not exist reports progress against nothing, and a reader cannot tell a genuine zero from a placeholder. **§17.2 now defines two cell styles, and the distinction is normative.** Milestone, `TODO`, `PLAN` and `PRD` rows use `█` (U+2588) filled and `░` (U+2591) empty with tight brackets; the `MVP` row uses `▰` (U+25B0) and `▱` (U+25B1) with padded brackets, `[ `…` ]`. MVP is the headline figure and the rows around it are the inputs that feed it, so it is set in a different glyph pair to stay findable at a glance in a stack of otherwise identical bars — the `▰`/`▱` pair that was the whole of §17.2 before this version is retained for exactly that one row rather than retired. **Column alignment is normative, and the bracket padding is what preserves it**: the MVP row is one character narrower in its label field and one character wider inside each bracket, so every bar cell and every percentage digit lands in the same column across the whole block. Stated as rules — label-plus-colon left-aligned in a six-character field on every row but MVP, five on MVP followed by `[` and a space; every bar in columns 8 through 27 on both; percentage right-aligned so its `%` lands in the same column on every row, which means two spaces after the closing bracket on the tight rows and one on `MVP`, with the separator never dropping below one space (so at 100% the `MVP` percentage sits one column right — the only value at which the two row types do not align, and preferable to a bracket abutting a digit). **Cell count is specified for the first time.** The old text said "20-character" and left the mapping from percentage to cells entirely unstated, so 43% could legitimately render as 8 cells or 9. It is now the percentage scaled to twenty cells and rounded to the nearest cell, with two saturation rules overriding the rounding: twenty filled cells **only** at exactly 100%, zero filled **only** at exactly 0%. Rounding 99% up to a visually complete bar reports work as finished that is not — precisely the drift §17 exists to catch. Unchanged: **§17.3's cadence** (baseline at task start, at each milestone completion, and in the end-of-turn summary), and the prohibition on legacy ASCII bars, now stated for `#`, `-` and `=` and binding on every row rather than on "the progress bar" singular. §16's §17 checklist bullet is rewritten from the old three-figure summary to the row-block form. - **v1.46 (2026-08-08):** **§5.7 added — Agent Context Files.** §5.2 has enumerated the required root files since the standard's early versions and never named the one file every coding agent actually reads. That silence was not neutral: in its absence each project invented its own arrangement, and a survey of the umbrella found five incompatible conventions running simultaneously across ~39 repositories — byte-identical twins (`sonde`), a symlink (`achernar`), a declared superset (`copy/cpx`, `pearlite`), a thin pointer in one direction (`flux`, `tachyon`, `os-prober`), and genuinely divergent files each holding facts the other lacked (`anvil`, `bravais`, `gitway`, `loran`, `zamak`). The failure mode is specific and silent. `AGENTS.md` is the cross-vendor convention (Codex CLI, Cursor, Aider, OpenCode, Goose); Claude Code reads `CLAUDE.md`. When both exist as parallel prose they are edited in different sessions and drift, and **the agent reading the stale copy is never told it is stale** — it proceeds confidently on a build command that changed six weeks ago. Several files had already noticed and responded with the wrong remedy, carrying explicit "whenever you update CLAUDE.md, update AGENTS.md in the same pass" instructions: a maintenance tax paid manually, forever, that the drift proves was not being paid. §5.7 makes **`AGENTS.md` the single authority** — required at every project root alongside the §5.2 files, harness-neutral, carrying build/test/lint commands, architectural invariants, forbidden patterns, layout, and every fact an agent cannot infer from the code. `CLAUDE.md`, where a project ships one, becomes an **`@AGENTS.md` import plus only what is meaningless to a non-Claude harness** — Skill-tool invocations, `.claude/` paths, slash commands, Claude-client MCP configuration — and MUST NOT restate, summarize, or mirror it. Five rules attach. **Write to `AGENTS.md`**: new project knowledge goes there by default, and "update the context file" always means `AGENTS.md`; this is the rule that keeps the overlay from re-growing into a second copy one session at a time. **No duplication**, with the corollary that a "keep these in sync" instruction is evidence the split is wrong and MUST be removed rather than honored. **Both tracked** — a `.gitignore` entry for either breaks the `@AGENTS.md` import on a fresh clone and hides project knowledge from every contributor who did not author it; 15 of the surveyed repositories were ignoring one or both. **No secrets**, which is the clause that makes the tracking rule safe rather than merely tidy: context files become published artifacts, so credentials, tokens, keys, private hostnames or network topology, and personal filesystem paths are out, and a file that was previously ignored MUST be reviewed for sensitive content *before* it is un-ignored — a file that was safe as a local scratchpad has not thereby been cleared for publication, and un-ignoring is effectively irreversible once pushed. **Generated blocks target `AGENTS.md` only**: tooling that renders managed regions into context files — rule synchronizers, task systems — reintroduces exactly the duplication the import removes if it writes both, so the obligation is placed on the tooling rather than left for a human to notice. Other harness files (`GEMINI.md`, `.cursorrules`) follow the `CLAUDE.md` pattern rather than earning clauses of their own. This section **inverts the guidance previously carried only in the `spacecraft-agentic-cli` skill**, which instructed authors to make `CLAUDE.md` a strict superset of `AGENTS.md` and to start by symlinking or copying it — a rule that produced the duplication by construction and that every new scaffold reproduced. That skill's `references/agents-md-authoring.md` and both `assets/` templates are rewritten to match, and the Skill Cross-References table gains a `spacecraft-agentic-cli` row for context-file authoring, which had never appeared there despite the skill being the implementation layer for it. §16 gains a §5.7 checklist bullet. Nothing in §5.2 changes: `AGENTS.md` is added to the required set, and no existing required file is relaxed or removed. - **v1.45 (2026-08-06):** **§11.6 added — System Theme Declaration & Resolution.** §11 has been a palette *family* since v1.35 and §11.1 has required every palette reference to go through a named theme since v1.34, yet nothing in the document said what an application does when the *machine* has an opinion. The gap was invisible from both ends: §11.1 answers "how do I reference a color", §11.4 answers "which palette is mine", and neither question is "which member of the family renders on this system, right now" — so an application could satisfy every clause in §11 while shipping exactly one hard-wired theme, deaf to the desktop it runs on. Steelbore OS has meanwhile had a theme declaration for months — Bravais's `theme.nix` is a single word that re-themes every terminal, both bars, the TTY and greetd from one slug — which made the omission look like it did not exist. It ends at a rebuild: that machinery resolves at build time and exports per-role hex but never the slug, so a *running* application can see individual colors and still not learn which theme is active, nor whether high contrast or mono is in force. §11.6 closes it from both sides. **Applications register the family, not a theme.** §11.6.1 separates two obligations §11.4 had conflated: a project *authors* against one palette and *registers* thirteen — the six conforming palettes (`steelbore`, `steelbore-blue`, `steelbore-blackpinkpanther`, `steelbore-matrixgreen`, `steelbore-navywhite`, `tokyonight`), each with its `-high-contrast` sibling, plus `steelbore-mono`. Three were already required by §11.4 and §11.1.1, so the section adds ten, all of them already written out in `steelbore.toml`; every one binds the same eleven role tokens, so a theme layer that reads that file registers them in a loop. `steelbore-classic` is deliberately **not** in the mandatory set: it keeps the legacy six-role contract (§11.2), defines no surface class, and carries an `info` token that is not one of §11.1's eleven roles at all, so it is registrable only by an application that implements that contract too. **Resolution is two-stage, and that is the load-bearing decision.** Stage 1 picks a base palette from five sources — in-app selection, `SPACECRAFT_THEME`, the system declaration, the platform's light/dark preference, then the project's §11.4 default. Stage 2 picks a *variant of that palette* — a pinned `-high-contrast`/`-mono` slug, then `NO_COLOR` ⇒ `steelbore-mono`, then §18.1 accessible mode, then the platform's high-contrast preference under the §18.3 precedent that a system-wide preference has already been expressed. Keeping the stages apart is what makes the section composable: an accessibility signal chooses a *sibling*, never a palette, so it can never silently change the brand — exactly the promise §11.1.1 has made since v1.33. §18.1's four-source precedence is consumed, not restated and not modified; there is still one switch. An unknown or unregistered slug **falls through to the next source and is never fatal**, so a typo in `/etc` cannot leave a machine without a working interface (§3.1, graceful degradation), and the resolved theme plus the source that decided it are reported under `--verbose`, as §18.1 already requires of accessible mode. **Light and dark needed §11.4 read precisely.** `steelbore-navywhite` is the family's only light-canvas member, so a platform light preference cannot be answered by lifting a token — only by rendering a different palette. §11.6.2 states plainly that §11.4 forbids *combining* tokens from two palettes and that a color-scheme switch combines nothing: the entire token set is replaced at once, the new canvas comes with it unaltered, and no frame ever carries a token from two palettes. **Switching is compliant; mixing remains forbidden** — with two hard rules attached, that the switch is atomic and whole-surface (an application that cannot re-theme atomically resolves once at startup and holds), and that the canvas travels with the palette. The family pair is `steelbore` ⇄ `steelbore-navywhite`; a project may declare its own, or declare `light = none` with a stated reason on the §14.2.1 documented-exception footing, which buys it nothing under §18. Solarized Dark and Light are a natural pair upstream and §11.5 bars both from adoption, so neither may ever be the target of the color-scheme source. **The declaration is a file, deliberately.** `/etc/steelbore/theme.toml`, overridden per user by `$XDG_CONFIG_HOME/steelbore/theme.toml`, carrying `active` (required), an optional `light`/`dark` pair, `follow-color-scheme`, and `high-contrast`. A file, not a bus: the contract has to work for a CLI in a text console, where there is no session bus, no portal, and no portable way to ask the terminal what color its background is — which is why the platform color-scheme source is graphical-only and why the file is the channel that reaches everything else. Absence of the file is *no declaration*; a file saying `active = "steelbore"` is a declaration *of Modern*, and the distinction matters because a system may need to pin Modern rather than inherit whatever the default later becomes. **The declaration carries slugs and never colors** — the same division §13 draws for component systems, where the platform chooses the widget vocabulary and never supplies the palette; an OS-installed theme registry is advisory and the application's own `steelbore.toml` governs, so per-role color environment variables are explicitly *not* a Standard interface. The variable is **`SPACECRAFT_THEME`**, in the umbrella-wide `SPACECRAFT_` namespace §18.1 established with `SPACECRAFT_A11Y`; `STEELBORE_THEME` is named as **not** a Standard interface, because it is already in use as a boolean shell flag and giving it slug semantics would make `STEELBORE_THEME=true` resolve to a theme that does not exist and fall through in silence. **§11.6.5** puts the symmetrical obligation on Steelbore OS in every flavor: render the declaration from its own selection rather than maintain it by hand, export the slug so it reaches graphical sessions and system services rather than login shells alone, keep the platform's color-scheme preference in agreement with the declared palette's polarity, and validate the slug at evaluation time so an unknown theme fails the build rather than the boot. **Scope is both namespaces §6.4 authorizes** — `Spacecraft-Software` and `UnbreakableMJ` — and all three interface classes: a CLI is not exempt, because it already honors `NO_COLOR` and already emits ANSI, so it already has a theme whether or not it names one. Libraries and anything with no user-facing output record §11.6 as N/A. Registered games are **not** exempt: §18.5 carves out §18 and §10, never §11, and a game satisfies this section in its menus, HUD, and settings chrome, not in the world it simulates. Three things are unchanged. **`steelbore` is still the sole default** — §11.6 changes what an application *can* render, never what it renders when nothing is declared, which remains the project's §11.4 palette and Modern where none is declared. **§11.4's mixing prohibition is unchanged**, and is now stated precisely enough to be enforceable. **§18 is unchanged** — §11.6 reads its resolved state and adds no accessibility rule of its own; a declaration file's `high-contrast` key selects a theme sibling and is explicitly barred from being read as enabling accessible mode. §11.4 gains two bullets and three amended ones; §16 gains a §11.6 bullet rather than lengthening the §11 one; the Skill Cross-References table gains a `steelbore-color-palette` row, closing a smaller gap found in the same pass — the skill has been the normatively cited canonical source in §11.4 since v1.39 and had never appeared in the table that tells a reader which skill to load. Recorded as a factual correction in the same entry: the §11 chapter-head palette-family table listed six slugs where `[meta] palette-family` in `steelbore.toml` and §11.4.1 both list seven — **`tokyonight` was missing** from the one table a reader consults first, present everywhere else since v1.39. It is added, and the table gains a canvas-polarity column, which §11.6.2 now makes normative content rather than an observation. - **v1.44 (2026-08-05):** **Skill Cross-References corrected — the accessibility row named a skill that does not exist.** The table pointed at `spacecraft-accessibility`; the skill has been `spacecraft-accessibility-support` since it was added. An agent following the Standard to find the §18 implementation layer would have looked for a directory that is not there, and the failure mode is silent — a missing skill does not announce itself, it simply never loads, so §18 work would proceed without the reference the Standard directs it to. The row now names the skill correctly. Nothing else in the table changed, and every other skill name it cites was verified against the catalogue in the same pass. The drift was pure naming: `spacecraft-standard-constitution`'s own cross-reference table has carried the correct name throughout, so the two documents disagreed and the published one was wrong — a reminder that a cross-reference is normative content like any other clause, and that renaming a skill is a two-repo edit. This entry records a factual correction only; no rule changes, and no section text was touched. diff --git a/The_Steelbore_Standard.md b/The_Steelbore_Standard.md index 0e14668..a8667a4 100644 --- a/The_Steelbore_Standard.md +++ b/The_Steelbore_Standard.md @@ -29,7 +29,7 @@ repository](https://github.com/Spacecraft-Software/Standard), newest entry first. It is kept out of this document so the standard reads as the rules *in force* rather than the record of how they got there. -This document is **version 1.46**, updated 2026-08-08 (§14: UTC, ISO +This document is **version 1.47**, updated 2026-08-09 (§14: UTC, ISO 8601). The skill encoding of the standard keeps a parallel history in `spacecraft-standard-constitution/references/CHANGELOG.md` in the [Construct @@ -2057,22 +2057,81 @@ implementation status of key milestones. ## §17.1 — Progress Reporting Format -Every progress report must include the percentage of completion for -individual milestones, the overall progress of the Minimum Viable -Product (MVP), and the total progress of the PRD. +A progress report is a block of labelled rows, one row per tracked +track. Every row carries its own 20-cell bar and its own percentage, so +each figure is legible on its own line rather than compressed into a +shared summary line. **Format template:** - [Progress: ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱] 70% - Milestones: M0: 100% | M1: 100% | M2: 70% | M3: 0% | M4: 0% - Product Status: MVP: 90% | PRD: 70% + M0: [████████████░░░░░░░░] 60% + M1: [████████████░░░░░░░░] 60% + M2: [████████████░░░░░░░░] 60% + M3: [████████████░░░░░░░░] 60% + M4: [████████████░░░░░░░░] 60% + MVP: [ ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱ ] 70% + TODO: [████████████░░░░░░░░] 60% + PLAN: [████████████░░░░░░░░] 60% + PRD: [████████████░░░░░░░░] 60% + +**Row order** is fixed: milestone rows `M0`…`Mn` in ascending order, +then `MVP`, then `TODO`, then `PLAN`, then `PRD`. + +**Only applicable rows are emitted.** The milestone rows match the +milestones the plan actually defines — there is no fixed count, and +`M0`–`M4` in the template above is an illustration, not a required set. +`TODO`, `PLAN`, and `PRD` each appear only when the task is driven by +such an artifact. `MVP` is always present. A row is never padded in at +0% to fill out the block: a fabricated track reports progress against +nothing and misrepresents the work. ## §17.2 — Progress Bar Style -The progress bar must use high-visibility Unicode block characters -(e.g., `▰` for filled and `▱` for empty) to form a clean, static, -20-character visual representation of total PRD completion. Do not use -legacy ASCII characters like `#` or `-` for the progress bar. +Every bar is a static, 20-cell, high-visibility Unicode bar. Legacy +ASCII characters — `#`, `-`, `=` — are forbidden in any bar. + +Two cell styles are in use, and the distinction is normative: + +| Rows | Filled | Empty | Brackets | +|----|----|----|----| +| Milestones, `TODO`, `PLAN`, `PRD` | `█` (U+2588) | `░` (U+2591) | Tight — no space inside either bracket | +| `MVP` | `▰` (U+25B0) | `▱` (U+25B1) | Padded — exactly one space inside each bracket | + +The MVP row is deliberately set apart: it is the headline figure, and +the tracks above and below it are the inputs that feed it. Its distinct +glyph pair makes it findable at a glance in a stack of otherwise +identical bars. + +**Column alignment is normative.** The MVP row’s bracket padding exists +to preserve it — the row is one character narrower in its label field +and one character wider inside each bracket, so every bar cell and every +percentage digit lands in the same column across the whole block. + +- On every row other than `MVP`, the label and its colon are + left-aligned in a six-character field, followed immediately by `[`. + +- On the `MVP` row, `MVP:` is left-aligned in a five-character field, + followed by `[` and one space. + +- Both place the first bar cell in column 8, so every bar occupies + columns 8 through 27. + +- The percentage is right-aligned so its `%` sign lands in the same + column on every row — two spaces after the closing bracket on the + tight-bracket rows, one on the `MVP` row. That difference is exactly + what the padded brackets buy. + +- The separator never drops below one space. At 100% the `MVP` row keeps + its single space and its percentage therefore sits one column right — + the only value at which the two row types do not align, and preferable + to a bracket abutting a digit. + +**Cell count.** The number of filled cells is the percentage scaled to +twenty cells and rounded to the nearest cell. Two saturation rules +override the rounding: a bar shows twenty filled cells **only** at +exactly 100%, and zero filled cells **only** at exactly 0%. Rounding 99% +up to a visually complete bar reports work as finished that is not, +which is the drift this chapter exists to catch. ## §17.3 — Reporting Cadence @@ -2462,9 +2521,11 @@ Before finalising **any** Spacecraft Software artifact, mentally verify: `references/ATTRIBUTION.md` present where reference content is adapted from external sources -- [ ] **§17** Development progress tracked and reported continuously - with milestone percentages, MVP, total PRD completion, and a Unicode - progress bar +- [ ] **§17** Development progress tracked and reported continuously as + the §17.1 labelled-row block — one 20-cell bar per track, milestone + rows then MVP then TODO/PLAN/PRD, only the rows that apply; MVP set in + `▰`/`▱` with padded brackets and every other row in `█`/`░`, columns + aligned, no ASCII bars - [ ] **§18** Accessible mode implemented and off by default; §18.1 toggle honored with correct precedence; status never color-only; no diff --git a/The_Steelbore_Standard.texi b/The_Steelbore_Standard.texi index 30b6bce..c68fef3 100644 --- a/The_Steelbore_Standard.texi +++ b/The_Steelbore_Standard.texi @@ -5,11 +5,11 @@ @setfilename The_Steelbore_Standard.info @documentencoding UTF-8 @documentlanguage en -@settitle The Steelbore Standard 1.46 +@settitle The Steelbore Standard 1.47 @c %**end of header -@set VERSION 1.46 -@set UPDATED 2026-08-08 +@set VERSION 1.47 +@set UPDATED 2026-08-09 @set SUBDOMAIN https://Standard.SpacecraftSoftware.org/ @copying @@ -3730,18 +3730,61 @@ When implementing features or writing code based on a Product Requirements Docum @section §17.1 — Progress Reporting Format -Every progress report must include the percentage of completion for individual milestones, the overall progress of the Minimum Viable Product (MVP), and the total progress of the PRD. +A progress report is a block of labelled rows, one row per tracked track. Every row carries its own 20-cell bar and its own percentage, so each figure is legible on its own line rather than compressed into a shared summary line. @strong{Format template:} @example -[Progress: ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱] 70% -Milestones: M0: 100% | M1: 100% | M2: 70% | M3: 0% | M4: 0% -Product Status: MVP: 90% | PRD: 70% +M0: [████████████░░░░░░░░] 60% +M1: [████████████░░░░░░░░] 60% +M2: [████████████░░░░░░░░] 60% +M3: [████████████░░░░░░░░] 60% +M4: [████████████░░░░░░░░] 60% +MVP: [ ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱ ] 70% +TODO: [████████████░░░░░░░░] 60% +PLAN: [████████████░░░░░░░░] 60% +PRD: [████████████░░░░░░░░] 60% @end example +@strong{Row order} is fixed: milestone rows @code{M0}…@code{Mn} in ascending order, then @code{MVP}, then @code{TODO}, then @code{PLAN}, then @code{PRD}. + +@strong{Only applicable rows are emitted.} The milestone rows match the milestones the plan actually defines — there is no fixed count, and @code{M0}–@code{M4} in the template above is an illustration, not a required set. @code{TODO}, @code{PLAN}, and @code{PRD} each appear only when the task is driven by such an artifact. @code{MVP} is always present. A row is never padded in at 0% to fill out the block: a fabricated track reports progress against nothing and misrepresents the work. + @section §17.2 — Progress Bar Style -The progress bar must use high-visibility Unicode block characters (e.g., @code{▰} for filled and @code{▱} for empty) to form a clean, static, 20-character visual representation of total PRD completion. Do not use legacy ASCII characters like @code{#} or @code{-} for the progress bar. +Every bar is a static, 20-cell, high-visibility Unicode bar. Legacy ASCII characters — @code{#}, @code{-}, @code{=} — are forbidden in any bar. + +Two cell styles are in use, and the distinction is normative: + +@multitable @columnfractions .22 .18 .18 .42 +@headitem Rows @tab Filled @tab Empty @tab Brackets +@item Milestones, @code{TODO}, @code{PLAN}, @code{PRD} +@tab @code{█} (U+2588) +@tab @code{░} (U+2591) +@tab Tight — no space inside either bracket +@item @code{MVP} +@tab @code{▰} (U+25B0) +@tab @code{▱} (U+25B1) +@tab Padded — exactly one space inside each bracket +@end multitable + +The MVP row is deliberately set apart: it is the headline figure, and the tracks above and below it are the inputs that feed it. Its distinct glyph pair makes it findable at a glance in a stack of otherwise identical bars. + +@strong{Column alignment is normative.} The MVP row's bracket padding exists to preserve it — the row is one character narrower in its label field and one character wider inside each bracket, so every bar cell and every percentage digit lands in the same column across the whole block. + +@itemize +@item +On every row other than @code{MVP}, the label and its colon are left-aligned in a six-character field, followed immediately by @code{[}. +@item +On the @code{MVP} row, @code{MVP:} is left-aligned in a five-character field, followed by @code{[} and one space. +@item +Both place the first bar cell in column 8, so every bar occupies columns 8 through 27. +@item +The percentage is right-aligned so its @code{%} sign lands in the same column on every row — two spaces after the closing bracket on the tight-bracket rows, one on the @code{MVP} row. That difference is exactly what the padded brackets buy. +@item +The separator never drops below one space. At 100% the @code{MVP} row keeps its single space and its percentage therefore sits one column right — the only value at which the two row types do not align, and preferable to a bracket abutting a digit. +@end itemize + +@strong{Cell count.} The number of filled cells is the percentage scaled to twenty cells and rounded to the nearest cell. Two saturation rules override the rounding: a bar shows twenty filled cells @strong{only} at exactly 100%, and zero filled cells @strong{only} at exactly 0%. Rounding 99% up to a visually complete bar reports work as finished that is not, which is the drift this chapter exists to catch. @section §17.3 — Reporting Cadence @@ -4236,9 +4279,11 @@ project/skill root when triggers apply; deeper @code{references/ATTRIBUTION.md} present where reference content is adapted from external sources @item -☐ @strong{§17} Development progress tracked and reported continuously -with milestone percentages, MVP, total PRD completion, and a Unicode -progress bar +☐ @strong{§17} Development progress tracked and reported continuously as +the §17.1 labelled-row block — one 20-cell bar per track, milestone rows +then MVP then TODO/PLAN/PRD, only the rows that apply; MVP set in +@code{▰}/@code{▱} with padded brackets and every other row in +@code{█}/@code{░}, columns aligned, no ASCII bars @item ☐ @strong{§18} Accessible mode implemented and off by default; §18.1 toggle honored with correct precedence; status never color-only; no