docs: three trees, three audiences, and the rule for citing between them - #590
Merged
Conversation
… 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
force-pushed
the
docs/architecture-three-trees
branch
from
September 8, 2026 10:42
50f50cf to
c248ad0
Compare
…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
force-pushed
the
docs/architecture-three-trees
branch
from
September 8, 2026 12:01
85e6a9d to
11470f2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 styleskill it follows is
.agents/skills/mcpp-docs-style/SKILL.md.What this started from
Measured against
origin/mainat6e1c65c6:docs/chaptersdocs/specs/.agents/docs/Seven defects, each independently verifiable:
docs/specs/README.md— two levels down, in the tree with the narrowestaudience.
docs/README.mddid not mention it.check_docs_style.shiterateddocs/*.md docs/zh/*.md, which does notdescend, so the specifications were exempt by accident. Defect 2 is its
visible consequence.
docs/README.mdlisted two of four specifications..agents/docs/….numbering.
none of the sixteen classifier words in use.
What changed
The architecture is published.
docs/README.mdanddocs/zh/README.mdstate 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,08and09stop reading as steps four, eight and nine of a user's path.No chapter is renumbered:
docs/NN-is cited from 103 files includingsource and CI.
User documentation is a usage manual again. Every
.agents/pointer isremoved;
docs/20's "Not implemented" becomes "Current limitations", a list offacts rather than the argument for each gap, and gains the two device extensions
no published rule package claims.
05stops 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 oldsection 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_extensionsandrule_modulewere documented nowhere indocs/.01is the curriculum: six tracks, what each example is the first toteach, 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 witheach record's own title, plus
subject/statusfront matter required on newrecords. 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:
09-heterogeneous/boundary.cppm12 24 36 48;grep -rn '#include' src/empty11-featurescounters0 times without the feature, 2 with it12-a-new-device-language.toycompiles and joins the link on an engine that does not know the extension; editing the source and editing the compiler both reach the artifact42;42 → 43;42 → 142boundary/also runs an arrangement thatmcpp:pluginsrecords as measured andthat nothing in either repository was exercising.
Checks
check_docs_structure.shis new, nine rules, each falsified before it wascommitted — 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: thelanguage 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:
§2.xcross-references, in both languages, left pointing at sectionnumbers that had moved with the sections. A mechanical move keeps every
heading structure valid and leaves the prose pointing at the old shape.
05 claimed "every manifest key, including
[xlings]" — the one claim the movemade false.
"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
English primary with a 简体中文 mirror and lists it as an open question; doing
it before that is decided is the wrong order.
is a promotion of existing text and its own review.
mcpp emit xpkg/mcpp xpkg parsedisagree: the emitted descriptor fora package that keeps its own
mcpp.tomlcarries nosourceslist and thevalidator requires one. Isolated, reproducible, and recorded as a current
limitation in
docs/21rather than fixed here.Source changes are comment-only (nine files, repointed chapter citations).