Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
495edd5
2026.11.11.1: five rows the platform's own data serves
Nov 11, 2026
6c325b1
the llvm pin stays 23.1.3 everywhere; no #ifdef in module code
Nov 11, 2026
d7a9bc3
runner_lookup: the signal constants come from the mwrap of libc's macros
Nov 11, 2026
33c80e6
docs/zh: the longjmp row joins the abi table
Nov 11, 2026
09b1779
fix: the loader fold reads the generic string, not the native wide po…
Nov 11, 2026
c18bd6f
the CI legs the change itself turned up
Nov 11, 2026
d6f73ed
the mingw headers resolve lazily at both sites, and 299 reads the bra…
Nov 11, 2026
ead6bad
docs: the three-plane platform architecture, as the reference the nex…
Nov 11, 2026
d6abf3a
2026.11.12.1: the release the ecosystem round lands in; the three-pla…
Nov 11, 2026
ff990b2
docs: the architecture record carries its front matter, as the gate r…
Nov 11, 2026
891e1f5
docs: the agents index lists the new record
Nov 11, 2026
262357a
1076 runs again: the index carries the sysroot payload it skips without
Nov 11, 2026
e603382
root_position_key keeps its cross-version shape; abi longjmp invalida…
Nov 12, 2026
cf1492f
split the per-subject manifest policy out of step13_windows_resources…
Sunrisepeak Nov 12, 2026
0819c80
keep the long-path lookup's if off the windowsLongPaths line: the own…
Sunrisepeak Nov 12, 2026
9faee27
wip: corrections C1-C3, C6-C10; system table, provider runner, one lo…
Sunrisepeak Nov 12, 2026
a459dc5
wip: e2e 1076/1077/330, SPEC-016 v1.2, system-name ratchet, golden li…
Sunrisepeak Nov 12, 2026
adc3eb3
wip: docs en/zh, changelog, tier in why target, e2e 1080, ratchet in …
Sunrisepeak Nov 12, 2026
330b400
wip: bench leaves the per-commit run (main, dispatch, ci:bench)
Sunrisepeak Nov 12, 2026
eed19cb
wip: SPEC-013 v1.8, SPEC-014 v2.3, SPEC-002 v1.8
Sunrisepeak Nov 12, 2026
6582b8e
wip: design record section 15; the three-plane record is superseded
Sunrisepeak Nov 12, 2026
35b8540
wip: the matrix declares the cross arrangement of aarch64-linux-gnu o…
Sunrisepeak Nov 12, 2026
3df4277
wip: the openkal targets' platform is openkal-platform 0.27.0
Sunrisepeak Nov 12, 2026
b7e66a2
wip: member test and e2e 254 follow the providers' data
Sunrisepeak Nov 12, 2026
65ec20f
wip: e2e 986 holds FreeBSD's single files
Sunrisepeak Nov 12, 2026
1699976
wip: the musl identities of macOS stay listed on a macOS host, as gra…
Sunrisepeak Nov 12, 2026
6fc353f
wip: a script that skips itself is a skip (exit 77, mtest skip_exit);…
Sunrisepeak Nov 12, 2026
f7b3c85
wip: the skip status in the test spec and AGENTS.md
Sunrisepeak Nov 12, 2026
eda6d3e
wip: a runner template's place the build does not have is refused
Sunrisepeak Nov 12, 2026
64bbe56
wip: CI runs with mtest 0.6.1
Sunrisepeak Nov 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
875 changes: 875 additions & 0 deletions .agents/docs/2026-11-12-ecosystem-architecture-optimization-design.md

Large diffs are not rendered by default.

125 changes: 125 additions & 0 deletions .agents/docs/2026-11-12-three-plane-platform-architecture-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
subject: architecture
status: superseded
superseded_by: 2026-11-12-ecosystem-architecture-optimization-design.md
---

# The three-plane platform architecture: mcpp × openkal × xim

Date: 2026-11-12
Status: superseded by
[the ecosystem architecture optimization design](2026-11-12-ecosystem-architecture-optimization-design.md),
which extends sections 1, 2, 4 and 5 into four planes. Section 3 was written
before the round it describes was checked: its items 2 and 3 did not land in
the form stated there. A base package is read as a sysroot and the artifact
names the row's loader (not a loader "folded sysroot-relative" beside the
payload's own `-B/-L`), and an artifact of another system is not started at all
(not run as a child whose death is classified). The record of what was
implemented, with the check that holds each item, is section 15 of the
superseding design.

