| subject | docs |
|---|---|
| status | active |
The previous record in this series
(2026-09-08-documentation-architecture-three-trees.md) settled which tree a
document belongs to and published that architecture. It did not design the book
inside docs/. It grouped the chapters that existed, renumbered them into bands,
and moved six sections out of an over-large reference. That is a
reorganisation. This document is the design: for every chapter, who reads
it, the one question it answers, what it contains, what it must not contain,
where it sits, why there, and how it is judged.
Written because a reorganisation cannot fix what the measurements below show. A tree indexed by mechanism gives a task no home, and no amount of renumbering gives it one.
A topic is owned by the chapter that carries it as a ## section.
The first measurement counted headings whose text contained the topic's name, and that criterion was wrong in exactly the way this repository's own style skill forbids — a substring search standing in for a question about meaning. It reported testing as a section in seven chapters. Reading those seven:
| chapter | what its "test" section is actually about | verdict |
|---|---|---|
90-build-from-source ×2 |
mcpp's own test suite, for a contributor | a different subject |
50-machine-output |
the --message-format json schema |
it owns that |
04-dependencies |
the [dev-dependencies] table |
it owns that |
01-getting-started |
one step of a tutorial | legitimate; should link |
06-workspace |
the workspace fan-out | legitimate; should link |
11-publishing-a-library |
path overrides, under a heading that says "testing" | a naming defect |
03-mcpp-toml |
a worked example that happens to have tests | worked examples leave 03 |
40-baremetal |
how a test runs, restated | the one real duplicate |
So the corrected reading: one duplicated explanation, one misnamed heading, and a worked example that a separate decision moves anyway.
The conclusion survives the correction, and it is the part that mattered.
Before 07 existed, no chapter answered "how do I test" — the seven partial
mentions each assumed a reader who already knew, and none of them was the place
to learn it. A topic can be unowned without being duplicated, and this one was.
The same caution applies to the other rows of the first measurement, which are kept here as what they are — a count of headings, not of explanations: dependency resolution 7, C++ modules 7, diagnosis 4, caching 4, and the model 0. The last is the one that needs no re-reading: a section that does not exist cannot be miscounted.
00-getting-started goes from Installation to Creating a Project with no
section in between. mcpp is a build system, a package manager and a toolchain
provisioner in one program; a reader who does not know that reads every
subsequent chapter as an unrelated feature. The five nouns the whole tree uses
— package, graph, toolchain, target, index — are defined nowhere.
| property | chapters that have it |
|---|---|
| an opening that names its reader and its question | 5 of 24 |
| a "Current limitations" section | 6 of 24 |
| length within 2× of the median (≈420 lines) | 18 of 24 |
02-mcpp-toml is 1,626 lines and 05-build-mcpp is 1,218; 51-supported-versions
is 90. Nothing decided any of those.
Grouping and renumbering fix the index. They do not fix the book. A chapter that was written because a mechanism existed keeps being about the mechanism, and a reader with a task keeps not finding it.
Three rules produce every decision in §4 and §5.
R1 — One owner per topic. Exactly one chapter owns a topic. Every other chapter that touches it states one sentence and links. A second explanation is a second thing to keep current, and the two diverge on their own schedule.
R2 — A chapter exists for a reader with a task, not for a mechanism with a name. "Features" is a mechanism; "make part of a package optional" is a task. Where the two coincide the chapter keeps the mechanism's name, because that is what the reader searches for — but the contents are decided by the task.
R3 — Every chapter states its reader, its question, and its exclusions in its first fifteen lines. The exclusions are the load-bearing half: they are what stops the chapter from re-absorbing the topics R1 assigned elsewhere.
A fourth rule governs the sequence rather than a chapter:
R4 — A part is a reader's arc, and its order is the order that reader needs it in. Not alphabetical, not chronological by when the feature shipped.
Two more govern how a section is written, and both are about not handing the reader a decision that the design already made:
R5 — One recommended path in the body; every other spelling in a
<details>. mcpp supports more than one way to say many things, and it has a
style and a semantics of its own, so there is always a default. The body carries
that one. Legacy spellings, escape hatches and platform-specific forms fold
away. The criterion: a reader who reads only the body and opens nothing can do
the thing correctly without choosing. Folding a form away is not deprecation;
deprecation is said in words.
R6 — An increment is marked beside itself. A key, flag or behaviour added
later carries its version floor on its own line (2026.9.6.5+), not at the top
of the chapter and never as "it used to be X".
All six are recorded in .agents/skills/mcpp-docs-style so they outlive this
batch.
Everything in docs/ is about five nouns and the seams between them. This is
the content of the new chapter §4.1 specifies, and it is written here first
because the chapter list is derived from it.
| noun | what it is | the chapter that owns it |
|---|---|---|
| package | a directory with an mcpp.toml; identity is (namespace, name) |
02 |
| graph | what a build is: sources compile, objects link, actions extend | 05 |
| toolchain | a payload mcpp installs and pins, not a program found on the machine | 20 |
| target | the machine the artifact runs on, which is not the host | 21 |
| index | where packages come from, and what a descriptor promises | 11 |
The seams, each of which is a chapter rather than a section, because each is a place two nouns meet and a reader arrives with a question about the meeting:
| seam | question a reader arrives with |
|---|---|
| features | how do I make part of a package optional |
| workspaces | how do several packages become one build |
| the target side | how does a manifest say "only on this target" |
| rules | how do I teach the graph something it has no rule for |
| devices | how do I run an artifact on a machine that is not this one |
| accelerators | how does part of my program get compiled for a device |
Why the model is a chapter and not a paragraph in 00. 00 is a tutorial:
a reader following it is typing, not building a mental model, and a model
inserted there is read as preamble to skip. The model chapter is short, it is
the first thing the index points at, and every other chapter may assume it.
Three, each answering a question §1.1 measured as unowned.
| reader | anyone, before anything else. Assumed by every other chapter |
| question | what are the moving parts, and which one is failing when something fails |
| contains | the five nouns of §3 with one paragraph each; the three seams a first build crosses (manifest → graph → toolchain); where each noun's state lives on disk (target/, the store, the index cache); the one diagram |
| excludes | any field name, any flag, any command beyond mcpp build. It is a model, not a reference |
| why first | §1.2. Without it every later chapter is an unrelated feature |
| criterion | a reader who has read only this chapter can say which noun a given error message is about |
| reader | someone whose build now has more than their own code in it |
| question | where does a dependency come from, what does a version constraint mean, and what happens when two of them disagree |
| contains | [dependencies] in all its forms (index, path, git); what a bare version pins and what >= requires; one package one version, and the refusal when it cannot hold; mcpp.lock and --locked; mcpp add / update / why; [dev-dependencies] and [build-dependencies] and the difference in what each reaches |
| excludes | the identity rules (SPEC-001 owns them) and how to publish (11 owns that) |
| why here | it is the second thing every reader does, and today it is seven partial answers |
| criterion | a reader can predict which version resolves for a stated graph, and say why |
| reader | anyone with code that has to keep working |
| question | how do I run tests, what does mcpp consider a test, and how do I test what does not run on this machine |
| contains | tests/**/*.cpp as the convention; mcpp test and its selectors; [dev-dependencies]; the worker pool and run_exclusive; testing a cross or bare-metal target through a runner; --message-format json for a CI consumer, by reference |
| excludes | the runner mechanism (31 owns it) and the JSON schema (50 owns it) |
| why here | §1.1: seven chapters mention it, none owns it |
| criterion | a reader can run a test on a target their machine cannot execute |
Bands are meaningful: the first digit is the part. Within a part the order is the order that part's reader needs, which is R4.
The arc: understand the parts, get one program running, know where the examples are, write the manifest, add dependencies, make things optional, test.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 00 | How mcpp Works | anyone | what are the moving parts | fields, flags |
| 01 | Getting Started | a newcomer, typing | how do I get a program running | anything not on the path to a running program |
| 02 | Examples | a reader choosing a starting point | which example teaches what I need | the content of the examples |
| 03 | The mcpp.toml Manifest | an author | what may a manifest say | conditioning (22), features (05), the environment (23) |
| 04 | Dependencies and Resolution | an author with dependencies | where does a dependency come from, and which version wins | identity (SPEC-001), publishing (11) |
| 05 | Features and Capabilities | an author with something optional | how do I make part of a package optional | accelerator selection (32) |
| 06 | Testing | anyone | how do I run tests, including where they cannot run here | runners (31), the JSON schema (50) |
| 07 | Commands by Scenario | anyone, later | which command does the thing I want | everything each command means in depth |
Why 07 is last and not first. It is a lookup, used after the reader knows
the nouns. A reader who opens it first gets a list of verbs with no model.
Why the manifest (03) precedes dependencies (04) and features (05). Both are manifest tables; a reader who has not seen a manifest cannot place them.
The arc: package an application, publish a library's source, publish its binaries.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 10 | Packaging an Application for Release | someone shipping a program | how do I produce something another machine can run | libraries (12) |
| 11 | Publishing a Library to mcpp-index | a library author | how does my package become one others can name | the descriptor grammar (SPEC-001) |
| 12 | Distributing a Prebuilt Library | a publisher of binaries | how do I ship compiled artifacts and state what they are compatible with | the compatibility tag's grammar (SPEC-005, planned) |
Why publishing precedes targets. A library author publishes before they
cross-compile; an application author packages before they port. The reader who
needs 2x knows they need it.
The arc: what a toolchain is and how it is chosen, how a target is named, how a manifest conditions on one, what environment the project declares, and one worked cross-compilation.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 20 | Toolchain Management | anyone whose compiler matters | which compiler will build this, and how do I choose another | internals (91) |
| 21 | The Target Triple | someone building for another machine | how is a target named, and which are supported | conditioning (22) |
| 22 | The Target Side | an author supporting several targets | how does a manifest say "only there" | the accelerator axis (32) |
| 23 | The Project Environment | an author whose build needs tools | how does a project declare the tools its build runs | build programs (30-band) |
| 24 | Cross-Compilation Over openkal | someone cross-building a hosted target | how do I build for another OS from this one | bare metal (30) |
This part is new as a grouping, and it is where the design departs most from what shipped. Build programs and rule packages are the same subject at two scales: a project that needs the graph to do something it has no rule for, and a package that supplies that rule to others.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 30 | Build Programs: build.mcpp |
an author whose build needs a step mcpp has no rule for | how do I add work to the graph | authoring a reusable rule (31) |
| 31 | Authoring a Rule Package | an ecosystem author | how do I package that step so other projects can use it | the shipped rules' spellings (mcpp:plugins) |
Why they are two chapters and not one. Different readers with different questions. The first has a project and a problem; the second has an audience. The 1,218 lines of the current build-program chapter contain both, and its "Writing a rule package" section is now a second copy of chapter 31.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 40 | Bare-Metal and Freestanding Targets | an embedded developer | how do I build for a machine with no OS | reaching it (41) |
| 41 | Reaching a Device | anyone whose artifact does not run here | how do I run and test it where it belongs | the target's construction (40) |
| 42 | Heterogeneous Builds | a GPU or accelerator developer | how does part of my program get compiled for a device | rule authoring (31) |
Why bare metal moved out of 3x. It is not a toolchain topic; it is a
target with no operating system, and everything a reader needs after that is
about reaching it and running on it — which is 41. The three chapters are one
arc.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 50 | Machine-Readable Output | a tool or CI author | what may a program parse, and what is versioned | human-facing output |
| 51 | Supported Versions and Compatibility | anyone with a policy question | what may change between releases, and what may not | the exit-code table (SPEC-003) |
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 90 | Building from Source and Contributing | a contributor | how do I build and change mcpp | how a user builds their project |
| 91 | Toolchain Internals | a contributor, or a user debugging a toolchain | how does mcpp actually resolve and assemble a toolchain | how to choose one (20) |
| 92 | Releasing mcpp | a maintainer | how is a release cut and verified | publishing a package (11) |
| decision | effect |
|---|---|
| three new chapters (00 model, 04 dependencies, 06 testing) | the three topics §1.1 measured as unowned get an owner |
build programs move 0x → 3x, beside rule authoring |
the two scales of one subject become one part |
bare metal moves 3x → 4x, before devices |
the embedded arc reads in order |
| every chapter gains a designed opening (reader, question, exclusions) | 5 of 24 have one today |
| every reference chapter gains a limits section | 6 of 24 have one today |
| the manifest reference sheds its worked examples and its appendix | examples/ owns worked examples; the schema-ownership appendix is contributor material |
mcpp test mentions in six chapters become one sentence and a link |
R1 |
The renumbering this implies is the second in one batch, and that is the cost of having reorganised before designing. It is paid once here; §7 states the order that keeps every citation resolving while it happens.
- Write
00,04and06against their specs in §4. New content, no moves. - Apply R1: for each of the three topics, cut the six other explanations to a sentence and a link.
- Renumber into §5's bands, in one scripted pass with the link and label rewrite the previous batch established.
- Give every chapter its designed opening (R3) and, where it is a reference, a limits section.
- Split the manifest reference: worked examples out, appendix to
9xor SPEC-004. - Re-run the review in
.agents/skills/mcpp-docs-style§13 against the eight dimensions, with §5's table as the criterion for "面向人群" and "梯度".
Steps 1 and 2 are the ones that make the book different. Step 3 is mechanical and has a tested script. A batch that stops after step 3 has renumbered twice and designed nothing, which is the failure this document exists to name.
- It does not claim the current chapters are badly written. Most are accurate and several are excellent. The defect is that nothing decided what each one is for, so topics landed wherever a mechanism needed them.
- It does not merge chapters to reduce their number. 24 chapters for a tool that is three tools is not too many. Two of them are too long, and one grouping was wrong; that is the whole of the structural change.
- It does not settle the specifications' language. That question stands where the previous record left it.
The style skill calls the section mandatory for a reference chapter. Two chapters had the content under another heading and are renamed; the scenario, model, tutorial and index chapters are exempt, because their scope is stated by the "Not here" line in their opening and they claim no complete surface.
Eight of the original seventeen were written from facts the chapter already
stated somewhere in its body — 05, 20, 21, 22, 23, 41, 50, 51.
That is the method that works: promote a limit the chapter already states into
the section that collects them, rather than inventing one.
Eight remain: 04, 07, 10, 11, 24, 90, 91, 92. Scanning their
text for a limit statement returns nothing usable, which is the honest reading —
each needs a fact its area's owner can state.
They are open rather than written, and the reason is the rule itself. A fabricated limits section satisfies the check and measures nothing, which is worse than the section being absent — the reader then believes the boundary has been stated. Writing one requires a fact its area's owner can state and that a reader can reproduce.
Criterion for closing one: the section lists facts, each of which can be reproduced on the current release, and each of which a reader could otherwise only discover by hitting it.
The first reading said four chapters present several spellings as equals, on the
evidence that 04, 20, 30 and 40 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 — 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 the thing they belong to.
Measured on the property instead — a section that offers alternatives at equal weight, marked by "alternatively", "either form", "也可以", "等价写法" — the whole tree returns three hits, and none of the three is a choice presented to a reader: two are prose about what is accepted, one is a comment in a command line.
So R5's real debt after 05 (the dependency spellings) and 01 (the two
installs) is close to zero. What remains is to apply the rule as new
alternatives appear, not to convert a backlog.
Criterion, restated so it is not measured by proxy again: a reader who reads only the body and opens nothing can do the thing correctly without choosing between two ways of doing it.
Third time in this batch that a criterion counted something adjacent to the property: headings containing "test" for chapters that explain testing, substring spellings for a lookup index, code blocks for offered alternatives. The skill already says a criterion must not be a substring search; the variant worth naming is counting a proxy, which passes review because the number is real.
04 §3 is six worked examples, which examples/ owns, and Appendix A is the
admission criteria for new manifest fields, which is contributor material and
belongs to 9x or to SPEC-004. Both were named in §6 and neither is moved yet.
§10's index is hand-built and correct today. Nothing compares it against the
reference chapter's own section list, so a key added to 04 and not indexed is
invisible. The check is the same shape as rule 4 (every specification appears in
every index) and is one loop.
§5 designed the book for three readers — someone using mcpp, someone extending one project's build, and someone changing mcpp. It missed a fourth, and the measurement that found it is the sharpest in this record:
xim:payloads are named 84 times across 12 chapters. How to make one is explained nowhere.xim-pkgindexappears 17 times, all of them in the chapter about releasing mcpp itself.
Every toolchain, every device toolkit, every shader compiler and every emulator in this ecosystem is a payload. The documentation taught the whole 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 — the layer that makes a
host library reachable from an artifact on Linux — 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.
3x was "extending the build graph" and is now extending mcpp and its
ecosystem: the two scales of one project's own step, then the three kinds of
package that serve everyone else.
| # | chapter | reader | the one question | excludes |
|---|---|---|---|---|
| 32 | Authoring a Payload | someone packaging a tool or a prebuilt library | what is an xim: payload made of, and what must its descriptor say |
source packages (11), host libraries (33) |
| 33 | Authoring a Runtime Adapter | someone making a host-supplied library reachable | why an artifact cannot see a library that is installed, and what fixes it | anything redistributable, which is a payload (32) |
| 34 | Authoring a Board-Support Package | someone bringing up a board | what does a BSP supply, and how does one package serve an emulator and hardware | using a BSP (40), the runner a consumer sees (41) |
Each is written from a real published package rather than from the mechanism:
xim-pkgindex/pkgs/g/glslang.lua, mcpp-index/pkgs/c/compat.vulkan-runtime.lua,
and mcpplibs/cortex-m-rt. Every fact in them was read out of those files.
A proprietary driver's userspace is in ABI lockstep with a kernel module and its licence forbids redistribution. Neither is solved by effort, so it is modelled as a host capability and the adapter is how an artifact reaches it. An open driver takes the other answer — it is a payload, and a machine using one needs no adapter. Which answer applies is decided by the licence and the ABI, not by preference, and that is the sentence a reader of scenario 10 leaves with.
§5 said 24 chapters for a tool that is three tools is not too many. The count is 31 now, and the reason is that the tool is four things rather than three: a build system, a package manager, a toolchain provisioner, and an ecosystem other people publish into. The fourth had no chapters at all.
§4.1 specified 00 — How mcpp Works: five nouns, three seams, where state lives
on disk. It was written, it was accurate, and it was the wrong chapter.
The review's verdict was that a general user does not care about the operating principle. What a reader opening the first chapter wants is what mcpp is, what it can do, what its advantage is, and one example they can actually run.
The design failed two of its own rules to get there:
- R2 — a chapter exists for a reader with a task. "Understand the machinery"
is not a task a first-time reader has; it is a task a maintainer has, and it
already has chapters in
9x. - R7 — an advantage is shown by the artifact, not by the mechanism. A model chapter explains how the advantage is produced and never demonstrates it.
00 — What mcpp Is replaces it, and its shape came from the review too:
background → who pays → what mcpp is → the guarantee → the smallest example
that shows it. A first chapter earns the definition by first stating the
problem, and only then shows it solved.
- The definition, in the form the reviewer gave: mcpp = build system + build plugins + package manager + toolchain management + the environment and runtime (xlings), in one program.
- An analogy table — CMake/Meson,
build.zigand xmake rules, Conan/vcpkg, Zig's bundled toolchain and rustup, Nix/conda — so a reader with existing tools can place each part, with the disclaimer that places rather than equates. Named beside it: Cargo and Zig are the closest single-tool analogues, and for different halves of the same idea — Cargo for one program being build, packages, lock and tests, Zig for the toolchain shipping with the tool. The part neither has is the environment layer, which is why a project can declare the non-compiler tools its build needs. - The guarantee, stated once: clone any mcpp project and
mcpp buildworks, without installing a compiler, configuring an environment, or hunting dependencies. Plus the two boundaries that make it trustworthy. - A session that was run, with its real output: a five-line manifest, no
declared compiler or standard,
import stdcompiling on a machine whose owng++is 13.3.0 and cannot, andmcpp self envshowing the GCC 16 mcpp installed. 1.25 s of wall clock including the first run. - What mcpp is for: modules and the newest language features, and the ecosystems that follow — embedded, heterogeneous and GPU, graphics, kernel work.
The one part of the old chapter a user wanted — the table from a message's
shape to the stage that produced it — moved to 09, beside the other
diagnosis scenarios. The rest is deleted rather than relocated.
What this says about the method. The seven-cell spec was filled for the old chapter and it still produced the wrong chapter, because the cell that decides everything — the reader — was answered with "anyone" and then served as if that meant "someone who wants the model". A reader cell that names no task is not filled in.
And the opening block came off. Every other chapter opens with reader,
question and exclusions; on the front door that block reads as machinery. 00
has no "not here" to declare because everything else is elsewhere, which its
closing paragraph says in a sentence instead. Rule 11 exempts 00 by name, with
that reason in the script.
The user read chapter 00 and named three things: 背景:模块到了,工具链没跟上,
谁在为这个落差付账, and the table header 大致相当于谁的活. All three are
colloquial, all three violate §四 of the skill, and all three passed
check_docs_style.sh.
Two independent defects in one check, and each is a form recorded elsewhere:
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 谁在为这个落差付账 nor 打什么由谁决定
carries the marker. The predicate is now the word set 谁 / 哪 / 什么 / 多少 /
为何 / 如何 / 怎样 / 怎么.
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. Rule 4 adds them: the row above a |---|---|
separator, cell by cell.
Extending both reported 100 headings and 57 header cells across 20 chapters, in both languages. They are now noun phrases. The rename table is in the commit rather than here, because it is a list of 157 strings and not a decision.
One consequence was not obvious. Renaming 100 headings invalidates any link
that names a section by its anchor, and rule 9 of check_docs_structure.sh
discarded the fragment ((?:#[^)]*)?) — a link to a renamed section resolved to
the file and passed. It now computes GitHub's slug, including the -1 / -2
suffix for repeated headings, and verifies the fragment. It immediately reported
two anchors in chapter 30 that had been wrong since they were written, before
any rename.
R5 in the skill: the scope of a background section is decided by the problem, not by the tool. Chapter 00's background was about modules, which is the part of the problem mcpp is closest to. The problem a reader actually has is that a C++ project needs four things at once — a build description, dependencies, a compiler new enough, and an environment the result runs in — and no single tool owns all four. CMake is the de facto standard for the first, 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, not the structure.
The user asked where the plugin system is documented, and whether it reaches preprocessing and languages of one's own. The tree had chapter 30 (build programs) and chapter 31 (rule packages), and between them every primitive — but no section stating the model: what the extension points are, what the ecosystem has built from them, and where the boundary is. R1 says a topic has exactly one owner, and this one had none.
Chapter 31 now opens with it: five extension points with their effect and where each is declared; seven things the ecosystem has built from them; 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, which is measured rather than asserted —
- a dependency's
device_extensionsis consulted after the built-in roles, so a rule package cannot claim.cpp. Adding".cpp"to a rule's list is not diagnosed and has no effect, measured; - module-interface extensions are
[build] module_extensions, a project axis, because a module interface is scanned, produces a BMI and joins the link — three engine behaviours rather than a command; - an extension in neither table is refused by name, quoted from the run.
examples/12-a-new-device-language had a .toy that was "one integer per line,
and the entry point returns their sum", compiled by a shell script. It
demonstrated the two manifest keys and nothing else, and it was not a shape any
ecosystem author meets.
.toy now has let, assignment, if/else, while, calls between kernels,
and the arithmetic and comparison operators. Its compiler is an ordinary mcpp
package — lexer, recursive-descent parser, semantic checks, C++ emitter — built
for the build machine through tools = ["toyc"] + reexport = true and
reached with mcpp::dep_bin. That makes it the tree's first example of a
dependency producing a host tool, a capability that until now existed only in
prose.
And it measured a boundary the documentation did not state. The tool store's
key is the tool package's identity, version, host triple, compiler identity,
profile, features and the versions of its transitive dependencies. It holds no
source content, so editing a path tool's sources without changing its version
leaves the cached binary in place: mcpp run reported Finished dev in 0.00s
and printed the previous answer. Chapter 30 now states it, with the two ways
out. The action itself is not the gap — the rule declares the compiler binary
as an input, so a changed binary dirties the edge. What does not happen is the
rebuild that would change those bytes.