Skip to content

mcpp-language-server 0.0.12: the maintained mcppls-clangd engine, mcpp formatting, crash recovery, linux-arm64 again - #46

Draft
Sunrisepeak wants to merge 17 commits into
mainfrom
release/0.0.12-joint
Draft

Sunrisepeak wants to merge 17 commits into
mainfrom
release/0.0.12-joint

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

mcpp-language-server 0.0.12 bundles the maintained engine, mcppls-clangd 0.0.12 (LLVM 23.1.0 + 25 patches for C++ modules), on linux-x64, linux-arm64, darwin-arm64 and win32-x64.

What changed

Engine and payload

  • The payload binds its engine's immutable identity (payload version 4, engine.json). Both assembly and the server verify it before trusting the engine's declared capabilities.
  • mcppls.pack.clangd takes a maintained engine part byte for byte: no strip, no thinning, no re-signing.
  • (pending the engine release) The lock switches every platform to mcppls-clangd 23.1.0-mcppls.0.

Editing

  • mcppls.format.fallbackStyle: without a project .clang-format, an mcpp project formats in the pinned mcpp style.

VS Code

  • A crash during initialize, or a failed protocol write, settles the client before a fresh one starts (WA-VSCODE-003/004).

Save planning

  • A body-only save that the plan already covers does not trigger another whole-project plan.
  • test_save_plan failed only on macOS and Windows. Root cause: the hand-built test model used the raw temporary directory, while the workspace resolves documents canonically, as a loaded model does (/var → /private/var). Reproduced on Linux with a symlinked TMPDIR (the same four assertions failed) and fixed.

Platforms

  • linux-arm64 is bundled again. It had been dropped by a scope decision, not a failure. The maintained engine for it is built at the Ubuntu 20.04 floor, so it needs glibc 2.31 instead of 2.34.
  • Intel macOS scaffolding is removed. 0.0.11 never shipped Intel macOS.
  • Compatibility changes are in the CHANGELOG: linux-x64's bundled clangd needs glibc 2.31 (was 2.18), and macOS needs 12 (was 11).

Smaller changes

  • The background-index priority default applies on macOS only, the one host with evidence for it.
  • format.fallbackStyle matches auto case-insensitively.
  • mcppls-devtools check tree keeps raw evidence and caches out of the tree.

Evidence

Raw evidence from the joint work (Part 2 performance, VS Code, crash and resource runs) is in mcpp-language-server-0.0.12-evidence.tar.zst on the evidence-0.0.12 release. The full incremental history is kept in the archive/0.0.12-joint branch. The plan and its record are in .agents/docs/2026-10-09-0.0.12-part3-convergence-plan.md.

Companion engine PR: Sunrisepeak/mcppls-clangd#2

…h recovery, save planning

The product side of the 0.0.12 joint work with mcppls-clangd, without the raw
evidence it produced (that is in the evidence-0.0.12 archive):

- a payload binds its engine's immutable identity (payload version 4,
  engine.json: version, LLVM base and commit, fork commit, patch-series digest,
  platform, binary SHA-256, features), verified at assembly and at startup; a
  maintained engine selects the kit of its LLVM base, and workarounds retire
  only for a capability the verified identity declares
- format.fallbackStyle: without a project .clang-format, an mcpp project gets
  the pinned mcpp style when the bundled engine declares it
- VS Code: a server exiting during initialize, or a failed protocol write,
  settles the client before a fresh one starts (WA-VSCODE-003/004); recovery
  shares the manual lifecycle queue and the crash budget; the log path is
  learned from stderr before a report can be interrupted
- a body save whose disk and draft module structure the plan already covers
  does not schedule another whole-project plan
- the model gateway's initialize has its own bounded deadline
- Darwin pipes to children are protected from SIGPIPE per descriptor
- CI keeps bounded timing and stability diagnostics for native runs
…taken as built, save planning holds on aliased paths

- linux-arm64 returns to the lock, the release manifest, the extension and
  every CI matrix: its removal was a scope decision with no technical failure
  behind it, and the maintained engine is built for it at the Ubuntu 20.04
  floor (glibc 2.31 instead of LLVM's own build's 2.34).
- mcppls.pack.clangd takes a maintained engine part (mcppls-clangd's
  clangd-<version>-<platform>.tar.gz, whose clangd/ holds engine.json) byte
  for byte: no strip, no thinning, no re-signing, so the identity the payload
  verifies names the bytes it ships.
- test_save_plan failed on macOS and Windows only: its hand-built model named
  files under the raw temporary directory while the workspace resolves a
  document's URI canonically, as a loaded model does (/var is /private/var,
  Windows may hand out a short name). Reproduced on Linux with a symlinked
  TMPDIR (the same four assertions), fixed by giving the fixture the
  canonical root a loaded model has.
- the default background-index priority applies on macOS only, the one host
  with evidence for it (Linux maps both priorities to SCHED_IDLE; Windows'
  background mode also lowers I/O priority, unmeasured for indexing).
- format.fallbackStyle compares `auto` case-insensitively, like `mcpp`.
- payload version 4 is a named constant shared by assembly and verification.
- Intel macOS build scaffolding goes (its cross target, the __bzero stub, the
  Neovim bootstrap, the x86_64 SIGPIPE path); 0.0.11 never shipped it.
- mcppls-devtools check tree: no tracked file above 1 MiB, none generated.
- the xlings descriptors depend on the LLVM base of a maintained engine.
- CHANGELOG 0.0.12, install floors (glibc 2.31, macOS 12), the part 3 plan
  and its record; the earlier status documents point at the evidence archive.
@Sunrisepeak
Sunrisepeak force-pushed the release/0.0.12-joint branch from 0592ccd to 39a2b23 Compare October 9, 2026 07:03
@Sunrisepeak Sunrisepeak changed the title release: 0.0.12 joint maintained clangd implementation mcpp-language-server 0.0.12: the maintained mcppls-clangd engine, mcpp formatting, crash recovery, linux-arm64 again Oct 9, 2026
… not won in a polling race

The server answers initialize within milliseconds, so finding it between its
spawn and the client's start by polling the process table was a race; under
PRoot on linux-x64 the poll lost it for a full minute. MCPPLS_SERVER, read at
every start, now names a stand-in that waits three seconds before becoming the
real server, so the test kills a process whose initialize is certainly
unanswered, and the recovery it checks is unchanged. The format fallback line
of the initialization options moves below the engine.workers comment it had
split.
…fixes retire their workarounds

Running the conformance fixtures against the maintained engine, which product
CI had never done, showed where it speaks differently from stock clangd:

- A failed prerequisite is reported per importing file, "Failed to build
  module prerequisites for <file>; due to module worker failed: <source>:...",
  naming the unit that failed rather than the module. The parser took
  "prerequisites for <file>" for a module name, so no module-failed
  diagnostic, closure containment or std kit fallback happened
  (module-faults). It now reads the importer and the failed unit, and the
  module is the one the plan gave that unit.
- An import with no unit in the project is kept textual: "Keeping import of
  third-party module <name> textual; no module unit for it in this project".
  It is an unresolved module, as stock clangd's "Don't get the module unit"
  is, so it gets its stand-in (partial-scan-standins).
- WA-CLANGD-001 and WA-CLANGD-010 retire for an engine whose verified identity
  declares module-directive-recovery and const-correctness-views, as WA-006
  already did for module-directive-diagnostic-ranges. Conformance checks take
  "retired-by": a check watching a defect the payload's engine is proved free
  of holds and says why (workaround-canaries' 001 and 010, typing-import-spin's
  T2); against any other clangd it runs.

Both log formats keep working for an external stock clangd.
packaging/payload.lock.json names mcppls-clangd v0.0.12's
clangd-23.1.0-mcppls.0-<platform>.tar.gz for linux-x64, linux-arm64,
darwin-arm64 and win32-x64 (each sha256 from two downloads and the digest the
release publishes beside the asset); the stock clangd archives no platform
names go, the kit sources stay. clangd-version and CLANGD_VERSION are
23.1.0-mcppls.0; the kit keeps the LLVM base, 23.1.0.

The engine's identity declares module-directive-recovery, so the checks that
watch WA-CLANGD-001 itself being on (typing-import T6) or its disk-side
set-aside (typing-autosave T3) are retired-by it, as the canaries are.
…nd the scenario tests read its owned cache

The first product CI run with mcppls-clangd bundled showed three more places
where the product assumed stock clangd:

- Under PRoot every process is traced call by call, and mcppls-clangd's
  supervised compiler worker is a process per module; with PROOT_NO_SECCOMP
  clangd was still preparing after 20 s. For a verified maintained engine
  under a detected sandbox the server passes
  --modules-builder-worker-policy=in-process (with the owned cache's payload
  bounds off, which need a worker), the upstream way.
- mcppls-clangd's owned cache publishes every module file as
  .owned-payload-v1/generation-<slot>-<n>/payload.pcm. The scenario tests took
  a module file's unit from its directory and its module from its file name,
  so a warm start that reused all 111 xlings BMIs counted 135 rebuilds, SC4
  found no std file and U11 nothing to truncate. An owned payload's unit is
  now the source its control block names, its module the one that source
  declares, and a new generation holding the bytes of a payload there was is
  a read copy, not a build.
- In a module importer that was just opened, mcppls-clangd waits for the
  file's first preamble before it answers a completion (issue #50), where
  stock clangd answers at once without imported declarations. Typing checks
  with "firstOpenSeconds" now measure that wait on its own, with its own
  budget, and hold the typing after it to the unchanged budgets: ux-xlings U5
  locally, first answer 6.1 s after opening, then p95 0.14 s (stock: 0.21 s).
… directive recovery too

typing-import-spin's T2-crash-restarted is the Windows face of the defect T2
watches on Linux and macOS (clangd 23.1 crashes there instead of spinning); an
engine that declares module-directive-recovery has neither.
…y when the engine says so again

mcppls-clangd reports "Keeping import of third-party module <name> textual; no
module unit for it in this project" both for a unit whose scan keeps failing
(partial-scan-standins, reported at every attempt) and once while its provider
index catches up with a database whose provider moved. Under PRoot the second
came 7 s after the move, past DATABASE_REREAD, and typing-import's hello.greet
got a stand-in that pushed greet.cppm out of the database and restarted clangd.
For a module the plan gives a unit, a report is now taken only when repeated
at least 2 s after the first (and the count starts again when its provider
changes); a module the plan has no unit for is taken at once, as before.
…f is not primed again

module_already_built_ found a BMI only in stock clangd's layout,
<source>-<hash>/<command>/<module>.pcm, so with mcppls-clangd bundled every
warm start primed all of a project's modules again: on four cores, xlings'
first ready took 14.1 s against stock clangd's 7.2 s, and every importer's
prerequisites queued behind the 111 prime units (completion p95 at the 1 s
budget, recovery after a kill over 25 s on CI). An owned payload's unit is the
first source path its control block names; the units the owned cache keeps
are read once per plan, as the stock listing is, and the command check from
module-builds.json is unchanged. On four cores the warm start is now ready
in 3.0 s and typing completion p95 is 0.23 s (stock clangd: 7.2 s, 0.19 s).
…o stand-ins for importers and sets no file aside for one (WA-CLANGD-013)
…, for answers, latency while typing, crashes and stalls
…ack, and a probe's syntax error outside the workspace is no project issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant