Skip to content

mcpp-language-server 0.0.15: what clangd answered before stands in while it is slow, agents are told which answers are which, a guide to laying out module projects (mcppls-clangd 0.0.16) - #57

Merged
Sunrisepeak merged 9 commits into
mainfrom
design/completion-answer-layer
Oct 13, 2026
Merged

Sunrisepeak merged 9 commits into
mainfrom
design/completion-answer-layer

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Implements .agents/docs/2026-10-13-answer-cache-layer-design.md in one PR. The engine side is Sunrisepeak/mcppls-clangd#8, released as mcppls-clangd 0.0.16 (23.1.0-mcppls.4, 35 patches, three new). This PR's CI tested its build through packaging/engine-candidate.json, and the PR now pins the released archives.

clangd stays the one source of correctness. mcppls decides what an earlier correct answer is worth now and when it is given.

What changes

  • Answer layer. Completion, hover, signature help and the jumps keep clangd's answers under three keys:

    • K1, the place;
    • K2, the receiver's type, learned with a background typeDefinition;
    • K3, the qualifier with its aliases spelled out.

    Each answer also carries a certainty: the file's visibility fingerprint, the enclosing text, other files' changes and the provider's generation. When clangd is slower than mcppls.answer.budget (450 ms) the kept answer goes out, marked isIncomplete, and clangd's own answer replaces it. Other behaviour:

    • the same place in flight is answered at once (dedup);
    • a cancelled request goes on in the background and is kept;
    • idle prefetch;
    • kept between sessions;
    • nothing is kept from a failing engine;
    • a plan whose commands changed makes everything uncertain.
  • Editor UX. Only doubted items carry a small ·. Members a changed class's text added or removed are corrected by a lexical outline. A jump is given from an earlier answer only while its target file is unchanged, or when the declaration is found there again exactly once. A nearly empty list after ./->/:: comes back by itself via cxxModules/completionReady (S3 5.9, only to a client that declares it; VS Code does).

  • Agents and CLI. provenance on cxx_symbol/cxx_references and mcppls query symbol|refs|calls (S5 2.6); fresh: true / --fresh; verify, impact and review always use clangd's own answers; mcppls.answer.agent: authoritative.

  • Engine.

    • --module-input-recheck=10: a module input check holds while no change is reported;
    • preamble declarations are loaded by Sema only in module importers, and still for imports typed since the preamble or brought in by a header;
    • --interactive-actions=2: completion and signature help get their own slots;
    • eight or twelve retained ASTs with 15 or 31 GiB of memory.
  • Settings. mcppls.answer.cache (on, memory, off), answer.budget, answer.prefetch, answer.agent, completion.provenance (subtle, off, verbose).

  • Docs.

    • a new guide, docs/25-module-projects.md (en, zh-CN): wrapper modules, each header in one place, no #include of the standard library next to import std, a minimal GMF, bodies in implementation units, no re-export chains, each with its reason;
    • specs S3 5.9 and 6.3, S5 2.6;
    • agents, troubleshooting (log lines, the report's answers) and architecture updated;
    • CHANGELOG 0.0.15.

Tests

  • Product.
    • tests/test_answer.cpp (14 cases): contexts, keys, trimming, the store, certainty, composition, outline members and declarations, provenance.
    • tests/test_answer_routing.cpp (12 cases), a real Workspace with a held engine:
      • a slow engine and R3;
      • no R3 without the capability, or after typing on;
      • cancel into background;
      • K3 across files, and dedup;
      • agent provenance (k:/ka:), answer.agent: authoritative, and fallback provenance only for mcppls's own answers;
      • hover, jump and relocation;
      • plan change leading to uncertain;
      • persistence;
      • cache off.
    • Settings forwarded by the extension; completionStillWanted.
  • Engine. CompletionLoadsModulesImportedSinceThePreamble, recheck-interval tests, InteractiveActionsDoNotQueueBehindOthers; the module-inputs canary covers E1, E2 and E4. All e2e canaries passed locally before CI.
  • Locally. 38 test programs pass, as do 129 extension unit tests, devtools check all, specs validate.py (0 failures, traceability for every new rule) and 34 of 35 conformance fixtures on Linux. The one left, mcpp-build-programs, needs an mcpp newer than the local one.

Found by this PR's CI and fixed

  • Prefetch asked clangd where no person does. On ux-xlings (typing with autosave), the idle prefetch asked for completion in namespace xlings::|xself {. clang crashed there, and the file was set aside. Prefetch now asks only inside a function's body, never on a directive or comment line, and stops for the session once clangd has restarted.

  • Kept lists were always incomplete, so VS Code asked again at every key. On ux-modules-windows U17 that was 3.58 requests per typed word against a budget of 2. Now:

    • a certain kept list that clangd gave complete, for a word the current one extends, goes out complete;
    • an answer that arrives in the background gives the word's next letters clangd's complete list (A1).

    S3-6.3-1 says exactly when.

  • The engine's E2 (UP-39) missed imports added since the preamble. It dropped Sema's preamble load when the preamble imported nothing, but a module imported since then, typed in the file or brought in by an included header, is built for that request alone. The engine canaries module_scan_memo and module_request_inputs caught it; the check now uses the draft's own module set.

  • macOS: the routing test had a namespace-scope std::string and crashed before main.

  • The kept-answer deadline ignored clangd's pace. At 450 ms a kept list sometimes went out just before clangd's complete answer (Windows U17, 3.4 requests per word). Where clangd has lately answered a file within its regular budget, the kept list now waits just past clangd's slowest recent answer.

  • --fresh still got mcppls's own fallback ("the compiler did not answer in time"), seen on Windows with mcppls query symbol --fresh. A request for the engine's own answers now waits for the engine until its own deadline (S5-2.6-2).

Measured on Windows (GalTranslPP, a temporary validation run; 0.0.14 beside this PR's build)

this PR 0.0.14
idle completion p50, by file 0.27-0.47 s, 85 of 88 right 0.53-1.00 s, 67 of 88 right
warm start: first right completion 1.8 / 2.8 / 3.8 s 104 / 174 s / never
typing: completion p50 / p95 0.39-0.45 / 0.45-0.47 s 0.73-1.30 / 0.83-1.75 s
hover p50 once prepared 0.02-0.47 s 0.47-2.00 s
cold CPU, core-seconds 3016 5462
peak memory, cold 6.2 GB 5.7 GB
crashes, dumps, failed requests none none

Answer scenarios:

  • the same place asked again: 0.00-0.03 s;
  • typed, cancelled, deleted and typed again: 0.00 s;
  • std:: asked first in another file: 0.47 s;
  • a class with a member added: the new member listed (0.17 s);
  • mcppls query symbol reports provenance.

…s are told which answers are which (mcppls-clangd 0.0.16)

Implements .agents/docs/2026-10-13-answer-cache-layer-design.md: the answer layer (keys K1-K3, certainty from the
visibility fingerprint, the enclosing text, other files' changes and the provider's generation; the answer budget,
dedup, cancelled requests going on in the background, prefetch while idle, persistence), item-level marks only, the
outline that corrects a changed class's members and relocates jumps, cxxModules/completionReady (S3 5.9), answers
given before the engine's (S3 6.3), provenance for agents and the command line with fresh / --fresh (S5 2.6),
mcppls.answer.* and mcppls.completion.provenance, the engine's module-input-recheck and interactive-actions options,
retained ASTs by memory, and a guide to laying out module projects (docs/25-module-projects.md).
…he compiler did not answer in time; a plan whose commands changed makes kept answers uncertain; the routing fixture loads its model as the workspace waits for it
…the 0.0.16 engine: module input rechecks, the preamble load only in module importers, interactive slots
…ore the platform runtime is set up on macOS)
…d the one typed now extends, goes out complete (the editor filters it, as 0.0.14 A2); an answer that came in the background gives the word's next letters the engine's complete list (A1)
…laration's head (clang crashed completing `namespace a::|b {` on ux-xlings), and stops for the session once clangd restarted
… their budget, a kept list waits just past its pace, so clangd's complete list goes out (ux-modules-windows asked 3.4 times per word)
…gent: authoritative) waits for the engine up to its own deadline -- mcppls's own fallback no longer stands in (S5-2.6-2; seen on Windows with mcppls query symbol --fresh)
…ppls.4) on every platform; the candidate engine file goes
@Sunrisepeak
Sunrisepeak merged commit 4db7e91 into main Oct 13, 2026
62 checks passed
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