@@ -107,16 +107,28 @@ both keys (2026.9.2.1) and it survives the merge unmodified.
107107
108108## 4. What mcpp writes into ` .xlings.json `
109109
110- ** Decided (2026-09-03): mcpp writes ` workspace ` , and nothing else changes.**
111- The correspondence between ` [xlings] ` and ` .xlings.json ` is one to one in name
112- and in meaning, so ` [xlings.workspace] ` materialises as the file's ` workspace `
113- object and the merged semantics is xlings' own. The ` deps ` array stops being
114- emitted when ` deps ` is retired.
115-
116- The alternative — deriving a ` deps ` array from ` workspace ` when writing — is
117- rejected. It is a translation layer, which §2.13 refuses, and it would put the
118- same statement in the file twice, which is the drift shape section 1 exists to
119- remove.
110+ ** Decided (2026-09-03), and revised the same day against the xlings source
111+ (§13): the merge belongs in ` mcpp.toml ` , and the file keeps both fields.**
112+
113+ One authoring key. When mcpp materialises it, an entry becomes a ` deps ` element
114+ * and* a ` workspace ` member, because the file's two fields have two different
115+ consumers in xlings and neither subsumes the other: ` deps ` is the install
116+ trigger read by a bare ` xlings install ` (` src/core/cmdprocessor.cpp:163 ` ), and
117+ ` workspace ` is a version-resolution layer merged into the project's effective
118+ pins (` src/core/config.cpp:660 ` , ` :846 ` ). Emitting both is not a translation
119+ layer — it is the faithful materialisation of one statement, "use this at this
120+ version, provision it if absent", into the two places xlings reads those two
121+ halves.
122+
123+ The earlier draft of this section proposed writing only ` workspace ` and letting
124+ xlings provision from it. §13 measures that xlings does not: ` deps ` is the only
125+ key its install path reads. Writing only ` workspace ` would have produced a
126+ project that builds where the packages happen to be installed and fails on a
127+ clean machine, which is the failure this document exists to avoid.
128+
129+ If xlings later provisions from ` workspace ` , the ` deps ` half of the emission
130+ can be dropped without touching ` mcpp.toml ` or any manifest. That is the
131+ end-state, and it is a change on the xlings side, not here.
120132
121133One consequence for section 3's W2. mcpp does not only pass the author's
122134entries through: it appends the target's C library to the same channel
@@ -398,3 +410,103 @@ answered here.
398410`PATH` contract are unchanged. The change is confined to which of the two
399411package-shaped fields exists, and to the resolution loss §7 describes, which
400412the merged field inherits.
413+
414+ ## 13. What the four fields actually do, measured in the xlings source
415+
416+ Read at `/home/speak/workspace/github/openxlings/xlings`, 2026-09-03. Section 4
417+ and question Q1 of section 11 are answered here; section 12.5 is corrected.
418+
419+ ### 13.1 How the file is found at all
420+
421+ xlings locates a project config by walking the current directory upward for a
422+ `.xlings.json`, stopping at any directory that also contains a `subos/` — that
423+ signature means "an xlings home", never a project — and, failing that, by
424+ reading `XLINGS_PROJECT_DIR` (`src/core/config.cpp:765-799`).
425+
426+ mcpp writes `<project>/.mcpp/.xlings.json` and passes
427+ `XLINGS_PROJECT_DIR=<project>/.mcpp`, so the file is reached through the
428+ environment variable, not the walk. A person standing in the project root and
429+ running `xlings` does not see it: the walk looks for `<project>/.xlings.json`,
430+ one level up from where mcpp writes. Measured on a real materialisation
431+ (`mcpplibs/riscv-virt-rt/.mcpp/.xlings.json`), whose `.mcpp/` holds no `subos/`
432+ and therefore does not trip the home boundary.
433+
434+ ### 13.2 `deps` is the only install trigger, on both sides
435+
436+ `install_from_project_config` (`src/core/cmdprocessor.cpp:163-196`) is the
437+ no-argument `xlings install`. It reads `deps`, errors when the key is absent or
438+ is not an array, and installs each entry through
439+ `xmake xim -P <home> -- <target> -y`. It reads no other key.
440+
441+ mcpp's own provisioning does not use that path: it calls the `install_packages`
442+ capability with targets it read from `mcpp.toml` itself. So the `deps` array in
443+ the file serves a different consumer — a person running bare `xlings install` —
444+ than the pass that makes `mcpp build` work.
445+
446+ ### 13.3 `workspace` is a version layer, and a named subos drops the global one
447+
448+ The project file's `workspace` object is read into `projectWorkspace_`
449+ (`config.cpp:660-662`) and becomes one layer of the effective pins.
450+ `merged_workspace` (`config.cpp:846-864`) resolves them:
451+
452+ | Project subos mode | Layers merged, later winning |
453+ |---|---|
454+ | `Named` (the file declares `subos`) | project manifest, then that subos's own workspace |
455+ | `Anonymous` (project file, no `subos`) | global, then project manifest, then the project subos |
456+ | no project config | global only |
457+
458+ **A named subos drops the global workspace entirely.** A project that declares
459+ `[xlings] subos` therefore loses the machine's global pins for every tool it
460+ does not pin itself, and nothing in mcpp says so today. That is a property of
461+ `subos`, not of this proposal, and it belongs in `docs/17`.
462+
463+ **A `workspace` entry installs nothing.** No install path reads it. This
464+ answers Q1: xlings does not provision from `workspace`, which is why section 4
465+ was revised rather than kept.
466+
467+ ### 13.4 `envs` has no reader anywhere
468+
469+ Every `envs` consumer in the xlings source is one of two structures, and
470+ neither is the flat object mcpp writes:
471+
472+ 1. `xvm`'s `VData::envs` — environment variables attached to **one program's**
473+ shim, stored in the version database and applied when the shim runs
474+ (`src/core/xvm/db.cpp:724`, `src/core/xvm/shim.cpp:337`). Set through
475+ `xvm add --env`, not through any project file.
476+ 2. A SubOS's `subos_info.envs` — "an object of **provider sections**" keyed by
477+ binding (`src/core/subos/manifest.cpp:197-290`), part of the environment's
478+ own metadata.
479+
480+ Searching the whole source for `contains("envs")` and `["envs"]` outside those
481+ two files and the doctor that checks them returns nothing. There is no reader
482+ for a flat name-to-value `envs` object in a project or home `.xlings.json`.
483+
484+ **So `[xlings.envs]` is written by mcpp and read by nobody.** It does not reach
485+ a built program's environment either: `compute_subos_env`
486+ (`src/build/execute.cppm:418`) derives that from `plan.runtimeBinding`, the
487+ SubOS's own `subos_info`, and never consults `[xlings.envs]`. The sentence in
488+ `docs/05-mcpp-toml.md` §2.13 that calls it "env vars applied to the tool
489+ environment" describes an effect that does not occur.
490+
491+ Three ways out, and the choice is not this document's to make:
492+
493+ - **Wire it in xlings**: give the project file a flat `envs` object that the
494+ tool environment applies. The key already exists in mcpp and in the file.
495+ - **Map it onto `xvm`'s per-program `envs`**: possible only if the manifest
496+ says which program each variable belongs to, which `[xlings.envs]` does not.
497+ - **Retire it**, on the same three-phase path §6 gives `deps`, and for the same
498+ reason: a key that is read by nobody is the shape #531 exists to prevent, and
499+ it is worse here because the documentation states an effect.
500+
501+ The recommendation is to decide before this proposal ships, because retiring
502+ `deps` while leaving a second dead key in the same section would leave the
503+ section half-audited.
504+
505+ ### 13.5 Corrections this section makes to the rest of the document
506+
507+ | Where | Was | Is |
508+ |---|---|---|
509+ | §4 | mcpp writes only `workspace` | mcpp writes both fields; the merge is in `mcpp.toml` |
510+ | §11 Q1 | open | answered: xlings does not provision from `workspace` |
511+ | §12.1 | `envs` reader: "the materialisation" | no reader on either side |
512+ | §12.5 | `[xlings.envs]` is read by xlings for the tool environment | it is read by nothing |
0 commit comments