## 1. The statement

A platform enters this ecosystem as **data**, never as engine code. Three
data planes carry everything a target needs, and one normalisation layer
decides whether what was built is right:

| Plane | Carries | Where it lives | Invariant |
|---|---|---|---|
| ① row | serves/hosts/toolchain/sysroot/linkage/abi of a target identity | the toolchain model's table, or a platform package's own rows | target differences are data; the engine holds no per-target branch |
| ② payload | the toolchain bytes, and the base package that is the target's C library | the index (xim), installed by the fetcher through the revision channel | a build host needs mcpp itself and nothing else; where a row names a base package the host's link model yields entirely |
| ③ runner | how an artifact of another system starts (a declared prefix, an emulator, a loader) | row/platform data; resolved by the runner lookup | build never depends on a runner; running consumes the declaration |
| verification | one script, one expected output, normalised (CRLF, colour, codeset, console noise) | the shared harness | the harness knows no target; every executor family answers through it |

Two red lines hold throughout, and the gates hold them mechanically:
default behaviour is unchanged by any of it (the regressions stay green), and
no host name enters the engine — host differences are statements rows make.

## 2. The layering the planes serve

```mermaid
flowchart TB
subgraph consumer["a program of any system"]
A["import the C++ modules / C sources"]
end
subgraph libc["one C library, ported once"]
M["libc above the kernel ABI (spec)</br>static where the row says static"]
end
subgraph kal["the kernel-ABI specification"]
K["openkal: the interface, its conformance suite</br>and one implementation per system family"]
end
R1["row ① + payload ②"] --> A
M --> A
K --> M
KF["firmware implementations</br>(UEFI boot services, RISC-V SBI)"] --> K
KP["kernel implementations</br>(the reference kernel's own interface,</br>a BSD kernel's, a Windows kernel's)"] --> K
KX["a POSIX-library implementation</br>(for systems whose own libc is the interface)"] --> K
R3["runner ③"] -. runs the artifact on.-> consumer
```

The specification's own rules make the layering safe: an implementation may
declare an interface absent (the conformance suite decides which absences are
legal), a C library above the interface never sits above an implementation
that would call back into it (layer-cycle refuses that graph at resolution),
and a program states which ABI it speaks by depending on one.

## 3. What the merged round established

Measured, not aspirational (each item landed with its gate green):

1. **Rows as the only place targets differ.** Eighteen identities build from
one engine with zero per-target code; the identity that was missing
arrived as one table row plus one base package.
2. **Base packages.** Where a row names one, the payload is the target's C
library: the driver gets `--sysroot`, the payload's own `-B/-L`, a
loader folded sysroot-relative, and the compiler's runtime directory —
and the host's link words, runtime directories and closure rules yield
entirely. A cross needs nothing from the machine it stands on.
3. **Foreign-kernel execution.** An artifact of another system, of this
machine's architecture, runs as a child: its death by signal is named,
its status returned unchanged, and the runner declaration follows it.
4. **ABI members as data.** `abi longjmp` states how a jump crosses the
WebAssembly boundary; the probe renders the flag on both sides, and a
row that is not the member's subject is refused rather than ignored.
5. **Corrective revisions.** A resource whose bytes must change without a
version change is re-published under the same key with a raised
revision; the updater channel enforces that a raise is total — every
platform, one sha per url, shapes compared.
6. **One file, several systems.** A pack can hold the programs of several
systems: a PE leads with a POSIX script in its DOS header, and every
POSIX system's program rides behind it.
7. **Layer vocabulary.** `kernel-abi` is a layer the rows, the payloads and
the requirement side all speak (`layers.kernel-abi`, `requires`), an
implementation written above a C library never sits beneath one it would
call back into — the resolution refuses that graph before anything is
compiled — and a payload's kernel-abi is the target's system, so a
requirement stated on it holds across every route to the row.

## 4. What the next systems consume

The same planes, with no engine work:

