Skip to content

docs: three trees, three audiences, and the rule for citing between them - #590

Merged
speak-agent merged 36 commits into
mainfrom
docs/architecture-three-trees
Sep 8, 2026
Merged

docs: three trees, three audiences, and the rule for citing between them#590
speak-agent merged 36 commits into
mainfrom
docs/architecture-three-trees

Conversation

@speak-agent

Copy link
Copy Markdown
Member

Three documentation trees, three audiences, and the rule for citing between
them. The design record is
.agents/docs/2026-09-08-documentation-architecture-three-trees.md; the style
skill it follows is .agents/skills/mcpp-docs-style/SKILL.md.

What this started from

Measured against origin/main at 6e1c65c6:

tree files lines index
docs/ chapters 23 11,313 35 lines
docs/specs/ 5 1,156 42 lines
.agents/docs/ 268 109,146 one heading, no body

Seven defects, each independently verifiable:

  1. The three-way division of labour was stated once, in
    docs/specs/README.md — two levels down, in the tree with the narrowest
    audience. docs/README.md did not mention it.
  2. The specifications are 简体中文 inside the English tree with no mirror.
  3. check_docs_style.sh iterated docs/*.md docs/zh/*.md, which does not
    descend, so the specifications were exempt by accident. Defect 2 is its
    visible consequence.
  4. docs/README.md listed two of four specifications.
  5. Nine user chapters sent a reader to .agents/docs/….
  6. Six code comments named chapters that have not existed since an earlier
    numbering.
  7. The design tree had no status and no taxonomy: 65 of 268 filenames carry
    none of the sixteen classifier words in use.

What changed

The architecture is published. docs/README.md and docs/zh/README.md
state what each tree holds, carry a role index mapping an intention to chapters,
examples and templates, and group the chapters into seven parts. Parts VI and
VII separate the chapters written for tool authors and for maintainers — 04,
08 and 09 stop reading as steps four, eight and nine of a user's path.
No chapter is renumbered: docs/NN- is cited from 103 files including
source and CI.

User documentation is a usage manual again. Every .agents/ pointer is
removed; docs/20's "Not implemented" becomes "Current limitations", a list of
facts rather than the argument for each gap, and gains the two device extensions
no published rule package claims.

05 stops being four essays inside a field reference. 3,129 → 1,626 lines.
cxx_runtime → 03, [target.*] → 14, [xlings] → 17, host tools → 07,
[hooks] → 21, features → new chapter 22. A pointer stays at each old
section so its number keeps its place.

Chapter 23 — Authoring a Rule Package is new: the manifest keys, the four
action roles, declared inputs, depfiles, chained actions, the payload
declaration's two gates, the island boundary's four rungs, the reporting
channels. device_extensions and rule_module were documented nowhere in
docs/.

01 is the curriculum: six tracks, what each example is the first to
teach, the criterion for when a capability earns an example rather than a code
block, and the third teaching surface — project templates, which is where the
bare-metal lesson actually lives.

The design tree has a generated index (gen_agents_index.py), by date with
each record's own title, plus subject / status front matter required on new
records. The 268 that predate the convention are not rewritten.

Three new examples

Each is the first in the tree to demonstrate what it demonstrates, and each was
built and run:

example criterion measured
09-heterogeneous/boundary the consumer imports the generated module; no seam, no header, no hand-written .cppm 12 24 36 48; grep -rn '#include' src/ empty
11-features the default build's resolution does not name the optional package counters 0 times without the feature, 2 with it
12-a-new-device-language a .toy compiles and joins the link on an engine that does not know the extension; editing the source and editing the compiler both reach the artifact 42; 42 → 43; 42 → 142

boundary/ also runs an arrangement that mcpp:plugins records as measured and
that nothing in either repository was exercising.

Checks

check_docs_structure.sh is new, nine rules, each falsified before it was
committed
— the fix removed, the check run, the failure read. The metadata
rule was strengthened after the first version passed a spec whose
implementation-version row had been deleted.

The register rules now cover docs/specs/. The parity loop still does not: the
language question is open (design record §6.2, §11.1) and is not something a
script should assert.

What the review pass found

Reading the rendered text rather than the diff, per the skill's own rule:

  • Fourteen §2.x cross-references, in both languages, left pointing at section
    numbers that had moved with the sections. A mechanical move keeps every
    heading structure valid and leaves the prose pointing at the old shape.
  • Chapter 17's "Related chapters" had ended up mid-chapter, and its bullet for
    05 claimed "every manifest key, including [xlings]" — the one claim the move
    made false.
  • Two rules written in the skill and not applied: chapter 22 had no
    "Current limitations", and "every document states which rung it is on" was
    followed by nothing. The first is fixed; the second became a rule that is
    actually useful — a "Related documents" line naming the rung above and below.

Not in this PR, and why

  • Translating the specifications (1,156 lines). The design record recommends
    English primary with a 简体中文 mirror and lists it as an open question; doing
    it before that is decided is the wrong order.
  • SPEC-005 / SPEC-006 (the compatibility tag, the directive protocol). Each
    is a promotion of existing text and its own review.
  • mcpp emit xpkg / mcpp xpkg parse disagree: the emitted descriptor for
    a package that keeps its own mcpp.toml carries no sources list and the
    validator requires one. Isolated, reproducible, and recorded as a current
    limitation in docs/21 rather than fixed here.

Source changes are comment-only (nine files, repointed chapter citations).

… citation leaks

The division of labour between user documentation, specifications and design
records existed as a table in docs/specs/README.md -- two levels down, in the
tree with the narrowest audience. docs/README.md, where a reader arrives, did
not mention it. Nothing enforced the division because nothing published it.

docs/README.md and docs/zh/README.md now state what each tree holds, index the
chapters by part rather than as one numbered run, and carry a role index that
maps an intention to chapters, examples and templates. Parts VI and VII separate
the chapters written for tool authors and for maintainers from the chapters
written for users; the numbers do not move, because docs/NN- is cited from 103
files including source and CI.

Two of the four specifications were absent from the front page. All four are
listed now.

Nine user chapters sent a reader to `.agents/docs/...`. A design record
describes a moment and carries no stability promise, so a chapter that ends in
one has delegated a question it should have answered. Each pointer is removed;
docs/20's "Not implemented" section becomes "Current limitations", a list of
facts rather than the argument for each gap, and gains the two device
extensions that no published rule package claims.

Six code comments named chapters that do not exist -- survivors of an earlier
numbering. `docs/35-pack-design.md`, `docs/04-schema-xpkg-extension.md`,
`docs/34-release-readiness.md`, `docs/11-gcc15-cookbook.md`,
`docs/14-data-layout.md`, `docs/21-toolchain-and-tools.md` and
`docs/27-p1689-dyndep.md` are repointed or dropped. Every `docs/NN-*.md` path
named outside `.agents/` now resolves.

The style skill states the architecture this follows: which tree a document
belongs to, that docs/ is a usage manual for what is implemented rather than a
design account, the citation direction, the gradient, the coverage a surface
owes, and the review criteria.
check_docs_style.sh covers the register. check_docs_structure.sh covers the
architecture the style skill states: a user chapter may not cite a design
record, a specification may cite one only in its metadata table, every
docs/NN-*.md path named outside .agents/ must resolve, every specification must
appear in all three indexes and carry the four metadata rows that make its
currency decidable, and docs/ carries no emoji.

Each of the six rules was falsified before it was committed -- the fix removed,
the check run, the failure read. The metadata rule was strengthened after the
first attempt passed a spec whose implementation-version row had been deleted:
the original accepted any of three markers, so it measured the title rather
than the table.

.agents/docs/ is deliberately out of scope for the emoji rule. Its records
carry four thousand of them and are immutable once their change lands.
…and a device language the engine does not know

Three examples, each the first in the tree to demonstrate what it demonstrates.

`09-heterogeneous/boundary` is the island boundary with nothing on top: the
consumer writes `import boundary.kernels` and the project contains no seam, no
header and no hand-written `.cppm`. Every example and every fixture in this
repository and in mcpp:plugins kept a seam over the generated module, so the
arrangement the plugins README records as measured -- a consumer importing the
generated module and linking against an implementation compiled by another
driver -- was running nowhere. Its README states the four rungs and what each
one costs; the island is an ordinary C file so the example runs with no device.

`11-features` declares features rather than consuming them. Every heterogeneous
example passes `features = [...]` on a dependency edge and none had ever
declared `[features]`, `[feature-deps]` or `[dev-dependencies]`. The criterion
is not that the default build works -- it is that the default build's
resolution does not name the optional package: `counters` appears 0 times
without the feature and 2 times with it.

`13-a-new-device-language` is a rule package that declares
`device_extensions = [".toy"]` and `rule_module`, and a project that compiles a
`.toy`. That a new device language costs no engine release is the property the
accelerator design is built on, and its only instance was `rules-slang` in
another repository.

Three defects the third example found while it was being written, each now in
its README because a rule author will meet all three: an action's command does
not run from the package root, so a rule passes absolute paths; a pipeline's
exit status is its last command's, so a summator that lost its input still
exited 0 and produced a program that printed the wrong number; and the compiler
itself must be a declared input, or editing it leaves every edge clean and the
artifact keeps the previous compiler's bytes.

Also in this commit: the 09 README's prose said "all four" over a table of six
and never mentioned that two of its sub-examples generate their boundary; the
seven examples pinned mcpp:plugins 0.3.0, which is the release before all six
rules passed a depfile; and cuda/app/build.mcpp asserted that no source in the
project names a generated file while line 51 of the same file correctly said
the host half includes it.
`[features]` was 394 lines inside a 3,129-line field reference, and no example
declared one. It is chapter 22 now, with `provides`/`requires` and
`[feature-deps]`, and `examples/11-features` is its worked example. docs/05
keeps a pointer and loses the essay; it is about 1,570 lines lighter.

Chapter 23 is new and is the one this tree did not have: authoring a rule
package. The material existed as a 115-line section inside a 944-line chapter,
plus a README in another repository, and the two keys that make a new device
language cost no engine release -- `device_extensions` and `rule_module` --
were documented nowhere in docs/. It assembles the manifest keys, the four
action roles, declared inputs (including the compiler among them), depfiles,
chained actions, the payload declaration with its two gates, the island
boundary's four rungs, the reporting channels, and how a rule finds its own
files.

docs/01 was 64 lines listing directories. It is the curriculum now: six tracks,
what each example is the FIRST to teach, and the criterion for when a new
capability earns an example rather than a code block or a scenario entry. It
also names the third teaching surface -- project templates, which is where the
bare-metal lesson actually lives and which nothing told a reader about.

The new device-language example is renumbered 12 so the sequence has no hole.
3,129 lines, of which six sections were conceptual chapters that had landed in
the manifest reference because that is where the keys are documented. Each moves
to the chapter that already owns its subject:

  cxx_runtime, the C++ runtime contract   242 -> 03
  [target.*] conditioning                 138 -> 14
  [xlings], the project environment       317 -> 17
  host tools from a dependency            274 -> 07
  [hooks]                                 192 -> 21
  features and capabilities               394 -> 22 (previous commit)

05 is 1,626 lines and is a field reference again; no chapter is above 1,218. A
pointer stays at each old section so its number keeps its place in the sequence
and an existing link still lands somewhere useful.
…cs stop being exempt by accident

269 design records, 109,146 lines, and the whole index was the heading
`# 开发/方案文档目录`. It is generated now -- by date, newest first, with each
record's own title -- and CI compares the file against the generator.

What the generator derives is mechanical: the date from the filename, the title
from the first heading. `subject` and `status` are read from front matter and
shown only when a record declares one, because a subject inferred from filename
keywords would misfile records, and a misfiled record is worse for a reader than
an unfiled one. The 268 records that predate the convention are not rewritten: a
record describes the moment its change was made, and a pass adding a field
nobody chose would edit documents whose value is that they are not edited.

`status` is what the tree lacked most. Opening the accelerator design today does
not tell a reader that a v2 and then a v3 moved past it; the filename carries
that for the two authors who thought of the convention.

The register rules now cover `docs/specs/`. The old glob was
`docs/*.md docs/zh/*.md`, which does not descend, so four specifications were
exempt from the heading and second-person rules by accident. Extending it found
one heading to reword and one term to mark as code -- `did-you-mean` contains
`you`, which is a term of art and now reads as one. The PARITY loop still
excludes them, because whether the specifications become English with a
简体中文 mirror is an open question rather than a defect a script should assert.

Eight structure rules now, each falsified before it was committed.
…are checked

Appending [hooks] to 21 had put it after that chapter's 'Current limitations',
which is the one section that has to be last. Both languages reordered.

`mcpp emit xpkg` produces a descriptor that `mcpp xpkg parse` rejects for a
package that keeps its own mcpp.toml: the emitted mcpp segment carries
`manifest = "mcpp.toml"` and no `sources` list, and the validator requires
one. Isolated by adding the list by hand, which makes it validate. Recorded as a
current limitation in 21 rather than fixed here.

Rule 9: every relative Markdown link in docs/ and examples/ resolves. Rule 3
catches a chapter path named from anywhere including source comments; this
catches a link whose target is not there. A chapter moved in this batch would
satisfy one and break the other.
…pter 17 back in order

Moving six sections out of 05 left references behind that pointed at section
numbers which had moved with them. Fourteen in the two languages: `§2.8.1`
from inside the chapter that now contains it, `§2.13` from the chapter that
now IS it, `§2.14` from the chapter it moved to, `§2.7.1` from the chapter it
left. Each is repointed at the chapter that holds the content now, or at the
section of the same chapter when the reference became local.

Chapter 17's 'Related chapters' had ended up in the middle, and its own bullet
for 05 said 'every manifest key, including [xlings]' -- the one claim the move
made false. It is last again, renumbered, and 05 is described as the rest of the
manifest.

This is what the review pass is for: a mechanical move keeps every heading
structure valid and leaves the prose pointing at the old shape.
…he gradient rule becomes one that is followed

The review found two rules written in the style skill and not applied. Chapter
22 had no 'Current limitations' section while the skill calls that section
mandatory; it now records the two that were measured -- there is no
`--no-default-features`, and a dependency cannot be conditioned on the
accelerator.

The other was the rule itself. 'Every document states which rung it is on' is
not useful to a reader and no chapter did it. What carries the gradient is the
entry index and a 'Related documents' line naming the rung above and below, and
that is what the rule says now. 22 also joins the role index row for a library
author, which is where a reader looking for features would start.
…cannot show

build_examples.sh derives its list from the tree and fails on a root in neither
BUILD nor SKIP. It failed on all four new roots, which is the check working;
each is classified now, and the rule package is skipped for the reason its
siblings are -- a rule package is not a standalone build, because its module
imports the bundled mcpp module that exists only inside a consumer's build.

Two criteria are asserted in a step of their own because a build cannot show
them. For 11-features, that the DEFAULT build's resolution does not name the
optional package -- 'the default build works' passes while the package is
resolved and merely unused. For 12-a-new-device-language, that editing the
compiler reaches the artifact: the action declares its tool as an input, and
without that the build stays green over the previous compiler's bytes.
…cture

What the measurements say afterwards, what the review pass found, what the work
found while building the examples, and what is open with the reason each is open
rather than late.

The review section is the part worth keeping: fourteen cross-references in two
languages were left pointing at section numbers that had moved with their
sections, and every heading-structure and bilingual-parity check stayed green
throughout, because neither is a check about meaning. A mechanical move keeps
every structure valid and leaves the prose pointing at the old shape.
…our that did not

check_docs_style.sh compares heading STRUCTURE, which catches a page that has
fallen a section behind. It cannot see a table row or a code block that never
made it across, and four were sitting in the tree — none introduced by this
batch, and none visible to any other check:

  docs/zh/22 (from 05)  the `[features]` section had NO BODY: the TOML example
                        that defines the syntax and all three bullets were
                        absent, in the section that defines the mechanism
  docs/zh/05 §2.11      the `identity` verdict table — ok / mismatch / missing /
                        unverified — and the two paragraphs around it
  docs/zh/08 §7.4       the shared-library format table and what follows it:
                        Mach-O's install name, and the refusal of an unservable
                        target
  docs/zh/16            SEVEN target rows. The 简体中文 support matrix listed 14
                        targets where the English listed 21, all seven missing
                        ones Cortex-M

Rule 10 compares table rows and fenced code blocks per document pair. It was
written after the first two were found by hand, and it immediately found the
other two, which is the argument for it: a bilingual pair can agree on every
heading and disagree about a support matrix.
The first description of it in this batch was wrong in the direction that
matters. It said the emitted descriptor lacks a `sources` list which the
validator requires, and that adding the list by hand makes it validate.

Measured again, this time on the STATUS rather than the output: `mcpp xpkg
parse` reports `unknown mcpp-segment key 'manifest'` and exits 1. The missing
`sources` error follows from it -- the ignored key means nothing derives
sources from the manifest it names -- and adding the list removes the second
error, prints the summary, and still exits 1. The first reading took a printed
summary for success.

mcpp-index uses that key in 0 of 218 descriptors. A package keeping its own
mcpp.toml omits the `mcpp` field entirely. So the defect is not a missing
list: `mcpp emit xpkg` writes a descriptor shape that the resolver in the same
release does not implement and that no published descriptor uses.
…ation was missing

Two things, and the second is the one that matters.

The chapters are renumbered so the number says which part a chapter is in: 0x
uses mcpp, 1x ships what was built, 2x is toolchains and targets, 3x is bare
metal and devices, 5x is the machine-facing contracts, 9x is mcpp itself. Within
a part the order is a reading order. The index read `00, 01, 05, 06, 07, 21, 22`
under Part I, which is a list a reader cannot sort. Renumbering was refused in
the previous batch on a measurement that counted 103 citing files; 73 of those
are `.agents/docs` design records, where citing the number a chapter had at the
time is correct. The live cost is 29 files and 56 occurrences, plus 287
intra-docs links, all scripted -- and the earlier refusal conflated an immutable
record with live code.

The second thing is `.agents/docs/2026-09-08-the-documentation-as-a-book.md`. A
reorganisation groups the chapters that exist; it does not decide what each one
is FOR. Measured: testing is a section in seven chapters, dependency resolution
in seven, C++ modules in seven, and the model -- what mcpp's moving parts are --
is a section in none. Five of 24 chapters state their reader and their question;
six have a limits section.

So the design specifies, per chapter, the reader, the one question it answers,
what it contains, what it must NOT contain, where it sits and why. It creates
three chapters for the three unowned topics, moves build programs beside rule
authoring because they are one subject at two scales, moves bare metal in front
of devices because that is the arc, and states the rule that keeps a topic from
being explained a second time.

That implies a second renumbering, which is the cost of having reorganised
before designing. It is stated in the design rather than hidden.
…ecord the rules in the skill

The previous commits reorganised. This designs.

MEASURED, and it is why renumbering was not enough: testing is a section in
seven chapters, dependency resolution in seven, C++ modules in seven, and the
model -- what mcpp's moving parts are -- in none. Five of 24 chapters state
their reader and their question; six have a limits section. A tree indexed by
mechanism gives a TASK no home, and no numbering gives it one.

Three chapters, each for a topic the measurement showed unowned:

  00  How mcpp Works    the five nouns every other chapter uses -- package,
                        graph, toolchain, target, index -- the three seams a
                        first build crosses, where state lives, and a table
                        from a message's shape to the noun it is about
  04  Dependencies and Resolution
  07  Testing           including a target this machine cannot execute

`00` is the one that changes how the rest reads: mcpp is a build system, a
package manager and a toolchain provisioner in one program, and a reader who
does not know that reads every chapter as an unrelated feature.

Renumbered a second time, into the bands the design specifies rather than the
ones the reorganisation guessed: build programs move beside rule authoring
because they are one subject at two scales, and bare metal moves in front of
devices because that is the arc. The design states that a second renumbering is
the cost of having reorganised before designing.

The design document caught its own defect: its chapter list dropped Workspaces
entirely, and a filename collision surfaced it.

Six rules are abstracted into `.agents/skills/mcpp-docs-style` so they outlive
this batch: one owner per topic; a chapter exists for a reader with a task, not
a mechanism with a name; reader, question and EXCLUSIONS in the first fifteen
lines; a part is a reader's arc; one recommended path in the body with every
other spelling folded into `<details>`; and an increment marked beside itself.
The skill also gains the seven-cell chapter spec that must be fillable before a
chapter is touched, and the review rubric grows to eleven dimensions.

Chapter 04 is the first section written to the recommended-path rule: the
dotted selector in the body, the namespace sub-table folded away. Rule 10
caught that the 简体中文 half had not been changed with it.
R3 of the book design, applied to all 27 chapters in both languages, and then
made a check so it does not decay back.

Five of 24 chapters had an opening that named their reader. The other 22 began
with a summary of their own subject, which tells a reader what the chapter is
about and not whether it is the chapter they want. Each now opens with three
statements in its first fifteen lines: who reads it, the one question it
answers, and what it deliberately does NOT contain.

The exclusions are the half that does the work. They name the chapter that owns
each neighbouring topic, which is what stops a chapter from re-absorbing a
subject another one owns -- the failure the measurement found seven times over
for testing and for dependency resolution.

Rule 11 checks all three. It immediately caught chapter 00, which stated its
exclusions in a closing section rather than in its opening; the closing section
was written first and reads as a summary, which is exactly the shape the rule
exists to reject.
The check for rule 11 was falsified by breaking chapter 51 and then running
`git checkout -- docs/51-supported-versions.md` -- which restored the file to
HEAD, and the opening had not been committed yet. The rule reported it
correctly and the commit went out red.

A falsification test must copy the file aside, not revert it, whenever the
change under test is uncommitted.
… that said seven

The design's §1.1 reported testing as a section in seven chapters and concluded
that seven chapters explain it. The criterion was a substring search over
heading text -- the exact shape this repository's style skill forbids, used in
the document that states the rule.

Read properly, the seven are: two about mcpp's OWN test suite (a contributor's
subject), one that owns the JSON schema, one that owns the `[dev-dependencies]`
table, two legitimate mentions inside a tutorial and a workspace section, one
heading that says "testing" over a section about path overrides, and one worked
example. Exactly ONE is a second explanation of how a test runs: 40-baremetal.

So R1 is applied where it applies. 40-baremetal now defers the model to 07 and
keeps what is specific to a board -- one image per test file, and semihosting
carrying `main`'s return value into the emulator's exit code, which is why the
model is identical to a hosted run rather than merely similar. 01 and 06 gain a
line naming 07 as the chapter that owns the topic.

The conclusion the measurement was drawn for survives: before 07 existed, no
chapter answered "how do I test". A topic can be unowned without being
duplicated, and that one was. The correction is kept in the design document
rather than quietly replaced, because the wrong criterion is more transferable
than the right count.
…ook also a reference

Three things the reader-facing side was missing, and the rules for each are in
the style skill so they outlive this batch.

02 — SCENARIOS. The tree had an index by example (03) and an index by command
(09) and none by the work in front of a developer. Nine scenarios -- a CLI tool,
a library, a workspace, a graphical application, cross-compiling, bare metal,
GPU compute, graphics, a build step -- each stating the situation, what mcpp
contributes to it, the path through the chapters, one project to run, and the
one thing that surprises people. Every scenario is backed by a runnable project
or a published template; a path with nothing to run is a claim rather than a
scenario, and the chapter says so.

A LOOKUP INDEX. The chapter list is a reading order and cannot answer "I have
`[feature-deps]` in front of me". docs/README.md gains the other index: manifest
tables and keys, commands, and concepts, each to the chapter that owns it. The
two properties -- a book that is read in order and a reference that is looked
up -- are carried by two indexes rather than by one table pretending to do both.

THE RULES. R7: an advantage is shown by the artifact, not by an adjective --
six lines of manifest, `Finished dev in 0.06s`, `counters` 0 times without the
feature and 2 with it. The criterion is that deleting every adjective leaves the
advantage visible. R8: a complex feature is introduced as shortest-runnable →
common shape → full surface → edges, one axis at a time; the criterion is how
many screens before the reader has something running. Plus the two-index rule
above. The review rubric is fourteen dimensions now.
…atch leaves open

The limits section moves to the end of chapter 30 and takes the canonical name
in both languages. It had been left mid-chapter by the split that appended a
section after it.

Seventeen reference chapters still have none, and they are recorded as open
rather than written. A fabricated limits section satisfies the check and
measures nothing, which is worse than an absent one: the reader then believes
the boundary has been stated. The criterion for closing one is in the record --
facts a reader can reproduce on the current release.

Also open and recorded: four chapters that still present every spelling at the
same weight (R5 is applied to one section so far), the manifest reference's
worked examples and appendix, and the fact that the new lookup index has no
check comparing it against the reference chapter's own sections.
…as it

The self-review found five citations, in two languages, reading
`See *One package, one version* in [04 — mcpp.toml](04-mcpp-toml.md)`. The
section moved to chapter 23 with the `[xlings]` split. Rule 3 could not see it:
the path resolves, and the chapter is simply the wrong one. The earlier §-number
sweep could not see it either, because this citation names its target by TITLE.

All five are repointed, and rule 12 checks the shape: a citation of the form
`See *X* in [NN](NN-….md)` -- and its 简体中文 form -- must land in a chapter
whose text contains X. Falsified before committing.

Two more from the same review pass: chapter 20 appeared in no scenario path,
though "which compiler builds this" is a question every reader eventually has,
and it joins scenario 1; and the limits section of chapter 30 was left
mid-chapter by the split that appended a section after it.

The duplicate-sentence scan across 27 chapters found two hits and neither is a
duplicated explanation -- one is a shared cross-reference, which is R1 working,
and the other is one sentence two chapters reached independently.
The assessment of the finished book found a fourth reader the design had missed,
and the measurement that found them is the sharpest in this batch:

  `xim:` payloads are named 84 times across 12 chapters.
  How to make one is explained nowhere.
  `xim-pkgindex` appears 17 times, all in the chapter about releasing mcpp.

Every toolchain, device toolkit, shader compiler and emulator in this ecosystem
is a payload. The documentation taught all of consuming them and none of
producing them, and the omission was hidden by how often they are mentioned. Two
more of the same shape: a `compat:` runtime adapter is named in four chapters
and authored in none, and a board-support package is described from the
consumer's side in 40 and 41 with no chapter on writing one.

Three chapters, and `3x` becomes "extending mcpp and its ecosystem":

  32  Authoring a Payload                 what an xim: descriptor must say, the
                                          two mirrors, `latest` as a reference,
                                          the exports that write a consumer's
                                          RPATH, and the `when` tier
  33  Authoring a Runtime Adapter         why a dlopen fails against a library
                                          that is plainly installed, and what a
                                          symlink farm plus runtime.library_dirs
                                          fixes
  34  Authoring a Board-Support Package   one package and two environments, the
                                          zero-libc tier, the machine table that
                                          is not a default, and run_exclusive

Every fact is read out of a published package -- glslang.lua,
compat.vulkan-runtime.lua, cortex-m-rt -- rather than out of the mechanism.

The adapter chapter records a decision that is not a packaging choice: a
proprietary driver's userspace is in ABI lockstep with a kernel module and its
licence forbids redistribution, so it is a host capability and the adapter is
how an artifact reaches it. An open driver is a payload and needs no adapter.
Which answer applies is decided by the licence and the ABI, not by preference.

Scenario 10 and a role-index row carry the new reader; the lookup index gains
`xim:` and `compat:`.
`90-build-from-source` was 116 lines and its source layout was wrong: it listed
`src/manifest/` and `src/platform/`, which moved into `modules/` in the
workspace refactor, and it named none of the nine workspace members. A
contributor reading it looked for directories that are not there.

Rewritten from the tree: nine workspace members with what each holds, the
engine's own directories, and the real test counts -- 108 unit tests and 370
end-to-end scripts.

Three sections it did not have, and a contributor needs all three:

  the capability gate      `# requires: elf gcc` decides which e2e scripts run,
                           and a script requiring a capability no job provides
                           never runs anywhere -- its greenness means nothing

  writing a check that     after writing a check, remove the fix and run it
  measures something       once. Three shapes it catches, each of which has
                           shipped here: a criterion that never runs, one that
                           cannot fail, and one applied to the wrong object.
                           And: state the denominator, because an empty
                           enumeration also finds nothing

  the checks beside the    four of the eighteen scripts in .github/tools/, each
  tests                    with what it refuses, read out of the script rather
                           than guessed
Four of the six worked examples in chapter 04 are runnable projects under
examples/, and the project is the better answer: it builds, and CI checks it.
Those four become one table of pointers; the two shapes with no example yet --
a pure C library and a mixed C/C++23 project -- stay as manifests. 04 drops from
1,377 to 1,271 lines.

Appendix A was the admission criteria for new manifest fields, which is
contributor material rather than a field reference, and it sat BEFORE section 3
-- an ordering the earlier splits left behind. It moves to 90 as *Adding a
manifest field: the admission criteria*, before the PR guidelines.

Rule 13 is added with it: every table the manifest reference documents must
appear in the lookup index of docs/README.md, compared on the key NAME rather
than its spelling, because the two documents legitimately write
`[targets.<name>]` and `[targets.<n>]`. It found one real omission --
`[package] platforms` was documented and not indexed -- and was falsified
before committing.
…stated

The method that works, and the one this batch was missing: a limit a chapter
already states somewhere in its body is PROMOTED into the section that collects
them, rather than invented. Scanning each chapter for sentences of the shape
"is not / cannot / only on / not yet" turned up real material in eight:

  05  two things need the network and only two; a namespaced selector is not
      covered by the refresh window
  20  a macOS host has no Linux-targeting payload at all; an explicit
      [toolchain] is never overruled
  21  a `planned` row is registered and nothing is wired; host_can_serve is a
      different question from the tier
  22  a dependency cannot be conditioned on the accelerator -- the layer is
      resolved FROM the graph, so it would decide the answer it is asking
  23  a tool cannot be conditioned on the accelerator, for the same reason, and
      a manifest that writes one is refused
  41  exactly one dependency may supply a runner name; a runner the environment
      does not supply stays absent
  50  the exit-code table is scoped to the commands it names; absence of JSON
      means "not supported" and a client cannot tell which reason
  51  mcpp.lock records and verifies a resolution and does not constrain one

Eight remain -- 04, 07, 10, 11, 24, 90, 91, 92 -- and scanning them returns
nothing usable. That is recorded rather than filled, for the reason the design
already gives: a fabricated limits section satisfies the check and measures
nothing.
`0x — Everyone` / `0x —— 人人都需要` describes an audience in a sentence
fragment. The style skill requires a noun phrase, and the band names are the
skeleton of the table of contents -- the place the rule matters most. It is
`0x — Fundamentals` / `0x —— 基础` now.

The paragraph that explained the bands went stale in the same place: it still
said `3x` extends the build graph, which stopped being true when the band took
in payloads, adapters and board-support packages. It is a table now, which is
also what the skill says to use for an enumeration.

The rule is extended in the skill to say it governs part and band names, not
only chapter headings, with this rename as the worked example: the audience
belongs on each chapter's "Reader" line, not in the skeleton of the contents.
The review's verdict on the previous 00 was that it scored zero, and it was
right. `How mcpp Works` was accurate and was the wrong chapter: a general user
does not care about the operating principle. It failed two of the design's own
rules -- R2, because "understand the machinery" is a maintainer's task and
already has chapters in 9x; and R7, because a model chapter explains how an
advantage is produced and never demonstrates it.

`00 — What mcpp Is` replaces it with what a first reader actually wants:

  the definition   mcpp = build system + build plugins + package manager +
                   toolchain management + the environment and runtime (xlings)

  an analogy       CMake, xmake rules, Conan, GCC/LLVM/MSVC, Nix/conda -- so a
                   reader with existing tools can place each part, with the
                   disclaimer that places rather than equates

  the guarantee    clone any mcpp project and `mcpp build` works, without
                   installing a compiler, configuring an environment or hunting
                   dependencies -- and the two boundaries that make it credible

  a real session   a five-line manifest with no compiler and no standard
                   declared, `import std` compiling on a machine whose own g++
                   is 13.3.0 and cannot, `mcpp self env` showing the GCC 16 mcpp
                   installed, 1.25s wall clock including the first run

  what it is for   modules and the newest features, and the ecosystems that
                   follow: embedded, heterogeneous and GPU, graphics, kernel

The one part of the old chapter a user wanted -- the table from a message's
shape to the stage that produced it -- moves to 09 beside the other diagnosis
scenarios. The rest is deleted.

The style skill gains the distinction this needed: an ANALOGY places a part
against a tool the reader knows and is admissible in user documentation; a
COMPARISON claims mcpp is better on some axis and belongs to a design record.
An analogy carries a disclaimer, or the placement is read as equivalence.
The per-part table places each of mcpp's five parts against a tool a reader may
already use. What it did not say is that two tools are close analogues of the
WHOLE shape, and for different halves of the same idea:

  Cargo  one program that is the build, the packages, the lock file and the
         test runner -- so a project is cloned and built with no preliminary
         step. That is chapter 00's guarantee, in another language.

  Zig    the toolchain ships with the tool and cross-compiles by default -- so
         the compiler is not something the machine must already have. That is
         the toolchain row.

`build.zig` joins xmake rules on the build-plugins row, since both are the same
idea: the build is a program the project writes.

The part neither analogue has is the environment layer, which is why an mcpp
project can also declare the non-compiler tools its build needs. Stating that is
what keeps the analogy from being read as equivalence -- alongside the
disclaimer the skill now requires of every analogy.
@Sunrisepeak
Sunrisepeak force-pushed the docs/architecture-three-trees branch from 50f50cf to c248ad0 Compare September 8, 2026 10:42
…ends one way

Two corrections from review, and both are about what a reader meets first.

CHAPTER 00 IS RESTRUCTURED. It opened with a metadata block -- reader, question,
exclusions -- which is a reference-chapter device and reads as machinery on the
front door. And it stated what mcpp is before saying what problem that answers.

It now runs background -> who pays -> what mcpp is -> the guarantee -> the
smallest example that shows it:

  C++20 gave the language modules, and adopting them turned out to be a
  build-system problem: scan for `import`, order the compiles, cache and
  invalidate the interfaces, with a compiler new enough to have the feature --
  and `import std` needs the standard library's own module built first. The gap
  is concrete: this machine's g++ is 13.3.0 and cannot compile it.

  A person pays an afternoon per machine. An agent pays context, in three places
  before it writes a line: reading the build system, reconstructing the
  environment it assumes, and following a header through its transitive includes
  to find what is declared. Modules remove the third; mcpp removes the other two.

Rule 11 exempts `00` by name, with that reason in the script: it has no "not
here" to declare because everything else IS elsewhere, which its closing
paragraph says in a sentence.

THE INSTALL SECTION FOLLOWS R5. `xlings install mcpp -y` is the recommended way
and is the only one in the body. The standalone curl script and the per-host
default-toolchain table fold into a `<details>` -- they were offered at equal
weight, which asks a first-time reader to choose between two installs before
they have any basis to.
…proxy

The record said four chapters offer several spellings at equal weight, on the
evidence that they carry many code blocks and no <details>. That counted a proxy
instead of the property. A section with five code blocks is usually five
features documented in sequence -- chapter 20's are glob exclusion, per-glob
flags and generated files -- or one continuous session, which is what chapter
00's six blocks are. Folding any of those away would break what they belong to.

Measured on the property -- a section that offers ALTERNATIVES at equal weight,
found by the markers that introduce one -- the whole tree returns three hits,
and none is a choice presented to a reader: two are prose about what is
accepted, one is a comment in a command line. R5's real debt after 05 and 01 is
close to zero, and what remains is to apply the rule as new alternatives appear.

This is the third criterion in this batch that counted something adjacent to the
property: headings containing "test" for chapters that explain testing,
substring spellings for the lookup index, code blocks for offered alternatives.
The skill says a criterion must not be a substring search; the variant now named
beside it is COUNTING A PROXY, which survives review precisely because the
number is real.
The previous commit corrected the record and the rule it drew did not reach the
skill, because the anchor had shifted. It is there now, as item 7 beside "a
criterion must not be a substring search":

  counting code blocks to decide whether alternatives are offered at equal
  weight; counting headings that contain a word to decide which chapter owns a
  topic. The number is real and the thing counted is not the property -- and
  because the number is real, review does not catch it.

With the three instances from this batch recorded beside it, so the shape is
recognisable rather than abstract.
Chapter 00's section headings `背景:模块到了,工具链没跟上` and
`谁在为这个落差付账`, and the analogy table's column header
`大致相当于谁的活`, are all colloquial, all violate the register rule, and all
passed check_docs_style.sh. Two independent defects in one check.

THE PREDICATE TESTED A MARKER RATHER THAN THE PROPERTY. It matched `?`, 吗 and
呢 -- the punctuation a question usually carries. The property is the
interrogative word, and neither heading carries the marker.

THE OBJECT SET WAS ENUMERATED SYNTACTICALLY. It read lines beginning with `#`.
The property a heading has -- it names a topic, it is read out of order, it is
what a reader scans -- is held equally by a table's header cells, which were
therefore never examined.

- Chapter 00 rewritten. The scope of a background section is decided by the
  problem, not by the tool: a C++ project needs four things at once and no
  single tool owns all four; CMake is the de facto standard for one of them,
  and a de facto standard is a statement about adoption rather than about the
  experience of use; the environment is the layer that fails most often because
  it is the only one nothing checks. Modules are the fourth constraint on that
  structure rather than the structure.
- 100 headings and 57 column headers become noun phrases, in both languages.
- check_docs_style.sh: the predicate is now the interrogative word set, and a
  fourth rule covers column headers. Chapter 00's title is exempt by name, with
  the reason stated.
- check_docs_structure.sh rule 9 discarded the link fragment, so a link to a
  renamed section resolved to the file and passed. It now computes GitHub's
  slug and verifies the fragment. It immediately reported two anchors in
  chapter 30 that were wrong when they were written.
- The skill records R5 (the scope of a background section), the predicate rule
  and the column-header rule, each with this batch's own sentences as the
  worked example.

Each of the four new checks was falsified before commit: an interrogative
heading with no question mark, a Chinese column header, an English column
header, and an interrogative inside inline code that must not fire.
…nsion model

`.toy` was "one integer per line, and the entry point returns their sum",
compiled by a shell script. That is not a language, and not a shape any
ecosystem author meets.

THE LANGUAGE. `.toy` now has `let`, assignment, `if`/`else`, `while`, calls
between kernels, and the arithmetic and comparison operators. The grammar is
stated in the README and at the top of `compile.cppm`. The sample source is
Euclid's algorithm and a caller.

THE COMPILER. `toyc/` is an ordinary mcpp package: a lexer, a recursive-descent
parser, semantic checks and a C++ emitter, in three modules and a driver. It is
built FOR THE BUILD MACHINE through `tools = ["toyc"]` + `reexport = true`, and
the rule reaches it with `mcpp::dep_bin`. This is the repository's first
example of a dependency producing a host tool, a capability that until now
existed only in prose.

Four criteria measured: the `.toy` compiles and joins the link
(`answer() = 42`); the language is executed rather than pattern-matched
(`gcd(1071, 462) = 21`, computed by the emitted loop); editing the `.toy`
reaches the artifact (42 to 63); and with the feature removed the build stops
at the module import with no `toyc` in the tool store.

AND ONE BOUNDARY MEASURED. Editing the compiler's SOURCE does not reach the
artifact. The tool store's key is the package identity, version, host triple,
compiler identity, profile, features and the versions of its transitive
dependencies -- it holds no source content. That is exact for a tool from an
index, because a published version is immutable, and not exact for a `path`
dependency being edited: `mcpp run` reported `Finished dev in 0.00s` and
printed the previous answer. Chapter 30 now states it with the two ways out.

CHAPTER 31 GAINS "THE EXTENSION MODEL", which answers what mcpp's plugin system
is and where it is already used: the five extension points with their effect
and where each is declared; seven things the ecosystem has built from them; the
three shapes the model expresses (a new language whatever compiles it,
preprocessing and code generation, and a file that is partly C++ and partly
another language); and the boundary, measured rather than asserted -- a
declaration cannot reclassify an extension the engine owns (adding `.cpp` to a
rule's `device_extensions` is not diagnosed and has no effect), module-interface
extensions are the project's axis, and an extension in neither table is refused
by name, quoted from the run.

build_examples.sh lists `toyc` in BUILD and states why it and the app are two
signals rather than one. 12 of 12.
Section 14: the register rules were written and then not enforced. The check
had two independent defects, each a form recorded elsewhere -- the predicate
tested a marker (`?`) rather than the property (an interrogative word), and the
object set was enumerated syntactically (lines beginning with `#`) while a
column header is a heading by every property that matters. Extending both
reported 100 headings and 57 column headers. It also surfaced that the
structure check discarded a link's fragment, so a link to a renamed section
resolved to the file and passed. R5 is recorded with it: the scope of a
background section is decided by the problem, not by the tool.

Section 15: the extension model had no owner. Chapters 30 and 31 held every
primitive between them and no section stated the model itself. Chapter 31 now
opens with it, and its boundary is measured rather than asserted. The example
had to become real before it could carry it -- the language, the compiler, and
the tool-store boundary it measured.
… isolate it

The device-language step still asserted the previous example: it grepped for
`toy_answer() = 42` and edited `rules-toy/tools/toyc.sh`, a shell script that no
longer exists. The job failed with "the .toy did not reach the link".

Rewriting it turned up a claim I had written from reading the rule rather than
from measuring it, and the measurement contradicts it.

WHAT THE FIRST REWRITE ASSERTED. Bump the tool package's version, and the
artifact follows. That is true, and it does not test what its message said.
Falsified by removing `a.input(compiler)` from the rule: the version bump still
reached the artifact and the step still passed. The tool's path is on the
action's command line, so a new path re-runs the edge whether or not the
compiler is also a declared input.

WHAT ISOLATES IT. Different bytes at the same path: build a compiler that
behaves differently and overwrite the cached binary in place, leaving the
command line byte-identical. And both directions, because neither alone is the
property -- with the input removed, the artifact followed the overwrite and then
stopped following the restore. With the input present the step exits 0; with it
removed, 1.

The step now covers four things: the `.toy` reaches the link; the emitted loop
runs (`gcd(1071, 462) = 21`, a value no constant in the tree holds); the
compiler's bytes are tracked by the action; and the tool store holds no source
content, with a version bump as the way out. Probe runs exit non-zero on
purpose -- the program returns 1 when the answer is not 42 -- so they are judged
by their output rather than their status.

The README and chapter 30 said the action re-runs when the compiler binary
changes. That is now measured rather than reasoned, and both state which case
does not isolate it.
@Sunrisepeak
Sunrisepeak force-pushed the docs/architecture-three-trees branch from 85e6a9d to 11470f2 Compare September 8, 2026 12:01
@speak-agent
speak-agent merged commit 9a71c9a into main Sep 8, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant