Skip to content

Commit b9cb76e

Browse files
committed
design: the authored project file is the reference, not a SubOS state file
Two artifacts share the name and this document measured one for the other. The authored file maps a name to a version string or a platform object; d2mcpp/.xlings.json is the published example, and it settles two of the three open items. Version unconstrained is the empty string. "code": "" is already in use, the resolver returns it unchanged, and an empty value reads downstream as claiming no version — which is what deps = ["cmake"] means today. No * and no latest is introduced. The namespace in the key position is undefined rather than forbidden: nothing derives an install address from a workspace entry, because nothing installs from workspace at all, so the question becomes real only when mcpp does. Both candidate forms are stated with what each costs, and the item is marked as a request rather than a finding. The native platform keys are recorded as linux, windows, macosx and default.
1 parent f458495 commit b9cb76e

1 file changed

Lines changed: 77 additions & 69 deletions

File tree

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

Lines changed: 77 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -91,62 +91,62 @@ llvm = { macos = "20", default = "22" }
9191

9292
Three decisions the table needs, listed for review.
9393

94-
**W1. There is no `"*"`, and none should be invented.** xlings already has two
95-
spellings for "not an exact version": a version **prefix**, which
96-
`match_version` resolves to the highest match (`src/core/xvm/db.cpp:411``22`
97-
selects `22.1.8`), and `latest`, which `cmd_use` resolves to the highest
98-
installed version before writing (`commands.cpp:592-607`). Both are **input**
99-
spellings: what lands in a workspace file is always a concrete version, which
100-
is why a stored `latest` would fail at shim time rather than mean anything. The
101-
manifest therefore accepts a version, a prefix, or `latest`, and "must exist,
102-
version unconstrained" is spelled `latest`. Measured on three real subos files
103-
on the development host: every stored value is concrete.
104-
105-
**W2. The namespace goes on the version, not on the key — and the key form was
106-
checked rather than assumed.** Measured on the development host: 1635 targets
107-
in the version database and 546 workspace entries in the default SubOS, and
108-
**not one key contains a colon**. The colon appears on the other side:
109-
`"mcpp": {"active": "xim:2026.8.30.2", …}`.
110-
111-
`ns:name` as a key was considered and does not work, for a reason stronger than
112-
convention. A workspace key is looked up by the name a program is **invoked
113-
as** (`get_active_version(workspace, program_name)`,
114-
`src/core/xvm/shim.cpp:409-412`); nothing is ever invoked as
115-
`xim:picolibc-riscv`, so such a key would be read by nobody — the shape §6
116-
refuses for `deps`.
117-
118-
And the namespace is not a property of the tool. It qualifies **where a version
119-
came from**, which is why one target legitimately carries both scoped and
120-
unscoped versions at once. Measured, on this machine, for `mcpp` itself:
121-
122-
```
123-
"mcpp": { "active": "xim:2026.8.30.2",
124-
"installed": ["2026.8.21.1", …, "xim:2026.8.28.2", "xim:2026.8.30.1"] }
125-
```
126-
127-
Eight versions of one target, some from the xim index and some not. Moving the
128-
namespace onto the key would split that into two targets, and `mcpp` on `PATH`
129-
would resolve to whichever half won — which is the same defect in the small
130-
that `ar` from two providers would be in the large.
131-
132-
So the form is:
133-
134-
```toml
135-
[xlings.workspace]
136-
picolibc-riscv = "xim:1.8.12"
94+
These are settled against the **authored project file**, not against a SubOS
95+
state file. The two are different artifacts: a state file is what `cmd_use`
96+
writes (`{active, installed}` records, one per binding-group member), while a
97+
project file is what a person writes. `mcpp-community/d2mcpp/.xlings.json` is a
98+
published example of the latter:
99+
100+
```json
101+
{
102+
"workspace": {
103+
"d2x": "2026.08.02.2",
104+
"mdbook": "0.4.43",
105+
"code": "",
106+
"mcpp": { "linux": "2026.8.2.1", "macosx": "2026.8.2.1", "windows": "2026.8.2.1" }
107+
}
108+
}
137109
```
138110

139-
the key being the xvm target and the namespace riding the value, exactly as the
140-
file writes it. mcpp reconstructs the install address `xim:picolibc-riscv@1.8.12`
141-
from the pair when it provisions, so nothing is lost, and the C library mcpp
142-
injects (§4) is expressible in the same shape.
143-
144-
A key containing a colon is a **hard error naming the correct form**, rather
145-
than a second accepted spelling: one fact, one way to write it, is the whole
146-
argument of this document applied to itself.
147-
148-
**W3. The per-platform value form is unchanged.** It is already accepted on
149-
both keys (2026.9.2.1) and it survives the merge unmodified.
111+
**W1. "Version unconstrained" is the empty string, and it is already in use.**
112+
`"code": ""` in the example above is the spelling. `resolve_platform_workspace_value_`
113+
returns it unchanged and `workspace_from_json` stores it
114+
(`src/core/xvm/db.cppm:383`, `db.cpp:1100-1110`); downstream, an empty value is
115+
read as "this entry claims no version" (`Config::version_origin`'s `claims`
116+
predicate, `config.cpp:1108-1112`). So the entry names a member of the
117+
environment and leaves its version open, which is exactly what `deps = ["cmake"]`
118+
means today. No `*` and no `latest` is introduced: `""` is the form the file
119+
already has, and it maps onto an install target with no `@version`.
120+
121+
**W2. The namespace is undefined in this position today, and defining it is
122+
xlings' call.** No workspace key anywhere carries one: not in the authored
123+
example above, and not in 1635 version-database targets or 546 SubOS entries on
124+
the development host. The colon appears only on the version side, where a
125+
scope qualifies where a version came from — `"mcpp": {"active":
126+
"xim:2026.8.30.2", …}`, one target holding both scoped and unscoped versions.
127+
128+
But that is a statement about **resolution**, and the namespace is needed for
129+
**installation**, and nothing derives an install address from a workspace entry
130+
today, because nothing installs from `workspace` at all (§13.2). The moment
131+
mcpp does, the question becomes real and has two candidate answers:
132+
133+
| Form | Reads | Costs |
134+
|---|---|---|
135+
| `picolibc-riscv = "xim:1.8.12"` | key is the xvm target; the scope rides the version, as the version database already spells it | the address is assembled from two halves |
136+
| `"xim:picolibc-riscv" = "1.8.12"` | key is the install address, as `deps` spells it | the key is no longer the name the shim looks up, so resolution has to strip it |
137+
138+
The second is closer to `deps` and to how a person thinks about a package; the
139+
first is closer to what the file already contains. Either works if the rule is
140+
stated once — what must not happen is both being accepted, which would put one
141+
fact in two spellings. **This is the one item in section 3 that is a request
142+
rather than a finding.**
143+
144+
**W3. The per-platform form is xlings' own, and its native keys are
145+
`linux`, `windows`, `macosx` and `default`** (`platform::OS_NAME` per
146+
`modules/platform/src/platform/*.cppm`, resolved by
147+
`resolve_platform_workspace_value_`). mcpp additionally accepts `macos` as an
148+
alias, which is a superset and stays; the documentation should show `macosx`
149+
as the aligned spelling.
150150

151151
## 4. What mcpp writes into `.xlings.json`
152152

@@ -537,29 +537,37 @@ workspace replaces the global one. That belongs in `docs/17`.
537537
answers Q1: xlings does not provision from `workspace`, which is why section 4
538538
was revised rather than kept.
539539
540-
### 13.3.1 What a workspace key is: an xvm target, of any kind
540+
### 13.3.1 Two artifacts share the name `.xlings.json`
541+
542+
They must not be measured for each other, and this document did so once.
543+
544+
**The authored project file** is what a person writes and what mcpp
545+
materialises: `workspace` maps a name to a version string or to a
546+
platform-conditional object, and nothing else. `d2mcpp/.xlings.json` is the
547+
published example (§3).
541548
542-
Measured on the development host's default SubOS, 546 entries:
549+
**A SubOS state file** is what `cmd_use` writes: the same key space, but each
550+
value is an `{active, installed[]}` record, and the keys are every member of
551+
every release ever switched to. On the development host's default SubOS that is
552+
546 entries, including package roots, their programs, and file assets:
543553
544554
```
545555
binutils = 2.42 ar = 2.42 as = 2.42 ld = 2.42
546556
gcc = 16.1.0 g++ = 16.1.0 cc = 16.1.0
547-
mcpp = xim:2026.8.30.2
548557
Scrt1.o, crt1.o, crti.o, crtn.o, glibc.files.1 … glibc.files.101
549558
```
550559
551-
Package roots, the programs of those packages, and file assets all live in one
552-
namespace, each with `{active, installed}`. A package root and its programs
553-
carry the **same version** because they are members of one release and
554-
`cmd_use` wrote them together (§15.1) — that identity is the group expansion's
555-
own footprint in the data.
556-
557-
So "the workspace holds packages" and "the workspace holds programs" are both
558-
half-right: it holds xvm targets, and a package's root is one of them. Writing
559-
the package in a manifest is therefore a legitimate entry, and its programs
560-
receive the same version when the entry is honoured. Writing a program is
561-
equally legitimate and selects the same release. What a key never carries is a
562-
namespace; that rides the value (§3 W2).
560+
A package root and its programs carry the same version there because they are
561+
members of one release and `cmd_use` wrote them together (§15.1). That identity
562+
is the group expansion's footprint, and it is why writing a package root in a
563+
project file pins its programs: the expansion happens when the entry is
564+
honoured.
565+
566+
The parser accepts both shapes for a value and disambiguates by reserved keys —
567+
an `active` or `installed` key marks the state form, anything else is read as
568+
the project form (`src/core/xvm/db.cppm:405-420`). So the two files are one
569+
schema seen at two stages, and the project form is the one mcpp's `[xlings]`
570+
mirrors.
563571
564572
### 13.4 `envs` has no reader anywhere
565573

0 commit comments

Comments
 (0)