| Scenario | What it uses | What is left to build |
|---|---|---|
| A POSIX-family kernel with its own libc | the POSIX-library implementation of the ABI (already above every such libc), rows, a cross toolchain payload | the toolchain payload; a disk-image asset; an emulator runner |
| Firmware (UEFI, SBI) | the existing firmware implementations; an ordinary PE row and three link flags state a UEFI application — measured, no new target kind; a runner's exit status is the program's (the contract already carries firmware: the harness states the status) | an OVMF/emulator runner entry |
| A system's official media, booted | the disk-image asset class (`<system>-disk-image`): official media assembled into a bootable image, serial console, a marker protocol that separates the program's output from the machine's noise, exit codes carried through | the generic emulator harness (overlay isolation, expect/send primitives, the marker protocol); the naming and attribution conventions |
| Freestanding and bare-metal targets | the freestanding rows; a C-only, no-module path | the conformance hook-ups |
| Any corrective republish | the revision channel | nothing |

The one boundary this architecture states out loud: the **semantic plane** —
a process model, a terminal — is the program's own. The infrastructure
answers that a target can be built, started and judged; it does not port the
program.

## 5. Naming (index side)

- Generic assets and toolchains carry no prefix; a tool whose contract is a
build-system session carries that system's prefix.
- A bootable-image asset is named `<system>-disk-image` — the thing, not a
mechanism, not a format; the asset's file names carry the format.
- Official media is attributed to its publisher in the recipe; repacked
bytes are provenance-recorded, double-mirrored, sha-identical.

These are conventions of the index, not engine vocabulary; the engine knows
none of the names.
9 changes: 8 additions & 1 deletion .agents/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ superseded_by: 2026-09-07-....md # when status is superseded
---
```

358 records.
360 records.

## By subject

Records that declare one. Everything else is listed by date below.

### architecture

- [The three-plane platform architecture: mcpp × openkal × xim](2026-11-12-three-plane-platform-architecture-design.md) — superseded by [2026-11-12-ecosystem-architecture-optimization-design.md](2026-11-12-ecosystem-architecture-optimization-design.md)

### build

- [大型工作区的构建空间与复用(mcpp#874)](2026-10-31-workspace-space-and-reuse-design.md) — active
Expand Down Expand Up @@ -79,6 +83,7 @@ Records that declare one. Everything else is listed by date below.

### ecosystem

- [生态架构优化方案:四个平面的收敛、已合入项的纠正与新系统的准入(mcpp × openkal × xlings)](2026-11-12-ecosystem-architecture-optimization-design.md) — active
- [测试与依赖解析补充方案:mcpp、mcpp test、mtest、mcpp-ide](2026-11-10-test-and-resolution-supplement-design.md) — active
- [生态顶层方案:#885 收尾之后的工作流、原则与依赖](2026-11-08-ecosystem-top-level-design.md) — active
- [#885 收尾补充方案:目标角色、平台事实、系统接口与版本书写](2026-11-08-ecosystem-885-supplement-design.md) — active
Expand Down Expand Up @@ -188,6 +193,8 @@ Records that declare one. Everything else is listed by date below.

### 2026-11

- [The three-plane platform architecture: mcpp × openkal × xim](2026-11-12-three-plane-platform-architecture-design.md) — superseded by [2026-11-12-ecosystem-architecture-optimization-design.md](2026-11-12-ecosystem-architecture-optimization-design.md)
- [生态架构优化方案:四个平面的收敛、已合入项的纠正与新系统的准入(mcpp × openkal × xlings)](2026-11-12-ecosystem-architecture-optimization-design.md) — active
- [测试与依赖解析补充方案:mcpp、mcpp test、mtest、mcpp-ide](2026-11-10-test-and-resolution-supplement-design.md) — active
- [生态方案:跨平台通用基础设施(mcpp + openkal + xim),以一个 C89 工程为验证](2026-11-10-cross-platform-ecosystem-design.md) — active
- [目标与提供者:统一的目标模型(结合 mcpp#911)](2026-11-09-target-model-design.md) — active
Expand Down
21 changes: 18 additions & 3 deletions .github/tools/check_e2e_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@
and neither does a longer name that contains it;
excused tests/e2e/coverage-exceptions.tsv lists it with the reason no hosted
runner can run it;
owed tests/e2e/coverage-debt.tsv lists it: it skips itself on every
host that starts it (a script leaves with 77 after a `SKIP:` line
when it can hold nothing on a machine, and the run reports it as a
skip). The list is a debt, and it only shrinks: each entry names
what a host lacks, and is removed when a host gains it;
uncovered none of these. The check fails.

An exception for a test that ran, or for a test that does not exist, also fails
the check, so that the list cannot outlive the reason it records.
An exception or a debt entry for a test that ran, or for a test that does not
exist, also fails the check, so that neither list can outlive the reason it
records.

Some claims need a test to pass on particular hosts, not on some host: docs/21
calls a target row `verified` when CI builds and runs its artefact, and the
Expand Down Expand Up @@ -133,6 +139,7 @@ def main() -> int:
workflows = workflow_tokens([p.read_text(encoding="utf-8")
for p in sorted((root / ".github" / "workflows").glob("*.yml"))])
exceptions = read_exceptions(root / "tests" / "e2e" / "coverage-exceptions.tsv")
debt = read_exceptions(root / "tests" / "e2e" / "coverage-debt.tsv")
required = read_host_requirements(root / "tests" / "e2e" / "host-requirements.tsv")

ran: dict[str, set[str]] = defaultdict(set)
Expand Down Expand Up @@ -165,17 +172,25 @@ def main() -> int:
counts["ran"] += 1
if test in exceptions:
stale.append(f"{test} is excused but ran on {', '.join(sorted(ran[test]))}")
if test in debt:
stale.append(f"{test} is listed as owed but ran on {', '.join(sorted(ran[test]))}: "
f"remove it from coverage-debt.tsv")
elif test in unaffected:
counts["unaffected"] += 1
elif named_by_a_workflow(test, workflows):
counts["job"] += 1
elif test in exceptions:
counts["excused"] += 1
elif test in debt:
counts["owed"] += 1
else:
uncovered.append(f"{test}: {'; '.join(sorted(skipped[test])) or 'in no report'}")
for test in exceptions:
if test not in tests:
stale.append(f"{test} is excused but does not exist")
for test in debt:
if test not in tests:
stale.append(f"{test} is listed as owed but does not exist")
unmet = []
for test, hosts in sorted(required.items()):
if test not in tests:
Expand All @@ -188,7 +203,7 @@ def main() -> int:

print(f"{len(tests)} tests: {counts['ran']} ran on a shard, {counts['unaffected']} unaffected by "
f"the change, {counts['job']} run by a dedicated job, {counts['excused']} excused, "
f"{len(uncovered)} uncovered")
f"{counts['owed']} owed, {len(uncovered)} uncovered")
for (host, shard), ms in sorted(shard_ms.items()):
print(f" {host} shard {shard}: {ms / 60000:.1f} min of tests")
for line in uncovered:
Expand Down
173 changes: 173 additions & 0 deletions .github/tools/check_system_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""check_system_names.py -- the engine's sources name no more systems than the baseline.

WHY THIS EXISTS

AGENTS.md section 2 states that the engine names no operating system: target
rows, providers and systems are data (modules/toolchain-model/data/builtin.toml,
SPEC-016), and code that is specific to one host lives in modules/platform/.
A review cannot hold that sentence: a branch on `"freebsd"` reads as an
ordinary line, and several entered the tree beside the tables that were meant
to replace them (design 2026-11-12, cause R1). This check counts instead.

WHAT IS COUNTED

Each word of the vocabulary below, in the engine's sources -- `src/` and
`modules/*/src/`, without `modules/platform/` and without tests and data --
in the two forms a branch on a system takes: the word as a string literal
(`"freebsd"`), and the host predicates of mcpplibs.os (`is_linux`,
`is_windows`, `is_macos`). Comments are not counted.

THE RATCHET

`system-names.baseline` records one number per word. More occurrences than the
baseline fail: the new line states a system fact, which belongs in a row, in
the system table or in a provider. Fewer occurrences fail as well, with the
line to write: the baseline follows the code down, so the count never returns.

check_system_names.py compare with the baseline
check_system_names.py --update rewrite the baseline to the counts found
check_system_names.py --list W print every counted line of word W
"""

import pathlib
import re
import sys

ROOT = pathlib.Path(__file__).resolve().parents[2]
BASELINE = pathlib.Path(__file__).with_name("system-names.baseline")

LITERALS = ["linux", "macos", "windows", "freebsd", "android", "emscripten", "ios",
"darwin", "netbsd", "openbsd", "haiku", "dos", "uefi"]
PREDICATES = ["is_linux", "is_windows", "is_macos"]

SOURCE_SUFFIXES = {".cppm", ".cpp", ".mcpp"}


def sources():
for base in (ROOT / "src", ROOT / "modules"):
for path in sorted(base.rglob("*")):
if path.suffix not in SOURCE_SUFFIXES or not path.is_file():
continue
rel = path.relative_to(ROOT).as_posix()
if rel.startswith("modules/platform/"):
continue
parts = rel.split("/")
if "tests" in parts or "target" in parts or "data" in parts:
continue
yield rel, path


def code_of(line, state):
"""The line without its comments. `state["block"]` carries a /* */ across lines."""
out = []
i = 0
in_string = False
while i < len(line):
if state["block"]:
end = line.find("*/", i)
if end < 0:
return "".join(out)
state["block"] = False
i = end + 2
continue
ch = line[i]
if in_string:
out.append(ch)
if ch == "\\" and i + 1 < len(line):
out.append(line[i + 1])
i += 2
continue
if ch == '"':
in_string = False
i += 1
continue
if ch == '"':
in_string = True
out.append(ch)
i += 1
continue
if line.startswith("//", i):
break
if line.startswith("/*", i):
state["block"] = True
i += 2
continue
out.append(ch)
i += 1
return "".join(out)


def count():
patterns = {w: re.compile(r'"%s"' % re.escape(w)) for w in LITERALS}
patterns.update({w: re.compile(r"\b%s\b" % w) for w in PREDICATES})
counts = {w: 0 for w in patterns}
lines = {w: [] for w in patterns}
for rel, path in sources():
state = {"block": False}
for n, raw in enumerate(path.read_text(encoding="utf-8", errors="replace").splitlines(), 1):
code = code_of(raw, state)
if not code.strip():
continue
for word, pat in patterns.items():
hits = len(pat.findall(code))
if hits:
counts[word] += hits
lines[word].append(f"{rel}:{n}: {raw.strip()}")
return counts, lines


def read_baseline():
base = {}
if not BASELINE.is_file():
return base
for line in BASELINE.read_text().splitlines():
line = line.split("#", 1)[0].strip()
if not line:
continue
word, number = line.split()
base[word] = int(number)
return base


def write_baseline(counts):
text = ("# One number per word: its occurrences in the engine's sources\n"
"# (.github/tools/check_system_names.py). The numbers only fall.\n")
for word in LITERALS + PREDICATES:
text += f"{word} {counts[word]}\n"
BASELINE.write_text(text)


def main(argv):
counts, lines = count()
if len(argv) == 2 and argv[0] == "--list":
print("\n".join(lines.get(argv[1], [])))
return 0
if argv == ["--update"]:
write_baseline(counts)
print(f"wrote {BASELINE.relative_to(ROOT)}")
return 0
base = read_baseline()
more, fewer = [], []
for word in LITERALS + PREDICATES:
was, now = base.get(word, 0), counts[word]
if now > was:
more.append(f" {word}: {now} occurrences, the baseline is {was}")
elif now < was:
fewer.append(f" {word}: {now} occurrences, the baseline is {was}")
if more:
print("the engine's sources name a system more often than the baseline:")
print("\n".join(more))
print("A fact of a system is data: a key of its row, of the system table or of a provider\n"
"(modules/toolchain-model/data/builtin.toml, SPEC-016), read where it was branched on.\n"
"Code specific to one host lives in modules/platform/.\n"
"`check_system_names.py --list <word>` prints the counted lines.")
if fewer:
print("the engine's sources name a system less often than the baseline; record it:")
print("\n".join(fewer))
print(" python3 .github/tools/check_system_names.py --update")
return 1 if more or fewer else 0


if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
Loading
Loading