Skip to content

Commit 158bfc3

Browse files
committed
design: what the four fields do, read in the xlings source
Section 13 answers section 4 and Q1 from the implementation rather than from inference, and corrects two claims this document and docs/05 both made. xlings does not provision from workspace: deps is the only key any install path reads, so the merge belongs in mcpp.toml and the file keeps both fields — one statement materialised into the two places xlings reads its two halves. envs has no reader on either side. Every consumer in the xlings source is either xvm's per-program VData::envs or a SubOS's subos_info provider sections, and neither is the flat object mcpp writes; mcpp's own run environment comes from the runtime binding. The key is documented as having an effect it does not have, and the section proposes deciding its fate before this proposal ships. Also recorded: a named subos drops the global workspace layer entirely, which is a property of subos that nothing in mcpp states today.
1 parent 3ac07da commit 158bfc3

1 file changed

Lines changed: 122 additions & 10 deletions

File tree

.agents/docs/2026-09-03-xlings-workspace-as-the-one-table.md

Lines changed: 122 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

121133
One consequence for section 3's W2. mcpp does not only pass the author's
122134
entries 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
399411
package-shaped fields exists, and to the resolution loss §7 describes, which
400412
the 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

Comments
 (0)