diff --git a/.agents/docs/2026-10-07-0.0.12-implementation-status.md b/.agents/docs/2026-10-07-0.0.12-implementation-status.md new file mode 100644 index 00000000..685ed473 --- /dev/null +++ b/.agents/docs/2026-10-07-0.0.12-implementation-status.md @@ -0,0 +1,914 @@ +# Joint 0.0.12 implementation status + +> **历史记录。** 0.0.12 的最终范围、决策与实施见 [Part 3](2026-10-09-0.0.12-part3-convergence-plan.md) §8。文中 `.agents/docs/2026-10-08-0.0.12-part2-evidence/`、`.agents/docs/assets/`、`tests/evidence/` 等原始证据路径位于 `mcpp-language-server-0.0.12-evidence.tar.zst`([evidence-0.0.12](https://github.com/Sunrisepeak/mcpp-language-server/releases/tag/evidence-0.0.12)),完整增量历史在 `archive/0.0.12-joint` 分支。 + +Scope: all W1–W8 and G0–G4 of the approved joint release plan. No merge or +publication. Product base: a0cd29b (0.0.11); engine candidate remains experimental. + +## Current checkpoint — 2026-10-08, published prerequisite generation repair + +Engine exports65 patches through0065, filling0063. Root65 rebuilds both changed-header consumers and passes all65 prerequisite tests782ms. Root joint7214ddce4 binary9052437d175c75b2b4f4a87fa12baef74bc9028b4ac4f527a360ae8a5408ea96 matches agent's focused artifact and passes64 prerequisite units923ms. Same original UP20 U7b source/CDB/product/scenario/affinity with fresh cache now passes: zero crashes/restarts,8 importers republish6.313s, probe clears2.306s, recovery6.481s against60s. Tracked maintained59 before control had six crashes/319.50s recovery. This is one Linux private-link replay; final native/1000-save proof remains open. Seven interactions/75% engine share do not qualify latency. + +Product7062e07 CI Intel model dev/release both pass. Remaining failures: CLion2026.2.3 test-only backend freeze watchdog assertion and Darwin-x64 cold first navigation median12.59s versus12s budget on stock locked payload. Watchdog numeric-zero test configuration passes all5 local2026.2.3 tests without suppressing assertions or changing server deadlines; native1748249 rerun is in progress. Engine c532f11 ARM64 Darwin/Windows pass; Linux lit fresh-publication checks need restored0064 log, Intel Darwin wide DAG still times out and requires diagnosis. Latest joint native run remains pending/in progress. + +Qt verified textual-prefix candidate0066 first original-command semantic/insertion controls pass, warm43–51ms/edited123–131ms; these are exploratory, not3×30 distributions.0065 records exact filesystem query spellings. UP28 records the existing header-import preamble visibility safety boundary; imported/unknown prefixes retain conservative handling. Final whole-recipe/native kits, product lock, UP13, resource bounds, full completion distributions,1000 saves, seven nightlies and RC soak remain open. Both PRs remain draft; no merge/publication. + +Native381643e Ubuntu20/Windows/ARM64 Darwin pass. Linux legacy-named lease fixture misses successful owned payload.pcm publication; corrected canary follows actual default owned layout and separately tests legacy Linux admission. Root both paths pass all6 lease/reclamation/semantic contracts. Strict completion evidence now requires actual per-request Sema and typed expected candidates; preserved identifier-only false positive fails4/4, prior genuine Sema19 control passes4/4.0066 remains private while full original-object PCH input audit is completed. Timing evidence collector builds and obtains actual cold/warm report/buildTimes/log snapshots in a real Linux stock pair; it is instrumentation proof, not native latency proof. + +## Latest checkpoint — 2026-10-08, combined61/62/64 + +The maintained59 original UP20 save replay completed and still failed:6 natural crashes/restarts,319.50s recovery (>60s), none of8 importer diagnostics republished within240s and only3.85% engine responses. All240 requests answered through recovery/fallback, which does not qualify semantic engine performance. Exact source bytes are restored. Tracked tests/evidence/up20-linux-fanout-maintained59 retains identity, measurements and parser excerpts. A same-CDB single-file check independently SIGSEGVs in AbstractTypeReader; a clean copied-CDB cache can pass, so actual cached dependency state is part of the open63 investigation. No fixed-crash claim. + +Engine exports63 patch files through0064 (0063 reserved).0061 narrowly preserves canonical GCC mapper dialect while honoring explicit Clang options;0062 derives preamble mode from actual attached leased BMIs before constructing PCH;0064 restores the established fresh-build event in owned publication. Root private eb4605693 engine06618ba735d457d29e3b9d20bf548c8918478f0b501ae851e85dca62e575d776 passes18 mangler controls plus75 related prerequisite/preamble controls, eight actual original-CDB Qt JSON qualified/member requests and all8 original-GCC insertion compilations. Original std.cc has no mapper marker and remains unchanged/unqualified; correct JSON warm~800–900ms still misses200/300ms latency goals. Ordered49–62/64 matches24 changed paths; shared46 archives remain read-only, not a final native recipe. + +Native c532f11 Ubuntu20 failure is the diamond canary waiting for the fresh owned publication log omitted0049; package and preceding semantic controls pass. Root reproduces that timeout, restores the event only after fresh successful durable publication, and strengthens the diamond with actual imported diamond_value completion. Cycle and diamond both pass. Floor CI now preserves available results even after failure. Corrected final native verdict remains pending. + +Symbol-bearing Windows UP12 proof is now extracted from the real artifact: engine86468960e2a4f237f9012b3db2383ce9dd0b5d5e156dad74a3bff3f1a84539ad at9e0e535, matching PDB GUID/age and clangdMain lookup, real NameType documentSymbol index14/kind10, exit0/readers stopped. This qualifies only that source and case, not final patches or UP13/UP20. Product7062e07 native CI is in progress; all joint final payload/resource/distribution/nightly/RC gates remain open. Both PRs remain draft, no merge/publication. + +## Historical checkpoint — 2026-10-08, combined private through0060 + +Engine c532f11 exports60 numbered patches, including0049 owned namespace logical payload admission and0059 retained implicit producer bundles. The combined private source d0e287169 rebuilt all changed/cache consumer objects and matches proper numbered49–60 application over accepted47/48 on all22 changed paths. Engine SHA46f703024e39b08e1db7f0d6ccda908ae6ca532b86ee366913a5d5e9acbb3987 is identical to the59 agent artifact. Selected64 prerequisite and completion/preamble mode units pass1100ms. Maintained MMD canary uses actual protocol4, leaves the dependency sentinel unchanged and creates no escaped dependency file. Shared46 archives remain read-only; this is not a complete native recipe or final payload. + +Real implicit stddef producer/importer completes fn_bundle in two independent processes while preserving the exact main and implicit inode/size/mtime, proving durable bundle reuse. Actual old49 protocol3 worker refuses the new request before payload creation. The retained bundle fixes lifetime but original Qt JSON remains unqualified: consumer and producer load distinct _Builtin_stddef PCM identities. Minimal compiler import/completion succeeds. Compiler dialect translation investigation and complete context/insertion distributions remain open. + +Native58 run37725013312: Windows and Ubuntu20 floor pass, verify-series passes. Both Darwin hosts fail only the large-header test's unsupported cache counters;0060 preserves every semantic/full-size/full-mtime control and asserts actual platform admission. Linux fails the SECOND warm fn_m completion after one successful response; this is retained as an actual semantic failure, not dismissed as test timing. The new private59 scan replay passes63hits/4invalidations but does not by itself establish that ordering/race fixed. Corrected c532f11 native run37758981234 is in progress. + +Windows symbol-bearing maintained run37722679744 at9e0e535 succeeds: pinned stock candidate qualification, fork build, PDB identity/debugger lookup and nonempty UP12 corpus replay all pass. This qualifies that source/corpus, not final59/future source, UP13 or all historical crashes. + +Product latest ca2785f CI run37723411216 has one failed Intel macOS dev gateway cancellation fixture: initialize exceeds the same300ms deadline before completion starts. The narrow optional initializeTimeout override keeps existing defaults and production startup budgets unchanged; the fixture forces500ms handshake, allows10s startup and keeps300ms completion plus cancel/<4s assertions. Controlled omission reproduces failure; root23cases/140assertions pass0.68s with real built mock. Native rerun pending. Earlier16241ca remains75/75green on the currently locked stock payload, not the joint engine. + +Recovered UP20 original U7b save baseline naturally crashes/restarts6 times in one session; recovery324.54s exceeds60s, all8 importer diagnostics remain, and only6.67% completion replies use the engine. Current dependency profile is GCC/libstdc++16.1 rather than byte-identical historical kits. Evidence is tracked. The maintained59 same-input replay is now running with fresh cache and matching builtin resources; no verdict yet. + +All W1–W8/G0–G4 remain the objective. Final same-source immutable platform kits/product lock, physical/global disk and parent/scanner RSS bounds, UP13/UP20 fixed-fork qualification, full completion correctness/latency distributions,1000 saves, seven qualified nightlies and native RC soak remain open. Both PRs are draft; no merge/publication. + +## Historical checkpoint — 2026-10-08, combined private through0056 + +Engine684d46c exports55 patches through0056, with0049 still reserved. +0055 uses full32-byte LLVM BLAKE3 content fingerprints after exact-fact indexing; +every input byte, current-VFS replay, command/environment/alias/error guard and +metadata admission boundary remains. Instrumented matched inputs reduce the +record+replay hashing stage from69.626ms to7.811ms; temporary timers are not +exported. Twelve focused tests pass238ms, including preserved-size/full-mtime +tail edits across buffer/chunk boundaries. Ordered0047–0056 application matches +all23 changed paths against private7ca13e82e. Shared root46 archives/source and +applied-series marker remain unchanged: this is partial-object integration, +not a clean native package or final payload. + +Combined actual executableab0cd926bdeb776c1826693f7609c609bb834f304ec041d6ba34c87f42c30215 +passes four preamble-mode LSP transitions and four Qt semantic requests with +strict UTF8/JSON trace. Single-process samples: warm62.89/63.49ms, +edited144.57ms, cold1799ms. A single sub200ms edit and candidate presence do not +close context/insertion/percentile gates. The original Qt compiler/CDB control +now passes unchanged; actual inserted completion compilation and the maintained +multi-context sampling fixture are being implemented. + +Native53 run37718071132 built Darwin arm64 successfully, then exposed a test +premise error: production intentionally admits only Linux host+target discovery, +but the new concurrent scan test demanded stores/followers on every host. +0056 retains all three real owner/follower M/N semantic cases everywhere: +Linux verifies original coordination counters, other hosts verify fresh scans +with no publication counters. No skip, deadline change or production expansion. +Windows53 compiled/tests/preamble/request-inputs passed, then failed hashing +extensionless clangd although subprocess execution found clangd.exe. The fixture +now resolves the actual executable using the shared strict resolver; all four +actual directive ranges and suffix/missing-file controls pass locally. Corrected +native heads remain pending. The53 Ubuntu20 run precedes the already-exported +Python3.8 boundary API correction; newer floor results remain required. + +Product16241ca native run37716680273 remains75/75 green. New documentation +head486c0da run37720832816 is still in progress with no observed failure at this +checkpoint. These prove the locked product payload, not the joint maintained +engine. Darwin cold21546ms recurrence remains retained.49 aggregate generation +quota/lease work has passed current local units/default LSP and matched real +parent-death cleanup controls; child prerequisite lease acquisition is still +being implemented before export. No physical allocation/RSS qualification is +claimed from payload byte accounting. + +Both PRs remain drafts; no merge/publication. Final immutable same-source kits +and product lock, complete native/floor runs, actual fixed-fork symbolized crash +replay (UP-12/13/20), physical cache/parent/scanner bounds, full completion +context/insertion distributions, seven qualified nightlies and RC soak still +gate W1–W8/G0–G4. UP-20 pinned source/build database recovery alone is not new +baseline crash or fix evidence. + +## Historical checkpoint — 2026-10-08, combined private through0054 + +Product16241ca run37716680273 is fully green:75/75 jobs pass, including native +units, installed editors, UX and release checks. This proves the current locked +product payload and repaired recovery fixture, not joint maintained-engine +release acceptance. The earlier Darwin cold21546ms recurrence remains retained; +individual subsequent passes do not establish stable cold preparation latency. +This documentation update will receive its own native CI verdict. + +Engine7f3dfc7 exports53 patches through0054, with only0049 still reserved. +Optional47 capture/output ceilings cover actual reduced/implicit/index writers +and old-worker bounded-protocol refusal;54 removes quadratic exact-recording +loops without changing canonical scanning or fresh VFS validation. Ordered +47/48/50/51/52/53/54 application matches all23 changed paths against private +sourced6ca614826. Eleven production TUs and four test TUs are rebuilt before +read-only root46 archives.134 related units pass; four real LSP mode transitions, +bounded default-worker dirty-header/relative-CDB semantics and synthetic FIFO +transport pass with normal shutdown. Strict trace parsing and four Qt semantic +requests pass. The integration sample is warm94/96ms, edited204ms; potential +compiler overlap is explicitly excluded from comparative conclusions. Quiet54 +samples are edited204–210ms;200ms/context/insertion/statistics remain open. + +The46 Ubuntu20 failure is a Python3.8 fixture API, after successful package and +same-source clang builds, request-input replay, ten DAG cases and cold completion. +Replay now uses compatible resolved relative_to checks; root/sibling/parent/ +symlink boundaries and actual local scan memo pass. Corrected-head native floor +validation remains pending. UP-12's actual native baseline crash input is enrolled +in the now nonempty Windows corpus, preserving original source/license and the +NameType semantic assertion. Fixed-fork native/symbol qualification and UP-13/ +UP-20 scenarios remain required. UP-20's original pinned176-module source and +producer2026.9.21.1 build database have been recovered locally; no new actual +baseline crash or fix is claimed from this recovery alone. + +Both PRs remain drafts with commit history preserved. Root source/archive/binary +and applied-series marker still remain verified46; private links do not stamp a +clean full recipe as complete.49 aggregate generation/lease/admission work is in +progress. Final same-source immutable kits/product lock, physical cache allocation +and parent/scanner bounds, actual crash replay, native/floor installation, complete +context/insertion statistics, seven qualified nightlies and RC soak still gate the +full W1–W8/G0–G4 release. No merge or publication. + +## Historical checkpoint — 2026-10-08, exported engine through0053 + +Engine head757a040 carries51 patches, with numbered0047 and0049 reserved +for separate worker-output and aggregate owned-cache admission work. New48 +stores the actual preamble mode;50 resolves document policy on the update +worker;51 owns delayed trace filenames;52 fixes Windows fixture JSON;53 +bounds identical scan publication coordination. Each has its own exported +patch, explanation, focused evidence and upstream drop condition. Independent +ordered application matches all eight changed48/50/51/52 paths and all three +53 paths against their committed private source. Root source/archive/binary +still remain combined46; private links are not full-recipe release artifacts. + +Final private53: nine focused units pass233ms; four Qt semantic requests pass, +strict UTF8/JSON trace valid. Matched-resource warm96–101ms, edited235ms, +cold2272ms. Coordination removes the overlapping second scan and extra +3,403,495 retained manifest bytes, with each follower performing full own-VFS +validation. It does not shorten the first scan. Edited200ms and full statistical +context/insertion gates remain open. A maintained real LSP fixture passes four +cold/header/draft mode transitions without AST barriers, normal shutdown and +unchanged disk source; all native platforms now run it in CI. + +Product16241ca excludes the previous shutdown PID when waiting for the actual +replacement client. Installed local Linux VSIX passes both initialization +recovery cases, with all initialization/cache-report assertions retained. +Native162 run37716680273 is still pending; no failures observed at39/55 jobs +completed. Prior21 run passed all eight native unit jobs after the settings fix +but exposed the Linux recovery fixture witness and another Darwin cold timeout. +The Darwin engine actually replies after21546ms, over the unchanged15000ms +stress budget; background priority's previous pass did not stabilize cold +module preparation. Exact recurrence evidence is retained separately. + +Engine46 run37714424693 passes Linux and Darwin arm64, fails Windows with +older response fixtures, and still awaits Darwin x64/Ubuntu20 verdicts. Series +verification37714424439 passes. New53 run37718071132 and series37718071128 +are queued/pending; corrected Windows head is not yet qualified. Both PRs +remain drafts. Final immutable same-source kits/product lock, actual fixed +crash corpus and symbols, aggregate owned-cache/parent/scanner bounds, floor +installation, context statistics, seven qualified nightlies and RC soak remain +required by the full W1–W8/G0–G4 plan. No merge or publication. + +## Historical checkpoint — 2026-10-08, combined patches 1–46 + +Engine exports 46 ordered patches with individual explanations, test maps and +upstream drop conditions. Combined development source 1c4fa5ed2 matches ordered +application across 74 affected paths and three overlays; executable SHA +2f91a4aa31c07c7f49b3ddbf6dfa04e1629f4d5668aa7339d8d8ab1f56f71011. +All 100 related tests pass in 535 ms. Actual default-worker LSP preserves dirty +header semantics and unchanged disk. Actual noisy-worker LSP retains semantic +ControlValue after a synthetic 8 MiB diagnostic failure, with zero FIFO disk +allocation and no residual BMI/unit. This is transport proof, not crash corpus. + +43 publishes verified optional memory-budget ownership leases and collects +marked crash-orphan cgroups while retaining live/replaced/mismatched objects. +Actual parent SIGKILL and real cgroup replacement controls pass. 44 reuses +semantic scan failures only with complete fresh bounded manifests, original +diagnostics and cancellation checks; cap8192, unchanged 32 MiB cache budget. +45 bounds Linux worker diagnostics using a FIFO and retained 64 KiB prefix. +46 moves copy orphan traversal to bounded resumable maintenance, preserving +active physical leases across aliases and keeping filesystem work off requests. + +Matched Qt flags/CDB: warm344–348 ms versus42 baseline725–730, edited742 ms +versus1302–1314, cold2556 ms. Four semantic requests pass. Warm still exceeds +200 ms; full insertion/context/statistical performance qualification remains +open. Repeated completion policy inventory is the next optimization target. +Hard stable/staging/copy disk admission design is also in progress. + +Product759deb6 defaults background indexing to background priority while +preserving explicit user settings and full indexing. Native run37709654683 +passes all five VS Code jobs, both Code OSS jobs and all four Neovim jobs; +Darwin x64 answers40/40 stress requests with max11954 ms under unchanged15000 +ms, versus the older19861 ms failure. Different hosts/runs do not prove causal +speedup. All eight unit-platform jobs fail generated settings table equality; +42eea9e fixes the registry and regenerated English/Chinese documentation. +Local test_settings passes10 cases/675 assertions. New native verdict required. + +Engine42 run37708608349 passes Linux and Darwin arm64 builds, but Ubuntu20 +runtime fails because the semantic harness lacked its same-source clang driver; +53915fa explicitly builds that driver/resource target. Windows also fails and +its exact build log is being inspected; Darwin x64 has no completed verdict yet. +Neither PR is all green. All commits remain in the two drafts, no merge or +publication. Product still locks stock23.1.0; final23.1.0-mcppls.1 artifacts, +parent/scanner RSS bounds, hard owned-cache disk limits, nonempty actual fixed +crash corpus, native worker/floor qualification, context matrix, seven qualified +nightlies and RC soak remain required by the full G0–G4/W1–W8 plan. + +## Historical checkpoint — 2026-10-08, worker default integration + +The maintained engine now exports 42 ordered patches. Root development source +777503b85 matches independent ordered application across 74 affected paths and +three overlays. All 94 related units pass (550 ms). Linux exportable module +builds use the owned supervisor by default, with a 60-second deadline and a +4096 MiB aggregate virtual-address allowance divided by actual pool concurrency. +Dirty-header semantics are explicitly enabled in the real LSP fixture: relative +CDB commands, draft header 42 versus disk 41, actual checked 2 GiB worker limits, +correct fn_m completion, unchanged disk, normal shutdown and unit cleanup pass. +A real delegated 128 MiB group also passes the same semantic case, observed +membership and normal group removal. Ten module DAG cases pass and bound actual +active workers at configured 1/2/4. Source lock/read leases survive child reap; +maintenance collection runs separately from request compilation. + +Product b50dac8 fixes a second crash-log path race exposed by run 37703379435: +successful reports redact HOME paths to ~/..., overwriting the real startup +absolute path. Report updates now accept absolute paths only. All 119 editor +units pass. Matched installed Linux VSIX control, identical available payload, +real HOME caches and successful unmodified report responses: baseline is +1 pass/1 missing-tail failure, fix is 2 pass; privacy and assertions are intact. +The earlier blocked-report proof alone did not cover this overwrite. + +Latest observed product b556056 CI has 54/56 jobs completed and four failed +editor-platform jobs, so it is not all green. Three missing-tail failures map +to the repaired HOME-path overwrite; Darwin x64 instead has an actual cold +references request at 19861 ms against the unchanged 15-second limit. That +performance failure remains open and is retained separately. Previous engine +head d49dbdd has Linux CI success; this is not native/floor qualification of +new 38-42 patch bytes. Both PRs remain drafts and all commit history is retained. + +Full G0-G4/W1-W8 scope remains active. Outstanding work includes parent/scanner +resource bounds and measured RSS, orphan cgroup lifetime after parent SIGKILL, +stable published cache growth, native worker policy, historical fixed-fork +crash qualification, statistical real-project performance, final distinct +immutable maintained-engine packages/product lock, installed four-platform +and minimum-OS acceptance, seven qualified nightlies and RC soak. New default +worker proof closes the prior API-only integration gap; it does not close these +release gates. No final package, steady promotion, merge or publication claim. + +## Historical checkpoint — 2026-10-07 18:35 UTC + +The sections below are chronological implementation evidence, not a claim that +all older open items have since closed. The joint release remains blocked. + +- Product head `8132fba` passes run `37641615697`, including native units, + editor integration, payloads and release-check performance/stability jobs. + Those jobs use the locked stock engine and do not prove joint acceptance of + the latest maintained engine. +- Engine `afd74df` passes Linux, both macOS architectures, series verification + and the Ubuntu 20.04 package gate in run `37654044049`; Windows is still + executing. A cancelled duplicate push run supplied the apparent failed + checks for that same SHA; no Windows verdict is inferred from them. +- Engine `4fc990a` replaces the reply-only lifecycle loop with all-exported-function + semantic assertions, one deadline per process including shutdown, reaped + intentional kills and mandatory semantic recovery. The first focused run + rejected early lexical `fn1`; an AST operation now precedes the clean-cycle + request. Ten Linux cycles pass on development binary SHA + `a55e539c221e27948963d028951bd7ee40ed0f125865dbf43381939ac1d7d499`, + with ten semantic clean exits and three separately recorded intentional kills. +- Both the lifecycle and corpus harness reap POSIX process groups even after + their leaders exit. Eight negative-control test groups pass, covering lexical + or wrong-symbol replies, request errors, crash/timeout, clean shutdown and + inherited-pipe cleanup. The sanitizer nightly now uploads structured reports. + Details and repeatable commands: engine `ci/lifecycle-evidence.md`. +- Engine PR CI now checks branch updates once via the PR event; main pushes + remain checked. Active expensive native builds finish before the latest + queued revision. New series verification is run `37667668339`; native build + run `37667668359` is pending behind the live Windows build above. + +Next dependency chain: finish native Windows feedback → fix any semantic/platform +failures → complete the real crash corpus and symbol identity → remaining W2/W5 +root repairs and cache/resource evidence → immutable maintained-engine/product +package integration → four-platform final installation and qualifying nightly/RC +soak. The semantic lifecycle smoke supplies no real crash-corpus, 1000-save, +two-hour load, RSS/cache budget or minimum-OS installed-editor verdict. Patches +remain experimental; no `steady` promotion, merge or publication is claimed. + +## Current evidence + +- Engine draft: https://github.com/Sunrisepeak/mcppls-clangd/pull/2 +- Tracking issue: https://github.com/Sunrisepeak/mcpp-language-server/issues/45 +- G0 implementation rejects release packaging with nonsteady patches or + nonexistent executable tests. Current enabled patches correctly fail release + eligibility; this is not a candidate ready for release. +- Crash corpus replay executes asserted LSP sequences and records binary SHA, + clean exit/crash/timeout/error outcomes. Empty corpus fails. Debugger absence + now fails the Windows evidence job. Symbol/PDB identity is still unverified. +- A/B product completion requires module symbols, probe subprocess failure + fails evidence, and missing latency metrics cannot vacuously pass. +- Fast Linux negative controls: 3 test groups passed, including wrong semantic + response, crash and timeout. These prove gate behavior only. + +## Outstanding work + +G0 is incomplete: collect raw hangs and nonempty real crash inputs; the C7 +draft-overlay validation defect is now repaired with focused evidence. G1–G4 remain open, including semantic/root-cause repairs, +optimization budgets, formatting/extensions, final immutable artifact/kit wiring, +four-platform packages and installation, real project/provider verification, +qualifying nightly history and RC soak. Existing historical measurements are +reference evidence, not acceptance of new candidate bytes. + +Keep routine testing below one third of implementation effort. Use focused +reproductions to decide fixes, then one combined verification per stable batch. + +## Implementation batch 2 + +- Product draft: https://github.com/Sunrisepeak/mcpp-language-server/pull/46 +- Version tool advanced the product and editor versions to 0.0.12. Local Linux + dev build passed both on the 0.0.11 base and after that version update. +- Engine 0008 isolates index-only completion behind an explicit experimental + flag. Member/prefix/pointer assertions pass with the semantic default; the + original experimental bytes fail all three. This is correctness containment, + not proof of the W1 performance target. +- Engine 0009 stores native nanosecond timestamps and file identity rather than + second-truncated mtime. Synchronous same-size/same-second exported-member + replacement passes. Asynchronous replay still exposes a generation/preamble + race, also seen with vanilla; it remains blocking and is selectable with + `completion_quality.py --async-scheduling`. +- Patched LLVM caches now include series/overlay content and apply.sh rejects a + stale marker instead of silently skipping a changed series. +- Local carried range/tidy lit: 2 passed. Semantic LSP smoke completion, hover, + current-version diagnostics and symbol-checked latency passed. Tiny-project + timings are not real-project performance acceptance. +- Product inferred fixture against the semantic-default engine before 0009: + C7 failed after 181.8 seconds, other checks passed (186.1 seconds total). + Log: `/tmp/joint-inferred-semantic.log`. This disproves that disabling 0006 + alone fixes C7. Debugger attach was unavailable under the current ptrace + policy; no machine security policy was changed. +- Engine PR CI discovered 0007 omitted WindowsCrashDumps.h from its patch; + 0010 now carries the header. Prior local builds had an untracked copy and + therefore did not prove clean buildability. New CI is required to verify it. + +Next: isolate 0002's validation/published-copy changes from C7 using bounded +replay, then repair asynchronous dependency generations and raw hang/crash +roots. Do not declare Linux fully validated or PR mergeable yet. Full W1–W8, +four-platform package acceptance, steady history and RC evidence remain open. + + +## Implementation batch 3 + +- Engine 0011 fixes the C7 root: validation memo hits now compare input identity + against the request VFS as well as disk. Draft overlays cannot reuse a disk-only + memo when file size/time happen to match. A negative-control probe accepts the + stale overlay before the patch and rejects it after the patch while retaining + valid disk memo reuse. Two focused cache lit tests pass. +- Product inferred fixture with the repaired engine passes C7 in 2.5 seconds + and the complete fixture in 6.9 seconds, zero failures. Evidence: + `/tmp/joint-inferred-vfs.log` and engine + `tests/evidence/draft-validation-memo.json`. This does not close asynchronous + preamble-generation races or real-project completion performance. +- Engine build stamping and packaging bind source commits, patch digest, + configuration, platform and actual binary SHA. Packaged capability claims + require a canary on the final stripped bytes. LLVM and runtime licenses are + included; SHA256SUMS excludes itself. Experimental local package checksum + verification passes, but its home-directory loader prevents promotion. +- Product payload manifest version 4 preserves immutable identity and validates + it during assembly, verification and runtime resolution. Missing/forged + metadata fails; explicit external engines do not inherit bundled identity. + LLVM base-version kit matching remains independent of the full fork version. + Focused identity, assembly and runtime tests pass; specification validation, + VS Code compilation and devtools checks pass. Legacy manifests remain accepted. +- A real Ubuntu 20.04 rootfs is pinned by SHA and used for the Linux floor build. + GCC 9 hit an internal compiler error; after that terminal failure the recipe + switched to Ubuntu's Clang 12. Its compiler-cache reset required one restart + after a second terminal failure. The current container + `mcppls-joint-linux-floor-clang12` is building, tracked by session 93919 and + `/tmp/joint-linux-floor-clang12-reconfigure.log`. No successful portability + verdict exists until packaging, ABI checks and semantic replay finish. + +Next: finish the active Linux floor build and inspect final bytes; complete +four-platform product wiring and remaining W1–W8 repairs/evidence. Draft PRs +remain experimental. Neither merge nor publication is authorized. + + +## Platform wiring + +Intel macOS is now present in the product lock, release platform manifest, +VS Code target list, native dev/release unit jobs, Linux cross-build, payload, +conformance, editor and installation matrices. CI uses the explicit Intel +`macos-15-intel` runner. The server deployment target is 12.0. The platform +invariant check and YAML parsing pass. These are wiring checks; actual native +CI and minimum-OS acceptance are pending. Existing Linux arm64 wiring is +preserved, without adding it to the four-platform acceptance promise. + + +## Linux floor and formatting implementation + +- The real Ubuntu 20.04 engine package succeeds after fixing Python 3.8 + compatibility in identity generation. Final SHA: + `f34f13810f62f000c5448aa2ae68e33df3442a4f84e22819ab78e73b64c03ccd`. + It starts on glibc 2.31, uses `/lib64/ld-linux-x86-64.so.2`, requires at most + GLIBC 2.29, and has no dynamic GLIBCXX dependency. Draft-overlay semantic + completion passes on these exact bytes. Engine evidence: + `tests/evidence/linux-glibc231-engine.json`. This proves an engine part, not + the full installed server/VSIX or a later rebuilt candidate. +- Engine 0012 registers the pinned mcpp C++ style. Clang 23 golden output is + identical for the preset and snapshot; project/user overrides and raw LSP + formatting pass (2 focused lit tests). Packaging requires a formatting canary + before declaring `format-style-mcpp`. +- Product format.fallbackStyle selects this capability only from verified + payload metadata. `auto` scopes it to roots with mcpp.toml; other projects + opt in explicitly. External engines receive no automatic unknown preset, + extra user arguments retain priority, and no project configuration is written. + Focused server/settings tests, docs registry, extension compilation and + repository checks pass. Editor golden cases and full candidate acceptance + remain open. +- Intel PR CI found missing published xlings/mcpp bootstrap and a compiler + generated __bzero import. An explicit LLVM target override plus a distinct + libSystem import stub produces real Intel Mach-O executables locally. The + focused instance test cross-compiles. CI now builds both unit profiles on + Linux and executes their binaries on the Intel runner; payload/core fixtures + use cross-built tools. Native execution is pending. Real mcpp producer tests + on Intel need a usable native build-tool bootstrap and remain open. + + +## Asynchronous dependency repair and portability gate + +- Engine 0013 closes the reproduced asynchronous stale-export completion: + completion/signature-help ParseInputs now carry the module builder; semantic + completion validates old prerequisite modules against the request VFS and + rebuilds invalid dependencies before parsing. It bypasses the stale preamble + and stat cache only for that invalidation. The old sequence misses freshItem; + the repaired sequence passes draft and equal-size/same-second disk edits, + member/prefix/pointer assertions included. Raw requests, replies and SHA are + in engine tests/evidence/asynchronous-module-completion.json. New imports, + provider/CDB changes, DAG parallelism and real-project budgets remain open. +- PR engine CI now covers all four promised platforms by default. Linux PR and + release packaging use a shared action that imports the SHA-pinned Ubuntu + 20.04 rootfs, executes the real recipe, checks final ELF/runtime identities + and runs the asynchronous draft probe. Experimental package artifacts can be + inspected in PR CI; release eligibility still rejects nonsteady patches. +- The final Linux engine after 0012/0013 completed successfully. SHA: + `d657c56cd752c4203bfe0525e478bff6aaa7d061dca0163ed2c4844b94f63dfe`. + Its glibc 2.31 runtime, system loader, final-byte formatting and asynchronous + draft checks pass; evidence is engine + tests/evidence/linux-glibc231-format-async-engine.json. +- The explicit maintained engine override accepts a verified full fork identity + against the lock's LLVM base, then preserves the full version in payload v4. + Wrong-base assembly fails. Focused pack tests pass (14 cases, 49 assertions). +- These exact engine bytes and a release server now pass the inferred fixture + inside the original minimal Ubuntu 20.04 rootfs with no network, mcpp or + compiler. Both server instances share the same container namespace; owner + contention passes. The full fixture is 7.3s and C7 2.5s. The container has no + server/clangd processes after teardown. Raw reports and byte identities are + in .agents/docs/2026-10-07-0.0.12-evidence/. This is userspace floor evidence, + not an old-kernel or installed-VSIX claim. Local candidate metadata was dirty. +- Three nonempty raw-LSP formatting fixtures pass complete golden equality: + maintained auto preset/project override, user override/project override, + and external-engine capability isolation. S4-4-11 traces these assertions. + Stock-engine CI includes the explicit-style fixture. A focused installed + VSIX scenario now covers preset, user and project formatting independently + and hashes each untouched workspace. All three installed-VSIX runs pass + on Linux in VS Code 1.132.0 (about 5.5s per assertion); evidence is + installed-vsix-formatting.json. Fresh extension directories were used, + without changing the user installation. Clean-machine editor and other + platforms remain pending. + + +## Compiler extension semantics and native Intel feedback + +- Engine patch 0014 adds semantic attribute introducer/SEH patterns, dedicated + cleanup function-reference insertion and exclusion of unmatched SEH-like + index macros. Ten raw semantic cases pass, including Linux/Windows target, + extension mode, declaration/expression, ordinary names, comments and strings. + Four actual returned edits compile after filling snippet fields; wrong-shape + cleanup functions are excluded. Minimal Windows SEH compiles for that target + and is rejected on Linux for the specific target reason. Engine evidence is + tests/evidence/compiler-extensions.json. These are Linux-host semantic cases; + native Windows and the new final Ubuntu floor bytes remain pending. +- Actual native Intel CI exposes SIGPIPE on blocked-peer teardown in both dev + and release test_process binaries. UP-O1 is registered in #24. The proposed + WA-PLATFORM-001 sets Darwin F_SETNOSIGPIPE on each owned child-input pipe and + rejects creation if protection cannot be installed. It changes no global + signal disposition. Linux process canaries pass (2 binaries, main 23 cases / + 86 assertions); Intel and arm64 cross-compile both process test binaries. + Native fixed-byte validation remains pending. Evidence/removal condition: + .agents/docs/2026-10-07-darwin-pipe-write.md. + +## Follow-up native and root-cause evidence + +- Intel macOS dev CI at 1fa6975 passes both process binaries, including the + blocked-peer teardown and closed-peer write: main 23 cases / 80 assertions. + Run 37553665184, job 112577351043. The remaining Intel failure is a pack + test fixture omitting darwin-x64, now corrected; focused Linux pack tests + pass 10 cases / 50 assertions. Release native validation remains pending. +- Compiler extension evidence now contains eleven semantic cases and visible + Linux __try macro preservation. Final Ubuntu 20.04 packaged engine 0014 + SHA aadcbc3839779d3751d9396a594f135170a2ff1d3830552056f8ad90f0be94b9 + passes the preceding ten-case probe and asynchronous module draft checks. + The eleventh macro case was verified on local unstripped bytes only. +- Engine 0015 repairs UP-01 at TokenCollector: logical tok::eod has no spelled + C++ token and must not enter token mapping. Plain clang parsing terminates; + raw pre-fix clangd hangs. Six raw malformed directives now reply, recover + after didChange, reopen and shut down; two before-fix controls time out. + Raw lit passes; syntax unit regression is added but not run. Native CI, + final packaged bytes, cancellation and missing-module hangs remain open. + WA-CLANGD-001 stays enabled. + +## Final Linux cancellation package and current CI + +- Engine patch 0016 gives the active preamble build a cancellation context and + checks cancellation between one-second module-lock waits. Document close + releases its wait without removing another process's live lock. Raw before/ + after proof: old binary times out after shutdown reply; candidate exits + normally, returns cancellation -32800 and serves a healthy second document. +- Final stripped Ubuntu 20.04 package SHA + 0d78a51df2a5a2dd0bf4588e86286a8b5f69928b04135e55aec29e3db2102f82 + passes the portable lock-close probe offline. Identity, raw replies and + portability proof are in engine tests/evidence/linux-glibc231-module-cancellation-engine.json. + Native platform and final installed VSIX validation remain open. +- Final patch 0015 Linux package separately passes six directive-recovery and + eleven compiler-extension scenarios; preceding local-only limits above are + superseded for that package. Those reports do not prove the newer 0016 bytes. +- Product run 37555378617 has passed all native unit jobs, Intel dev/release + execution and payload jobs. Neovim darwin-x64 fails before tests because + xlings v2026.8.17.2 installer rejects macosx-x86_64; other integration jobs + remain live/queued. This bootstrap failure requires implementation, not a + skipped platform acceptance claim. Engine run 37552196278 remains live. + +## Third-party imports and the real project latency fix + +- The real project stage trace (engine 0018) attributed qt-demo `std::ve` + latency to two stages: ~297 ms dependency validation and ~854 ms semantic + execution. Both traced to prerequisite handling, not Sema itself. Engine + 0019 repairs them: a direct import whose module unit the project cannot + supply (the toolchain std, a registry wrapper without a compile command) + no longer discards the resolvable modules' BMIs behind + FailedPrerequisiteModules, and a file whose imports are all textual keeps + its preamble because it never loads a named-module BMI (the upstream + SkipPreambleBuild guard exists for PCH+BMI mixing, which cannot arise + there). The skip verdict is cached per on-disk file identity plus + import-name set and is cleared by compile-command changes. +- Warm qt-demo completion on the local engine moved from ~1.3 s to a ~50 ms + steady state (first request ~0.4 s: the c++23 stdlib index and the initial + verdict derivation). `cli.`, `window.` member and `std::string` + qualified-name contexts return expected symbols at the same steady state. + This is exploratory single-machine evidence; the plan's three-start, + 30-round, full-matrix acceptance with baseline speedup remains open. +- Behavioral evidence: engine tests/e2e/third_party_import.py (reuse + semantics, fat-preamble retention, safe flip to trivial preamble when a + buildable import appears) and tests/evidence/*.json. Module regressions + (cycle, lock close, directive recovery, compiler extensions, completion + quality member/unsaved/async) pass on the fixed local binary. +- Engine 0007's Windows crash dump writer passed an int where MSVC's + permissive mode requires the MINIDUMP_TYPE enumeration (C2664); Linux hosts + never compiled that file. The cast is fixed and the series re-verified + locally with git am. The Windows CI verdict for the new series is pending. + +## Command-generation invalidation and CI repairs + +- Engine 0020 closes the provider-gain gap the 0019 work exposed: an empty + prerequisite set (all imports resolved textual) stayed reusable forever, so + a provider appearing through a compile-command change never reached files + that had already resolved to nothing. Reusable sets now carry the builder's + command-change generation and canReuse rejects a stale one before BMI + freshness. The provider-gain scenario in tests/e2e/third_party_import.py + drives this in one process across the directory CDB's five-second + revalidation interval: dep2 is forbidden in completion without a command, + then completes semantically after the database gains its entry. +- Product CI: the clangd review assets and the Intel Neovim bootstrap script + are now in tools/devtools/scripts.allow with reasons (both were caught by + the repo's own scripts allowlist check on every platform). +- The VS Code darwin-x64 stress suite failed once with 40/41 answered and a + single 15011 ms request against a 15 s budget on the Intel macOS runner, + with no code change in between; it is being watched for recurrence before + any budget discussion, per the plan's no-silent-threshold-relaxation rule. + +## CI repair chain and the product green run + +- Product CI is green on 062b23e (run 37619981285): every job passed, + including Neovim darwin-x64 on the pinned native binaries, Intel unit + execution, conformance darwin-x64, the ux suites and the release-checks + stability matrix with the cross-tools darwin-x64 split. +- The repairs behind it: two tracked scripts joined the devtools allowlist + (the review probe and the Intel Neovim bootstrap); the Intel macOS + stability job now follows the conformance cross-tools split (no native + mcpp exists there yet — the pinned xlings publishes no macosx-x86_64 — + so it repeats the three mcpp-free project shapes and the mcppls-shaped + fixtures keep full coverage on the other four platforms); and the + clangd-crash-context stand-in keeps a wall-clock-calibrated busy loop for + its 25-second window because the engine stuck watch samples the wrapper's + own CPU and an idle shell around a busy clangd read as a dead engine on + the slowest Intel runners (the warmup hover alone answered in 10.1 s on + the previously fatal run). The product watchdog itself is unchanged. +- typing-autosave T4/T5 failed once on the same runner class (a new import + rebuild exceeded the 5 s typing budget with the stock engine) and passed + on the rerun and every earlier run today; the durable fix is the + maintained engine's import path, in flight as engine patches 0019/0020. +- Engine CI on 1c77688: linux-x64, darwin-x64, darwin-arm64 and the Ubuntu + 20.04 floor package job all passed; win32 linked clangd.exe for the first + time (the crash-dump writer now links dbghelp through a pragma in the + Windows-only source) and the remaining gap was the lit runner path + (llvm-lit.cmd vs the shell wrapper), fixed on e11dc47 and rebuilding. + + +## Initialization recovery, semantic const fixes, and BMI reader leases + +- The earlier product green run is historical evidence, not a current stability + verdict: both runs 37641615697 and 37658653689 on 8132fba ultimately failed. + The latter exposed initialization crash recovery (duplicate command + registration and missed crash-loop notification), macOS extension-host + SIGPIPE diagnostic, a stress reference timeout and typing-import documentSymbol + timeout. A timeline audit confirms the extension host kept running after + SIGPIPE and exited normally after the failed test; this is not a proven host + crash. Budgets were not increased; native recovery and latency verdicts remain open. +- Product a51db39 makes recovery wait for the old initialization to settle and + creates a fresh language client through the host lifecycle queue. A Linux + SIGKILL-during-initialization counterexample fails against the old client + (two failing cases and four unhandled rejections) and passes both cases with + the fix, including restored commands/cache requests and the crash budget. + All 115 client unit tests pass. See 2026-10-08-client-crash-recovery.md. +- Maintained-engine patches 0021/0022 replace the operator-pipe blanket + suppression with semantic const range/overload probes, and protect BMI read + copies with kernel-owned sidecar leases. The const fixture keeps legitimate + warnings, removes invalid filtered/transformed-range fixes, and compiles + after applying all fixes. Four focused lit fixtures pass. The lease negative + control catches published BMI deletion/rebuild; the fixed engine preserves + published identity and aged live copies, and collects SIGKILL-orphaned + copies without deleting another live reader's files. Existing completion + quality scenarios also pass on the combined development binary. +- All 22 engine patches apply to a clean affected-file extraction of the + pinned source snapshot; all 45 patched paths and the overlay match the local + tested source. This proves series applicability, not immutable package or + cross-platform release identity. Reports and limitations live in engine + ci/const-correctness.md, ci/module-read-leases.md and tests/evidence/. +- Windows' same-second replay now changes mtime by a representable millisecond + and checks that the actual timestamp differs while remaining in the same + second. Its negative control simulates FILETIME rounding. This repairs an + invalid test premise; it does not prove arbitrary preserved-mtime edits. + Native Windows CI remains required. The Windows build now uses sccache; + actual cache hits and build time remain unmeasured. +- Engine HEAD 7ac5e7c contains the four new commits with retained history. + Product code-head CI 37670388519 is still running. Final maintained-engine + packaging/lock update, all native/floor installed-editor gates, real crash + corpus/symbol identity, qualifying nightlies and the RC soak remain open. + + +## Crash-investigation inputs and linked Windows symbols + +- Engine CI tooling now enables a symbol-bearing Release link, verifies + the executable/PDB GUID and age plus debug/public streams, and requires a CDB + lookup resolving clangdMain. It carries the exact pair, hashes, raw outputs + and engine-build identity; an empty symbols artifact no longer passes. + Two actual cross-linked tiny Windows binaries/PDBs validate matching and + mismatch rejection on Linux. Native clangd/PDB/CDB evidence remains pending. +- UP-12's original public GalTranslPP CI artifact and pinned GPPDefines.ixx were + recovered with the source license, original command and crash exit record. + A normalized replay retains the Windows target/LTO/unresolved imports and + requires the original enum with semantic kind. It passes on local Linux; + this does not reproduce the native crash. The Windows investigation job + first checks this candidate against the SHA-pinned historical engine and + rejects a successful baseline as ineligible. Inputs stay in candidates, + separate from the still-empty qualified release corpus. UP-13/20 reduction + and symbolized crash stacks remain open. + + +## Bounded DAG scheduling and explicit missing-BMI lexer recovery + +- Engine a282699 exports independent patch 0023. The prerequisite forest is + planned once, cycles checked before dispatch, and ready jobs share one + builder-owned pool. Default concurrency is two, capped at four and physical + cores. Ten local shapes cover diamond/order/dedup, failed siblings and + recovery, prebuilt dependencies, textual imports and concurrent importers. + Affinity probes verify physical-core caps. Exploratory cold time moved from + 831 ms to 485 ms at the default; this is not a statistical release gate. + Provider-table/scan reuse and hard RSS byte admission remain open. +- Restoring the original six explicit absent-BMI hints exposed a real Linux + hang in both pre-0023 and with-0023 engines. Live gdb stacks locate it in + TokenCollector, independently of the new build pool. After a missing named + BMI, the sticky fatal-loader flag let later import keywords appear once as + the original token and again from their queued directive stream. The token + mapper spun on the duplicate source position in the measured Release build. +- Engine 4f47215 exports independent patch 0024 (source commit 51506a1b7), + consuming the original keyword whenever a module directive was queued. + The exact explicit-hint candidate now returns NameType with enum kind in + 17.53 ms and exits normally. A minimal lit negative control times out before + the fix; the fixed marker/edit recovery passes. Both new lit fixtures and + the native-path DAG replay are included in engine CI. Raw evidence and + upstream/drop explanations accompany the two numbered patches. +- The Windows symbol build first failed C1041 with shared /Zi compiler PDBs + under sccache, even with /FS. cf9f7c0 uses CMake Embedded (/Z7) object debug + information and explicit /DEBUG /OPT:REF /OPT:ICF linking, retaining Release + optimization. Native identity/CDB lookup is pending on the corrected recipe. +- Earlier normalized Windows candidates passed the pinned original engine: + first the overlay CDB omitted producer information, then the disk-CDB case + omitted explicit BMI hints. Those runs are ineligible; the refined original + hints now need native baseline reproduction. Linux hang repair does not + establish the historical Windows exception's stack or close UP-12 globally. + + +## Provider generation reuse and native historical baseline qualification + +- Engine df6b0b9 adds separate patch 0025: a lazy immutable command inventory + shared by CDB generation, with provider-index reuse only for exact adjusted + command equality. Six focused unit groups cover configuration changes, raw + response files, CDB reload with an old live facade and source-name changes. + Three raw importer documents over 132 commands pass semantic completion and + clean shutdown: one inventory build, six provider-index hits. Per-facade + command copying, mangling and comparison remain O(N); scan reuse, admission + and latency/RSS release thresholds are still open. +- All 25 patches cleanly apply to the pinned snapshot's affected files. All + 57 patched/overlay paths match the tested source exactly. A full native + Ubuntu 20.04 recipe rebuild is running locally, including focused lit; this + is not yet a finished immutable-package verdict. +- Native Windows run 37684762425 reproduced the original UP-12 exception + 0x80000003 on historical binary dbd52c13d21ef9d284f4f0627efe76c81adf2fe0998f230127f554a54fc9dde7. + Replay initially raced stdout EOF against process termination. Engine + 58ec3b2 waits within the existing deadline for natural exit, preserving + clean-early-EOF failures and excluding cleanup kills from crash evidence. + Delayed exit9/exit0 controls pass; CI verification on c32edf1 is green. +- Corrected native run 37685946237 now qualifies the historical crash and + retains actual exit, raw initialization and stopped-reader evidence in + engine tests/evidence/up12-native-qualified-baseline.json. The maintained + native fork build is running. Symbolized stacks and native fixed-engine + semantic recovery remain pending; the full qualified release corpus is + still incomplete, so this does not close UP-12/13/20 or release readiness. +- Linux native CI stayed in package installation for over two hours. c32edf1 + bounds apt connection/lock waits and the tool-install step for future runs. + Existing live builds are preserved; no passing result is inferred from a + queue or installation timeout. Product 013bd78 CI 37684792316 has no failed + completed jobs at this observation, while editor/native gates remain live. + + +## Request scan ownership, directive capability, and current native failures + +- Engine a166b22 exports patch 0026: every module scan/build/reuse check receives + exact captured request contents and the supplied filesystem. The disk-stat-only + buildability memo is removed pending verified-input reuse. The raw M → no import + → N sequence passes with unchanged disk contents; supplied overlays and a + conflicting global draft are covered by units. +- Extending the DAG regression found a real natural SIGSEGV before worker + dispatch: the dependency scanner retained borrowed InMemoryFileSystem buffers + after their temporary view was destroyed. Request-owned immutable bytes now + outlive scanner services and drained jobs. The exact diamond request passes + after repair; all ten DAG shapes pass, including failure recovery, prebuilt + dependencies and concurrent importers. The fixture now saves failure replies + and natural exits before assertions. This fix is included in patch 0026. +- Engine 7ad0fd4 exports patch 0027 for UP-15. Diagnostic fallback no longer + skips whitespace from a line-end insertion, and preprocessing diagnoses a + missing module separator at the original directive. Four raw ordinary/physical + continuation cases fail on the immutable 25-patch package and pass after the + fix; full DiagnosticsTest and related module/provider units total 30 passes. + The compiler verify fixture also passes. All 62 patch/overlay paths for the + 27-patch candidate match independently applied source bytes. +- Engine 61b9f6c makes final-package capability declaration depend on the actual + raw directive canary. The stripped Linux development package SHA + 24244428d0ebf0c14a218487bbe88bbddeaaf8e5973172f45d57fccb08d84a44 + passes all three declared capabilities, including module-directive-diagnostic-ranges. + Product retirement of WA-CLANGD-006 uses only verified payload features: + identical versions without that capability, missing identities and corrupt + payloads keep compatibility. Thirteen focused workaround cases pass locally. + This development package is not the final floor/native/editor release package. +- The full local Ubuntu 20.04 25-patch recipe has now completed successfully: + 15 lit passes, runtime glibc 2.31, required maximum GLIBC 2.29, no unresolved + loader dependencies, package SHA + 14e6d1fe4e6ced3d991e0984356f53d12769b657764ccd800478766eec5d9c41. + Immutable identity and raw evidence are committed in the engine PR. Later + patches still require a new floor package. A native floor apt-install failure + is repaired with bounded update-and-install retries; no CI success is inferred. +- Historical Windows run 37688373724 now captures the actual second-chance + 0x80000003 with matching binary/PDB identity, source-resolved TokenCollector + frames (Tokens.cpp lines 750/913), and a valid retained minidump. The native + maintained-fork symbol build and fixed-input replay are still in progress; + UP-12/13/20 and qualified release corpus completion remain open. +- Product ee49d82 CI 37686772481 is terminal with failures. Build/unit, payload, + most conformance and several editor jobs pass, but eight editor/clean-machine + jobs and Darwin-x64 typing conformance fail. The common enable-switch failure + asserts client readiness before feature initialization completes: the server's + ready notification can precede client.start settlement. The switch fixture now + waits for both actual status and initialized client; two real Linux editor + cases pass with normal editor exit and unchanged workspace. Darwin additionally + exposes an unhandled destroyed-stream write; transport ownership is repaired independently by a connection-scoped writer + (WA-VSCODE-004 / UP-V2). The actual jsonrpc dependency has a discarded async + executor promise on failed request writes: matched baseline emits an unhandled + ERR_STREAM_DESTROYED, while the guard disposes pending requests normally without + a second rejection. All 117 editor unit tests and the combined four real Linux + enable-switch/crash-loop cases pass, with editor exit 0 and unchanged workspace. + No process-wide errors are suppressed. Native macOS verification and typing latency + and latest native CI are not yet accepted. +- Verified scan memoization, compiler/deadline/RSS admission, response provenance, + remaining crash reductions, distinct final immutable packages and product lock, + installed four-platform editor acceptance, statistical performance and RC soak + criteria remain required. Both PRs remain drafts; release readiness is unproven. + + +## Integrated scan reuse and latest product CI (2026-10-08) + +- Engine 855458d exports patch 0028; b396def exports patch 0029. Positive + P1689 scan reuse now replays observed successful/failed filesystem inputs, + exact bytes, directory prefixes and environment before publication and hits. + A preprocessor dependency collector rejects actual wall-clock builtin + expansions, including pasted names, while admitting ordinary token pasting, + inactive/literal builtin names and . Driver/Linux target, response + provenance, config/plugin and native CPU limitations remain explicit. +- Integrated Linux development evidence is committed as engine + tests/evidence/module-scan-memo-and-builtins.json: 32 related units pass in + 151 ms; the identical-main input replay records 79 hits and four correct + invalidations. All five raw builtin cases return real fn_m symbols and exit + normally: three positive cases have 12 hits/one store each, two actual builtin + cases have no hits/stores and 13 declines each. Independent application matches + 62 touched source paths and all three overlays. This is a development link, + not an immutable floor/four-platform release package. +- The Linux CI and Ubuntu20 final-stripped-package recipe now execute both + focused scan fixtures. Job-level native build concurrency replaces global + serialization, preserving active builds while allowing other platforms to + proceed independently. Latest engine head is pushed; new CI is not accepted + until its actual results complete. +- Product ad5763e run 37694070274 has passed all platform conformance jobs, + all platform payloads, and VS Code E2E on Linux x64, Windows and Darwin ARM. + Linux ARM VS Code fails reading cache status immediately after recovery; + Intel Darwin stress fails one references request at the 15-second deadline. + Both failures are under active repair; timeout increases are not the fix. + The run is still in progress and is not all green. +- Response-file expansion can change commands without changing the loaded + CDB generation; the provider inventory can consequently retain stale expanded + commands. A separate generation/input repair is in progress. Forced-global + freshness must honestly account for the distinct response-input inventory; + no constant-IO guarantee is assumed without a filesystem change epoch. +- Total RSS/compiler admission, deadline quiescence, qualified historical native + crash corpus, distinct immutable release packages/product lock, native editor + acceptance, statistical performance and full RC/steady criteria remain open. + The full joint 0.0.12 goal is active, and both PRs remain drafts. + +## Response generations, first completion and worker foundation (2026-10-08) + +- Engine aaadf09 preserves the full commit history and exports 36 numbered + patches. Ordered application matches all 70 touched source paths. Patch 0030 + freezes response inputs per CDB owner generation; a matched real-disk test + changes nested response bytes with unchanged CDB, size and mtime. The prior + owner mutates its command and retains a stale provider index; the repaired + generation test passes. The main flag-response raw LSP fixture passes both + baseline and candidate and is recorded only as regression coverage. +- Patch 0031 discards observed compiler-boundary cancellation before PCM + publication. Patch 0032 waits for the first module preamble and refreshes the + resolved compile command afterwards; real immediate cold completion changes + from absent fn_m on the retained 29-patch baseline to correct fn_m and normal + exit. Existing warm preamble behavior remains available. Patch 0033 repairs + the GC test to assert orphan read-copy ownership and preserve stable BMIs; + it does not solve persistent published-BMI disk growth. +- Patch 0034 supplies a captured-input internal compiler entry. Integrated + development evidence has 82 related units passing and three actual child + cases: captured main/header success with erroneous disk contents, invalid + request and captured compilation failure. Patch 0035 adds an owned child + supervisor and atomic actual-server DraftStore export, but stays unwired and + defaults to InProcess. Private Linux runs record 11 ms success, 103 ms + frontend timeout and 102 ms cancellation, with reap/temporary cleanup and an + unrelated child preserved. All affected 166 units are being rebuilt before + further integrated claims. Parent-death protection and hard memory admission + remain open; no native worker qualification is claimed. +- Windows historical run 37685946237 completed with a real compilation failure + from min/max macros in module DAG calls. Patch 0036 avoids their expansion; + the failed run is not fixed-fork crash qualification. Stock native crash + evidence remains retained. Native rebuilding/replay remains required. +- Engine Linux run 37701681572 returns all requested symbols and normal exit in + module_request_inputs, then logs cancellation of a concurrent AST during + shutdown. Its old harness rejected that expected cancellation. The harness + now accepts only the explicit cancellation outcome while rejecting other + prerequisite failures; real local request-input replay passes unchanged disk. +- Product 3ecd56a run 37698414113 has POSIX editor failures at missing + server-log-tail.txt after the third forced crash. Linux and Darwin logs agree; + initialization recovery passes. The real server log files exist in retained + artifacts. Log-path discovery currently depends on an asynchronous report + that rapid crash/restart interrupts; a startup-announcement repair is being + verified. The prior workflow runner-context validation error was separately + fixed, and no cancelled or partial CI run is counted as all green. +- Both PRs remain drafts. Full native CI, historical fixed-fork corpus, final + immutable packages/product lock, default worker resource guarantees, + statistical performance and RC/steady qualification remain release blockers. + +### POSIX editor crash-log repair integrated + +Product 02a1c76 records the actual info-level startup log announcement from the +current client before initialize/report can finish, and ignores late reports +from replaced clients. Root TypeScript compile and all 118 editor units pass. +Matched real Linux E2E uses identical server SHA +9d5cea9a2ec7a611584eadc4363eb0e412f959073d152fe54b59547421577e2d, +Code 1.132 and debug logging: a private transparent proxy withholds only +cxxModules/report. Baseline 3ecd56a fails the unchanged missing-tail assertion; +the repaired extension passes both crash tests and records the actual latest +server log. The normal unproxied repair also passes both tests. No optional-log +contract or crash assertion is weakened. Private retained proof is +/tmp/mcpp-crash-log-review/README.md and identity.json; this is source extension +Linux evidence, not final installed native VSIX acceptance. Latest native CI +must still complete before claiming the platforms repaired. + +Root integration additionally passes the two real Linux crash-loop cases in +5 seconds with normal editor exit and unchanged workspace. The E2E runner now +copies editor logs and extension-global crash reports into the upload directory +in finally, retaining short macOS socket paths. Actual report files including +server-log-tail.txt/info.json are present under /tmp/mcppls-root-crash-evidence. +A controlled one-action 1 ms stress bound fails as intended and still retains +editor logs under /tmp/mcppls-root-failed-editor-evidence, proving the rejection +path preserves evidence. This shortened bound is private verification only; +CI request deadlines remain unchanged. diff --git a/.agents/docs/2026-10-07-0.0.12-joint-release-plan.md b/.agents/docs/2026-10-07-0.0.12-joint-release-plan.md new file mode 100644 index 00000000..5dd13f0f --- /dev/null +++ b/.agents/docs/2026-10-07-0.0.12-joint-release-plan.md @@ -0,0 +1,228 @@ +# mcppls 0.0.12 + mcppls-clangd Joint Release Plan + +> **历史记录。** 0.0.12 的最终范围、决策与实施见 [Part 3](2026-10-09-0.0.12-part3-convergence-plan.md) §8。文中 `.agents/docs/2026-10-08-0.0.12-part2-evidence/`、`.agents/docs/assets/`、`tests/evidence/` 等原始证据路径位于 `mcpp-language-server-0.0.12-evidence.tar.zst`([evidence-0.0.12](https://github.com/Sunrisepeak/mcpp-language-server/releases/tag/evidence-0.0.12)),完整增量历史在 `archive/0.0.12-joint` 分支。 + +> **For agentic workers:** review 通过后,使用 `superpowers:executing-plans` 逐项实施;当前文档不授权发布、改生产配置或移除保护。各根因修复先提交复现与设计,再提交实现,保留独立 review 和追加 commit。 + +**Goal:** 让 mcppls 0.0.12 默认携带可追溯、语义正确、经真实项目验证且四平台可分发的维护版 clangd,而不只是将上游缺陷隐藏在产品保护或更快但错误的补全后面。 + +**Architecture:** fork 负责 Clang/clangd 内部的语义、模块构建、锁、生命周期和性能;mcppls 负责项目/编译器画像、调度、缓存失效、故障隔离和统一分发。两仓以不可变引擎身份、能力声明及同一组缺陷复现协议联动;发布依据是候选二进制和产品安装包的联合验收,而非 patch 数或绿色 build。 + +**Tech Stack:** C++23 modules、LLVM/Clang 23.1.0 基线、Python LSP replay、CMake/Ninja/lit、GitHub Actions、VS Code extension host、mcppls payload/VSIX/xlings。 + +**Spec:** [既有缺陷覆盖与本地实测](2026-10-07-maintained-clangd-0.0.12-plan.md),[#24](https://github.com/Sunrisepeak/mcpp-language-server/issues/24)、[#37](https://github.com/Sunrisepeak/mcpp-language-server/issues/37)、[#43](https://github.com/Sunrisepeak/mcpp-language-server/issues/43)、[#44](https://github.com/Sunrisepeak/mcpp-language-server/issues/44)。本文件取代前份方案的初步发布顺序;测量记录保持原样。 + +状态:2026-10-07,联合设计供 review,**未实施,当前 fork 不可直接发布**。以下性能数值是建议的 release 目标,不是已经达到的结果。存在未定位的根因,因此这是 release 设计与工作包,不是可跳过诊断直接执行的完整 patch 蓝图。 + +## Global Constraints + +- 产品版本目标 `0.0.12`;引擎首个合格正式版本目标 `23.1.0-mcppls.1`,当前 `23.1.0-mcppls.0` 仅实验。LLVM 基线 tag 解析为 commit SHA 后锁定。 +- 发布平台 `linux-x64`、`win32-x64`、`darwin-x64`、`darwin-arm64`;linux-arm64 本轮不承诺。四平台均需运行测试,而非交叉编译完成即可。 +- compiler-agnostic 保持:用户的 GCC/MSVC/Clang 工程不改成 LLVM 编译;clangd 的内部语义 BMI 不宣称能直接消费其他编译器的 BMI。 +- 同一源码/patch digest/构建配方生成平台产物;所有编辑器及 CLI 入口使用对应平台同一已验收引擎。显式用户 `--clangd` 配置优先,保留外部原版 clangd 支持。 +- 不以清缓存、禁模块、关闭 autosave、返回任意 lexical/global 候选作为真实修复;正确的 `-c` 编译命令、通用 watchdog/backoff/隔离/bundle 保留。 +- 不自动上传源码、日志、dump;full-memory dump 可含用户代码/凭据,必须显式 opt-in、容量限制和本地清理。 +- 只提升有证据的 ledger 状态:最小复现、对照失败、候选成功、回归测试、适用平台与包身份缺一不可。 + +## Review Focus + +1. 补全点不在文件最后一行、成员/指针成员与同名全局符号:必须保留正确作用域与插入文本(W1)。 +2. 模块导出、头文件、编译参数在请求进行中改变:不得复用旧依赖结果或发布过期响应(W2/W3)。 +3. 未保存的 import、取消/关闭和锁持有者死亡:不能挂死、误删活跃缓存或无限重启(W3/W4)。 +4. 用户自带 clangd/格式配置与编译器扩展:不能套用不支持的 fork 参数、覆盖用户配置或提示目标不支持的语法(W5/W6/W7)。 +5. 没有 xlings/开发机依赖的干净机器:包能启动;未找到 debugger、空 corpus 或缺 license 必须失败(W4/W7/W8)。 + +## 1. 联合范围与当前阻断 + +目前七个 patch 覆盖六个 UP 编号;没有 `steady`。其中 0007 是 Windows 取证,不是 crash 根因修复。实测 0006 把 `cli.` / `cli.ad` 成员补全改成全局索引候选;模块导出更新的 inferred C7 在 fork 下超时 180 s,而同一产品服务器搭配原版引擎约 2.5 s 通过。此差异尚不能归因到单一 patch。 + +| 发布工作包 | fork 主责 | mcppls 主责 | 0.0.12 验收结果 | +|---|---|---|---| +| W1 补全质量与 UP-25 | 正确语义路径、模块重复工作的优化 | 请求代际、上下文缓存、真实 provider | 成员/限定名正确,模块编辑后新符号出现;延迟有统计改善 | +| W2 模块失效与 UP-03/04/14/23/25 | BMI 验证、provider 查询、扫描和依赖调度 | 内存 draft/依赖 epoch/CDB 同步 | 同秒同大小修改、未保存导入、CDB 改变不会返回旧结果 | +| W3 挂死与 UP-01/02/06/07/10/17/21 | 锁等待、失败传播、取消和 worker 生命周期 | watchdog、重试边界、关闭与编辑序列 | 已有可复现 hang 直接 replay 不再挂;产品恢复有界 | +| W4 crash/缓存与 UP-12/13/18/19/20/24 | crash 根因、Windows 锁、copy-on-read 生命周期 | corpus 来源、隔离、目录预算、可选取证 | 非空 corpus 实际执行、无已复现 crash、无孤儿进程/无界积累 | +| W5 诊断/范围与 UP-05/09/15/22 | 保守正确的 const 检查、range 和位置 | 只按已证实能力退休特定过滤 | 真 warning 保留,view 假 warning 消失,合法 range 行为 | +| W6 #43/#44 用户功能 | mcpp fallback style 能力、编译器扩展语义 | 格式优先级/编译器画像/配置 | 配置不被覆盖,格式一致;扩展在合法目标/位置可补全 | +| W7 身份与四平台分发 | 可移植且同源的引擎产物 | kit 兼容/lock/VSIX/xlings/显式覆盖 | 干净机器真实安装使用,无 PATH 偷换或版本伪装 | +| W8 发布门槛 | steady gate、有效 bench/soak/corpus | joint release-checks、编辑器与真实项目 | 同一批验收 bytes 才进入 release candidate | + +UP-08 的跨模块声明/定义索引、UP-16 的 C++26 contracts/reflection,以及 mcpp/PRoot 本身的问题单列能力限制,不因维护版标签宣称已修复。导航不得相对原版回退;遇到可重复的新增退化同样阻断。完整 25 项状态沿用前份矩阵,每一项在 release notes 写出 fixed / mitigated / open 及证据,不使用“全面修复 clangd”表述。 + +### 路线选择 + +- **推荐:联合根因修复后切换默认引擎。** 按本文件G0–G4推进,实际解决正确性/稳定性并获得性能收益;成本最高,但符合本次“真实修复、优化、跨平台”目标。 +- **备选:0.0.12仅准备身份与分发,fork继续实验性opt-in。** 风险较低、可先交付基础设施,但不满足本轮默认启用真实优化引擎的完整目标;只有用户明确接受缩小范围后采用。 +- **不建议:当前fork直接打包默认发布。** 实测有成员语义/C7回归、raw hang与portable缺口,不具备发布依据。 + +本稿先供架构与release范围review。批准后,各工作包的诊断/复现产物决定具体函数接口与patch设计,再形成包含真实代码断言/命令的可执行实施计划;不会为尚未定位的crash提前编造修复代码。 + +## 2. 两仓边界与身份契约 + +共同身份记录如下,字段是本轮拟定契约,不代表现有 manifest 已支持: + +```json +{ + "engine-version": "23.1.0-mcppls.1", + "llvm-base-version": "23.1.0", + "llvm-commit": "", + "fork-commit": "", + "patch-series-sha256": "", + "platform": "linux-x64", + "sha256": "", + "features": ["semantic-tokens-range"] +} +``` + +尖括号表示每次构建生成并严格校验的身份值,不是允许打包的字面量。`features` 仅写经过测试并随该二进制启用的能力;新格式 fallback、crash dump 等分别测完再加。产品不得仅根据版本后缀推定能力。 + +完整 engine version 用于日志、报告、缓存分区和用户显示;kit/libc++ 兼容用 LLVM base version,resource-dir 仍依据对应 LLVM 资源目录。旧 manifest 没有新字段时保留旧解析,不凭空赋予 fork 能力;新 manifest 缺少身份或 SHA 校验失败拒绝组装。用户自带 clangd 不强行绑定 bundled kit,不传 fork-only 参数。 + +缓存契约:补全复用必须匹配 engine identity、workspace/context、compiler profile、CDB generation、document semantic context 和 module dependency epoch;导出变化必定失效。正文的兼容前缀缓存可复用,但旧 generation 的异步回复必须丢弃;`isIncomplete` 按真实语义处理。不由 mcppls 把无关全局候选过滤成“看起来像成员”来遮盖 fork 错误。 + +缺陷证据包契约:`id / platform / baseline engine sha / candidate engine sha / commands / request-edit sequence / expected symbols or diagnostics / observed outcome / raw logs / timing samples / root-cause link`。crash 追加 build-id、PDB identity/符号栈;无法定位时标记 open,不填写推测的“修复”。 + +## 3. 可单独 review 的工作包 + +每包统一顺序:先提交反例和机器可判定断言,确认原版/当前 fork 的差异;再提交根因和小型设计;最小实现后跑单包及联合回归,最后追加 commit。下列拟新增测试名是任务边界,实际 harness CLI 由相应测试提交定义,不假称当前命令已存在。 + +### W1:修正补全,然后优化语义工作量 + +**文件:** fork `patches/0006-UP-25-completion-index-fast-path.patch`、`tests/e2e/compare.py`、`tests/probes/completion_latency.py`;拟新增 `tests/e2e/completion_quality.py`。LLVM 实现落点 `llvm-project/clang-tools-extra/clangd/CodeComplete.cpp` 和模块/preamble 路径,变更通过 patch series 保存。产品 `src/orchestrator/completion.cpp`、`editors/vscode/src/completionGate.ts`、`tests/test_completion.cpp`;0.0.11 新增缓存实现以远端基线源码审计为准,不在旧本地 0.0.10 中杜撰路径。 + +**接口:** 接收身份、文档版本和依赖 epoch;产出保有语义的 CompletionList 及命中路径统计,不增加“任意回答即成功”的降级接口。 + +- [ ] 回放 `nlohmann::j`、`std::ve`、`cli.`、`cli.ad`、`ptr->`、类型限定名、空前缀、未索引模块;补全点在首/中/末行,字符串/注释/预处理行各一例。 +- [ ] 断言 `json/vector/addHelpOption/addOption` 等目标符号、成员集及插入后的可编译性;候选详情/重载/snippet 可以合理变化,不按总条数要求逐项相等。默认作用域不能无依据混入 `qVersion/Counter/AdlTester`,明确用户 all-scopes 模式另测。 +- [ ] 拆分测试 current fork、禁用 0006、禁用 0002、两者都禁用与原版;复现 inferred C7,定位 180 s 回归。修好以前关闭不安全默认 fast path 只是止损,不记为 UP-25 完成。 +- [ ] trace 分离 preamble 等待、验证、BMI 读入、Sema、index merge 和产品缓存。先消除重复验证/重复解析及无效等待,再评审结构性优化;逐步启用而非一开始扩大 index-only 路径。 +- [ ] 若考察 BMI completion summary,先证明作用域、成员继承/模板、导出与非导出可见性、失效和序列化版本;不能把依赖验证 memo 说成 AST 跨请求复用,也不能跨 ASTContext 共享 Decl 指针。 +- [ ] 运行候选质量测试及产品 inferred/typing fixtures,再运行真实 VS Code provider;依赖导出修改后旧符号消失、新符号在相应 completion 中出现。 + +**通过条件:** 所有语义断言通过,C7 不超时;同时达到第 4 节性能目标。若正确的 Sema 路径仍约 1 s,不宣布“性能修复”,回到 review 调整架构或范围,不默默降低门槛。 + +### W2:模块缓存、provider 与扫描失效 + +**文件:** fork `patches/0002-UP-25-memoize-module-file-validation-across-requests.patch`、LLVM `clang-tools-extra/clangd/ModulesBuilder.cpp`;产品 `src/project/modelcache.cpp`、`src/orchestrator/cache.cpp`,现有 `conformance/fixtures/inferred/`、`typing-import/`、`typing-autosave/`。新增回归按这些 fixture 结构建立。 + +**接口:** 输入 draft snapshots、compile-command fingerprint、依赖 generation;输出有效的模块 DAG/BMI 身份,不凭文件 size+秒级 mtime 认为等价。 + +- [ ] 固定同秒同大小替换、unsaved import、头文件内容更新、删除/重命名导出、CDB 参数变化、provider 新增/移除、菱形依赖;分别验证诊断和符号更新。 +- [ ] 0002 memo key 覆盖有效输入和配置;内存 draft 不能命中磁盘旧 cache。采用可靠 generation/高精度 stat 与必要内容指纹,跨平台证明;设计缓存容量及失效统计。 +- [ ] provider 查询按 CDB generation 建表,避免每次依赖查询遍历全 CDB(UP-04);headers/modules scan 只复用同输入结果(UP-23),编辑/参数变化后重新扫描。 +- [ ] UP-03 在 W3 失败传播/锁顺序稳定后再做 DAG 并行,明确 worker/内存上限;测试1/4核与嵌套/菱形失败依赖,无任务互相等待、没有并行风暴。 + +**通过条件:** 每次语义变更都产生正确新结果,旧依赖结果不能污染新回复;warm/no-op 明确减少验证/扫描次数,cold 不以丢依赖换速度。 + +### W3:挂死、取消与生命周期 + +**文件:** fork LLVM `clang-tools-extra/clangd/ModulesBuilder.cpp`、`TUScheduler.cpp` 及相应新增 patch/lit 测试;`tests/e2e/lsp_driver.py`。产品 `src/engine/clangd/process.cpp`、`conformance/fixtures/typing-import-spin/`、`typing-autosave/` 和 VS Code stress suite。 + +**接口:** import 构建失败向消费者传播可诊断状态;请求 cancel/didClose 终止所属工作,不使其他文档或后续 generation 不可用。 + +- [ ] 将 UP-01 `import ... .`、UP-02/10 未提供模块固化为 raw clangd replay;取消正在等待的请求,再请求正常文件,证明后续服务可用。 +- [ ] 记录锁持有者、等待依赖及 worker 状态,依据 wait graph 修复死锁/错误锁顺序,不仅把等待时长改小。 +- [ ] 连续 rapid edit、idle/reopen、didClose、autosave、shutdown;deadline 后检查 CPU、线程和子进程,不只检查有一个 LSP 回复。 +- [ ] 旧的 UP-06/07/17 无最小复现者,先收集 request sequence;有复现就加入阻断集,不以“暂时未复现”登记 fixed。 + +**通过条件:** 已固化的 raw canary 全部通过;单次失败/取消不拖垮其他文档。产品 watchdog 作为意外故障防线继续存在,不能作为 raw hang 已修好的证据。 + +### W4:crash 根因、锁和缓存清理 + +**文件:** fork `tests/crash/windows/README.md`、`.github/workflows/win-crash-corpus.yml`、`win-symbols.yml`、`tests/soak_loop.py`、0003/0007 patch;拟新增 `tests/crash/replay.py` 和 corpus manifest。产品 `src/orchestrator/cache.cpp`、`editors/vscode/src/crashReport.ts`、`src/engine/clangd/process.cpp`。 + +**接口:** corpus manifest 指定平台、CDB/输入与 LSP sequence、期限、基线结果和候选期望;replay 返回结构化 outcomes,区分正常回复、主动 kill、crash、timeout。dump 路径/预算只在用户明确启用且 engine 能力支持时传递。 + +- [ ] UP-12/13 用 Windows reduced inputs;UP-20 用实际 fan-out save sequence,Linux 与 Windows 分开登记,不能仅因为旧文档标题就称 UP-20 是 Windows 专属。 +- [ ] 当前 corpus 为空且 nonempty 分支只有 echo:实现真正 replay,缺 debugger/PDB 不允许 warning 后绿灯;用一个受控 crash 验证栈中含函数/源码信息和匹配 build-id,再运行真实 corpus。 +- [ ] 每个 crash 先获取符号栈并缩减,再确定 clangd 或 Clang 核心修复;不把未经证实的 stack overflow 当结论,不盲目提高所有 worker 栈至32–64 MB。 +- [ ] Windows stale lock 验证 dead PID、live PID、PID reuse、同/异 host、权限拒绝、并发 claimant;owner 身份不可靠时不能随意抢锁,失效恢复需有界。 +- [ ] copy-on-read 临时文件按 owner generation/lease 回收;crash 后清孤儿,但不删除任何仍被活进程使用/映射的 BMI。不能仅靠 atime+三天定义“安全”。产品 commands/context 目录保持预算及活动保护(UP-19)。 +- [ ] dump 默认关闭;开启后限制数量/总大小/保留期,report 本地提示敏感内容和手动导出流程。异常退出后 backoff/隔离/bundle 保留。 + +**通过条件:** 非空真实 crash corpus 无 crash/hang;主动 kill 不计为成功回复;cache/进程有界,crash capture 仅是取证通过,不使 UP-13 自动 fixed。 + +### W5:真实诊断与 semantic range + +**文件:** fork 0001/0004/0005 patch、`patches/PATCHES.md`、`ci/ci_build.sh` 与对应 lit 测试;产品 `editors/vscode/test/suite/workaroundCanary.test.ts`、`semanticTokens.test.ts` 及现有诊断 fixtures。 + +- [ ] UP-05 保留 backport 的原始回归测试,未来 LLVM 基线包含该修复时移除 carried patch,不改下游语义。 +- [ ] UP-22 测试 ref_view/filter/transform 等 view 链、真正只读普通变量、用户自定义 operator|、可变引用消费;不能一概禁止所有 operator| 参数的 const 检查。raw clangd 无过滤也要正确,现有产品 tidy fixture 通过不算根因证明。 +- [ ] UP-15 测试分号/跨行 import 诊断位置;UP-09 测试请求首中末行、跨边界 token 和 UTF-16,遵循 LSP 允许范围扩展及相交 token 的约定,不臆造严格 start-character 截断规则。 +- [ ] 完整运行新增 lit,现有硬编码六项不再遗漏 range/tidy/补全回归。按 feature 单独证实 WA canary;原版引擎仍保留对应保护。 + +**通过条件:** 假阳性减少且真实诊断不丢;产品过滤只因对应 raw canary 通过而退休。通用防故障机制不退休。 + +### W6:#43 格式和 #44 编译器扩展 + +**文件:** fork LLVM `clang/lib/Format/Format.cpp`、`clang/include/clang/Format/Format.h` 及 `clang/unittests/Format/`(新增命名 style 的备选落点),Sema completion 回归测试;产品 compiler-profile/format 请求路径通过源码审计定位后单独提交实现设计,VS Code `editors/vscode/test/suite/` 新增 formatting/extensions 测试。 + +**设计决策:** #43 提到 `.clangd`,实际样式来源应是 `.clang-format`。以 mcpp 仓库 `.clang-format` 形成固定版本的、clang23 可解析的样式快照,不运行时从网络读取。优先级为项目 `.clang-format` / 显式用户设置 > mcpp project fallback > 原有通用 fallback;不向用户项目写文件。mcpp fallback 的默认适用范围仅 mcpp project,其他工程 opt-in。若选命名 `mcpp` preset,必须 fork 注册并声明能力;不能给原版 clangd 传不存在的 preset。最终样式快照及样例 diff 作为 W6 的独立 review 产物。 + +- [ ] #43 保存格式 golden cases:模块/global fragment、import、模板、namespace、lambda、长表达式;校验 mcpp 默认与固定样式一致、项目/用户 override 有效、外部 clangd 不报未知 style。官方配置依据:[ClangFormatStyleOptions](https://clang.llvm.org/docs/ClangFormatStyleOptions.html)。 +- [ ] #44 的 `__attribute__` 是属性引入语法、`cleanup` 是属性名称、`__try` 是 SEH 关键字,不能全部当函数名塞进词典。按编译器/目标/语言及语法位置支持 GNU/Clang attributes 和 Windows MSVC/clang-cl SEH。 +- [ ] 验证属性位置、`cleanup(function)` 合法插入及声明、普通标识符位置、注释/string、Linux 与 Windows target;SEH 用实际目标编译器可接受的最小例子,不用任意含析构的 C++ 函数证明支持。 +- [ ] 语义 completion 在 fork parser/Sema 的合法上下文实现;产品只传准确画像与控制提示能力。clangd 尚不能忠实模拟的厂商语义明确标为限制,lexical 建议不能冒充编译通过。 + +**通过条件:** mcpp 格式 golden 和 override 测试通过;本轮指定的三类扩展有目标匹配、合法位置和实际编译检查。不承诺完成所有厂商所有扩展。格式配置依据与[属性参考](https://clang.llvm.org/docs/AttributeReference.html)不能替代目标编译器测试。 + +### W7:身份、kit、包与可移植性 + +**文件:** fork `UPSTREAM`、`ci/recipe.md`、`ci/scripts/configure.sh`、`package.sh`、`.github/workflows/release.yml`;产品 `packaging/payload.lock.json`、`modules/pack/src/payload.cpp`、`modules/pack/tests/test_payload.cpp`、`src/engine/payload.cpp`、`editors/vscode/src/payload.ts` 及 release workflows。 + +- [ ] 测试 suffix 引擎与 base kit 匹配、旧 manifest、缺失身份、伪造 hash、用户覆盖引擎;实现第 2 节身份,避免用 23.1.0 掩盖 fork binary,避免拿全 suffix 比 libc++ kit 版本。 +- [ ] 统一 archive layout、LICENSE/NOTICE、resource-dir/运行库;SHA256SUMS 排除自身,验证解压与 payload assemble 都一致。 +- [ ] Linux 建议基线 Ubuntu20.04/glibc2.31 x64,用真实容器/sysroot 和依赖检查保证;如 LLVM23 构建依赖不支持这一目标,必须带证据重新 review 最低版本,不能 recipe 写20.04而实际22.04构建。ELF interpreter 只能是系统可用路径,无 `/home/speak/.xlings/`;动态 GLIBCXX 需求一起检验。 +- [ ] Windows 建议 Windows10 x64,明确 CRT 打包/静态策略及许可,测试 MSVC/clang-cl/GCC 项目;macOS 建议 x64 最低12、arm64 最低12,显式 deployment target,分别真实启动。以上 OS floor 是待 review 的产品承诺,实施时须测试到下限,不只测 CI 最新 OS。 +- [ ] VSIX/CLI/其他编辑器/xlings 全部解析同一 manifest;xlings 不再靠 PATH llvmtools 偶然找到原版。决定独立 `mcppls-clangd` xpkg 或随完整 payload 携带时,以原子兼容升级和离线可用为验收,避免两个版本轴各自升级导致 kit 错配。 + +**通过条件:** 四平台干净机器安装后实际启动、解析模块、补全、格式、保存和重启;引擎 SHA 与验收身份一致。现有本机测试 ELF 依赖 home 下 loader/max GLIBC2.38,因此不能晋升为正式 Linux 产物。 + +### W8:联合门槛与 release candidate + +**文件:** fork `ci/check_ledger.py`、`ci/ci_build.sh`、`.github/workflows/release.yml`、`conformance.yml`、`bench.yml`、`soak.yml`;产品 `.github/workflows/prerelease.yml`、`release-checks.yml`、`release.yml`、`modules/pack/src/release.cpp`。 + +- [ ] ledger 校验新增 release-mode:启用且用于宣称修复的 patch 必须 steady;实验 patch 默认不启用、不冒充正式修复。缺测试、空 corpus、未执行 manifest、只回 lexical 的 gate 均以负例证明会失败。 +- [ ] 保留 fork 既定的连续7次 green nightly soak + bench 晋升 steady 条件,但先让这些 job 真正校验语义/corpus/回复与资源;旧空转或无正确性断言的 green 不计入7次。 +- [ ] release publish 依赖 build/lit/语义质量/基线对照/soak/四平台 portability 的共同 verdict,不只依赖 package。任何中间 job 跳过或失败都不能生成可晋升 candidate。 +- [ ] fork immutable 产物送到 mcppls lock/assemble;产品在真实 VS Code 安装对应最终 VSIX 验证,不用开发目录代替安装包。不从另一次重建复制“相同版本”二进制。 +- [ ] 报告冷/温阶段、p50/p95/sample count、CPU/RSS/缓存增长、正确性、fallback/restart/crash 数、平台和工件 SHA;release notes 分列 fixed/mitigated/open。 +- [ ] release candidate 先内部 review;Marketplace/OpenVSX/GitHub/xlings 发布仍走现有受控流程,本轮不授权推送或发布。 + +## 4. 建议联合验收指标 + +| 指标 | 阶段/方法 | 建议门槛 | +|---|---|---| +| 语义补全 | raw 引擎 + 产品 + VS Code;W1 所有语境 | 目标符号与合法插入100%通过;无上下文污染,无依赖更新漏符号 | +| 引擎补全延迟 | warm、每语境至少30请求、三次独立启动;报告全部原始样本 | 普通/限定名 p95≤200 ms,模块成员 p95≤300 ms;对约1 s的原版相同正确路径至少改善50% | +| 产品命中缓存延迟 | 独立于 raw 测量,body/prefix edit | p95≤50 ms;原版已有2–5 ms缓存场景不因强制绕缓存变成75 ms | +| 新导出生效 | 模块 export 编辑→消费者正确补全 | 小型 inferred fixture ≤5 s;C7不超时;重型项目按阶段报告,不套用小 fixture 限值 | +| 冷/温导航 | 继承 release-checks,固定机器与 fixture | 5次 median cold<12 s、warm<5 s;fork不退化,能达到什么幅度单列数据 | +| hang/crash | raw repro、产品序列、真实 corpus | 已复现阻断集0 hang/0 crash;不靠重启掩盖;未知问题明确 open | +| 稳定性 | 先短 smoke,RC 每平台≥2 h;UP-20≥1000 save iterations | 无异常重启/孤儿进程;请求无超期积压;RSS稳定期末≤1.2×初始且无持续线性增长 | +| cache | edit/reopen/kill循环、owner与预算测试 | 活跃 BMI不误删;孤儿最终回收;目录/磁盘回到配置预算以内 | +| 交互验证 | 每个平台真实 VS Code + 所支持 CLI入口 | 无弹窗 crash;补全选中后合法代码;格式/保存/跳转/关闭重开通过 | +| 分发 | OS下限干净机器,移除开发依赖/PATH偶然命中 | 四平台 hash可追踪、启动成功、license完整、无本机绝对依赖 | + +采样区分 cold/indexing/warm/cache-hit,不能混在一个 p95 中;超时、错误和丢候选样本计失败,不能从延迟样本中悄悄剔除。性能与正确性 conjunctive(同时满足),不做总分互相抵消。CPU/RSS 同机器比较,要求新增优化无≥20%的稳定期 CPU/RSS退化;噪声或 trade-off 有数据后重新 review,不自行放宽。 + +真实项目基线:qt-demo、mcpp `d1f1c98fa26d953e084a183a9672fc1e0ce63558`、xlings `84572b0cc8502a16afaa4ae00867aef17f18c2c2`,记录 CDB/工具链/硬件。先修旧 WA009 probe 缺失 `heavyh000` 输入,再做性能结论。此前真实 extension-host 40请求/引擎可作回归基线,但不等同于人手键入/选中建议;RC 增加录屏或人工交互记录。 + +## 5. 依赖顺序、评审点与退出条件 + +1. **G0:证据与门槛正确。** W8 的负例 gate、W1/C7隔离、W3 raw hangs、W4非空 corpus 和构建身份先落地。修复质量 benchmark,不能先发包再找证据。 +2. **G1:正确与稳定。** W1语义回归、W2失效、W3挂死、W4已复现crash/锁/泄漏、W5诊断通过;此阶段先不要求高风险结构优化。 +3. **G2:真实优化与功能。** 基于 trace 进入 W1/W2优化,W6格式/扩展;任何优化都重跑G1。仅禁用0006恢复原速不满足用户的优化目标。 +4. **G3:跨平台产品化。** W7产物/身份/kit,四平台最终安装包跑第4节;Windows符号、macOS两架构及Linux低版本缺一不可。 +5. **G4:RC review→release。** 连续完整验收、2 h稳定性、真实项目交互、记录剩余限制,使用相同bytes晋升。发布后具备候选回退与用户显式选择原版路径。 + +任何可重现新增语义回归、原有确定 hang/crash 未修、C7超时、性能未达、平台不能安装、空 corpus、身份不真实都阻断 **joint 0.0.12 默认启用维护版**。若成本超出本轮,向用户带数据提出拆分范围/延期;不能自行把“隐藏问题的当前 fork”命名为真实修复版本发布。 + +## 6. 本轮 review 的核心决策 + +1. 接受“根因修复 + 语义正确 + 性能 + 四平台”联合门槛,而不是只换引擎或跑通打包。 +2. 同意先修当前成员补全/C7回归及 hang/crash,再按 trace 做性能优化;不预设 BMI summary 或增大线程栈必然解决问题。 +3. 同意 mcpp 格式默认仅适用于 mcpp项目,且项目/用户配置优先;#44本轮以明确三类语法和目标为边界。 +4. 确认第4节性能预算、四平台范围及建议 OS floor;未达到时需要重新review,不隐式降低指标。 +5. 同意保留通用隔离/重试/bundle,feature workaround逐项退休,externally configured clangd继续可用。 +6. 同意按G0→G4推进:先可复现证据与正确gate、再根因修复、再优化、再候选联合验收,最终发布另行授权。 diff --git a/.agents/docs/2026-10-07-darwin-pipe-write.md b/.agents/docs/2026-10-07-darwin-pipe-write.md new file mode 100644 index 00000000..3116d4f0 --- /dev/null +++ b/.agents/docs/2026-10-07-darwin-pipe-write.md @@ -0,0 +1,34 @@ +# Darwin child-pipe writes + +Register: [UP-O1](https://github.com/Sunrisepeak/mcpp-language-server/issues/24#issuecomment-6028338032). Compensation: WA-PLATFORM-001 in +modules/platform/src/process.cpp. This is a platform runtime issue and belongs +outside the clangd workaround registry. + +The Intel runner executes the actual cross-built dev/release binaries. Both +failed by signal 13 in the existing blocked-peer shutdown test (CI run +37552260398, jobs 112572688643/112572688644). openkal-macos 0.12.0's env.cpp +explicitly records that its pipe writes can trigger SIGPIPE; its C-library +layer does not install a kernel signal disposition. + +Each parent-owned child-input write descriptor now receives F_SETNOSIGPIPE +before spawn. Darwin's existing native syscall convention is used because the +program supplies its own C ABI. Failure closes both input ends and the work +handle, and rejects spawn. The change is local to that descriptor. Constants +and semantics: [Apple XNU fcntl.h](https://github.com/apple-oss-distributions/xnu/blob/main/bsd/sys/fcntl.h). + +Evidence: Linux process tests pass, 2 binaries; the main test has 23 cases and +86 assertions. Intel and arm64 process tests cross-compile (2 binaries each). Fixed-byte +native CI remains pending. The new regression explicitly +waits for peer exit, writes to its still-open parent end and requires a returned +process-write error. Existing blocked-writer shutdown remains the lifecycle +canary. No native success is inferred from cross-linking. + +Remove WA-PLATFORM-001 only when selected openkal-macos reliably reports closed +pipe writes on both macOS architectures with default parent SIGPIPE handling. +Other arbitrary openkal streams do not gain a blanket protection from this fix. + +Native follow-up: Intel dev CI run 37553665184 / job 112577351043 at +1fa6975 passes the blocked-peer and closed-peer write canaries and both process +binaries (main: 23 cases, 80 assertions). The job fails later in a separate +pack platform fixture, which has now been corrected. Native release proof +is still pending because that fixture ran before its process tests. diff --git a/.agents/docs/2026-10-07-maintained-clangd-0.0.12-plan.md b/.agents/docs/2026-10-07-maintained-clangd-0.0.12-plan.md new file mode 100644 index 00000000..7e3cff87 --- /dev/null +++ b/.agents/docs/2026-10-07-maintained-clangd-0.0.12-plan.md @@ -0,0 +1,224 @@ +# mcppls 0.0.12:维护版 clangd 接入方案与本地验收 + +> **历史记录。** 0.0.12 的最终范围、决策与实施见 [Part 3](2026-10-09-0.0.12-part3-convergence-plan.md) §8。文中 `.agents/docs/2026-10-08-0.0.12-part2-evidence/`、`.agents/docs/assets/`、`tests/evidence/` 等原始证据路径位于 `mcpp-language-server-0.0.12-evidence.tar.zst`([evidence-0.0.12](https://github.com/Sunrisepeak/mcpp-language-server/releases/tag/evidence-0.0.12)),完整增量历史在 `archive/0.0.12-joint` 分支。 + +状态:供 review;本地候选已打包并在真实 VS Code 验证,**当前 fork 不满足默认发布门槛**。 +日期:2026-10-07(JST)。范围是分析、测试包与方案;正式 lock、生产行为和发布流程尚未切换。 + +联合 release 范围与执行门槛已扩展到 [mcppls 0.0.12 + mcppls-clangd 联合方案](2026-10-07-0.0.12-joint-release-plan.md):覆盖 #24/#37/#43/#44、真实根因修复、性能与正确性、Windows crash corpus、四平台分发以及逐项 workaround 退休。本文件保留原始分析和测量;第 1/5/6 节的初步接入建议以联合方案的 G0–G4 为准。**仅关闭不安全 fast path 并恢复原版速度不再视为满足 0.0.12 优化目标。** + +## 1. 结论与 review 决策 + +独立仓库的维护模型可行:固定 LLVM 基线,携带小型 patch series 和 overlay,四平台产物交给 mcppls 的 payload 流程。但当前实现没有覆盖 #24 的主要稳定性问题,而且补全加速引入了真实语义回归。建议下个版本接入维护版引擎的身份、分发与验收机制,**先修补全门控和模块编辑后的候选更新,再决定默认启用**;不要直接把当前七个 patch 全量视为已修复并删除 mcppls 的保护。 + +需要 review 的四个决定: + +1. 采用维护版 clangd;正式切换以本文件的发布门槛为准。当前包只作本地试验。 +2. 首先收紧或关闭 0006 的索引快速路径。成员、指针成员、类型作用域、字符串/注释、未知模块或索引不完整均须回到 Sema;正确性优先于 100 ms 指标。 +3. 分离 `llvm-base-version` 与完整 `engine-version`,保留已有 23.1.0 kit。payload/report 必须能看到 `23.1.0-mcppls.N`、fork commit 和二进制 SHA-256。 +4. 保留死锁、异常退出、autosave、缓存与后台索引保护;每项 workaround 根据实测 canary 单独退休,支持用户指定的原版 clangd。 + +## 2. 本次检查的身份与证据 + +| 对象 | 本次固定值 | +|---|---| +| 工作区原始 checkout | mcppls `6893a4e`,0.0.10;未在此处升级版本 | +| 测试服务器源码基线 | 当前远端 main `a0cd29b735971d56042e91c6162ae373bcbb193b`,0.0.11 | +| 测试候选 | 在隔离本地 clone 中用 `mcppls-devtools version --set 0.0.12` 生成版本,再 release 构建;**仅版本变化,无额外 0.0.12 产品功能** | +| fork checkout / 远端 main | `2724791464ff826454cb7c3a9946d2097a4fd259` | +| LLVM 基线 | `llvmorg-23.1.0`;`UPSTREAM` 当前是 tag,需要补解析后的 commit SHA | +| fork binary identity | `clangd version 23.1.0-mcppls.0` | +| VS Code | 1.132.0,Visual Studio Code,desktop,linux-x64 | +| 真实项目 | `/home/speak/test/mcpp/qt-demo`,Qt 6.11.1,gcc/libstdc++ 16.1.0,`import std; import nlohmann.json;` | +| 测试包 | `/tmp/mcppls-0012-fork-review-hCVnxE/mcppls-0.0.12-fork-linux-x64.vsix`,约 36.17 MB(vsce 报告) | +| VSIX SHA-256 | `f612d0a224c1b8eb8d6e7da70529fc13ba84befd86d94dd85172705051a685d8` | +| 打包 clangd SHA-256 | `a3855155d2e2a6746d07805153a59f7c352b8b768ff7401f9cd4aed41c9bd209` | +| 打包 mcppls SHA-256 | `28f1543eecbc0897f2d7d4c1621d65c2eee848b42411d56b2c6ca1adbb4491b7` | + +测试包通过现有 payload assemble/verify 和 vsce 打包,随后实际安装到独立 extensions-dir;VS Code 中运行真实扩展和它的 bundled server/clangd,不是 mock LSP。qt-demo 的修改只通过 VS Code buffer / LSP 传递,probe 最后复原,文件内容 hash 前后相同。候选最终报告 core clangd 与 mcppls 都 ready。 + +原始输出与可复跑脚本在 [assets/2026-10-07-clangd-review](assets/2026-10-07-clangd-review)。`results/vscode-fork-server.log` 记录了使用已安装候选 payload 的命令路径;VS Code JSON 内记录二进制 hash。临时包和内存盘缓存只保证当前机器、当前会话可用。 + +外部依据:[缺陷登记 #24](https://github.com/Sunrisepeak/mcpp-language-server/issues/24)、[fork PR #1](https://github.com/Sunrisepeak/mcppls-clangd/pull/1)。完整 comments 快照保存在 `results/issue-24-comments.json`。本次未修改线上 issue 或发布 release。 + +## 3. #24 覆盖矩阵 + +七个 patch 映射六个 UP 编号,其中 UP-25 两个 patch,UP-13 是取证设施。不能按 patch 数计算已修复问题数。ledger 当前没有 `steady`:0001–0004、0006 为 `stabilizing`,0005、0007 为 `draft`。 + +| UP | 当前 fork 的实际覆盖 | 下个版本处理 | +|---|---|---| +| 01 半成品 `import a.` 挂起 | 无 patch;本次 canary 仍挂起超过 10 s | 保留 WA-001 与磁盘隔离;高优先级回补确认过的上游修复 | +| 02 unresolved import 死锁 | 无 patch | 保留 WA-002/stand-in;增加真实复现后修上游 | +| 03 prerequisite 串行构建 | 无 patch | 保留 WA-003;独立衡量冷启动 | +| 04 查 provider 扫整库 | 无直接修复;0002 是 BMI freshness memo,不能算 provider lookup 修复 | 保留 WA-004 | +| 05 MSVC `align_val_t` 歧义 | 0001 回补 upstream #218152;Linux 上游回归测试通过 | Windows/MSVC STL 验收后对维护版单独停用 WA-005;原版继续支持 | +| 06 单文件不再回答 | 无 patch | 保留 quarantine | +| 07 快速编辑后无 CPU 卡死 | 无 patch | 保留 StuckWatch | +| 08 后台索引不准备 import,声明/定义分裂 | 无 patch;0006 更依赖索引,放大缺口 | 保留 WA-008;与 UP-17 合并研究 | +| 09 semanticTokens/range 缺失 | 0004 实现方法和 capability;按行裁剪,比补丁声明的 start-within 范围更宽 | 明确扩大范围策略并补边界/部分重叠测试;观察到范围外token本身不是LSP违规 | +| 10 unprovided `export import` 不结束 | 无 patch | 保留已知限制与超时隔离;列为稳定性补丁优先项 | +| 11 dependency scan 被 link 错误打断 | 无 patch;mcppls 已用 `-c` 处理 | 保留现有正确命令生成 | +| 12 Windows unresolved-import AST crash | 无根因 patch | 保留 containment;用符号和最小 corpus 定位 | +| 13 Windows 正确命令仍 AST crash | 0007 添加 opt-in minidump;不是 crash 修复 | 不宣称关闭;配置采集与符号匹配后再修根因 | +| 14 未保存 import 不构建 | 无 patch | 保留 WA-007;本次 autosave fixture 仍看到信息级提示 | +| 15 缺分号诊断落下一行 | 无 patch | 保留 WA-006;本次 autosave fixture 通过 | +| 16 contracts / reflection | 未实现 | 继续注明上游语言能力限制 | +| 17 已打开文件函数漏索引 | 无 patch | 不因索引快速补全而忽略;准备 reduction | +| 18 死进程残留模块锁 | 0003 Windows 本机 PID 探测,默认等 60 s;Linux 用 LLVM 原有逻辑 | 保留 mcppls cache lease/锁处理;Windows kill/restart/live-owner/PID reuse 分别验收 | +| 19 command hash 目录不回收 | 无 patch | 保留两代目录与 prune | +| 20 fan-out save crash loop | 无 crash 根因 patch;0007可协助 Windows 取证,不能解决已观测 Linux crash | 保留 backoff、bundle、重启控制 | +| 21 didClose 后 worker 空转 | 无 patch | 保留 K-7/K-8 | +| 22 ranges 错误 const 建议 | 0005 对所有传入 `operator|` 的变量宽泛抑制;canary 从 [4,5,6] 变 [5,6] | 部分覆盖;仍保留 WA-010,补 const 正例和四种非 const view 反例 | +| 23 非模块重头文件每次 rescan | 无根因 patch;0002/0006 的收益不能证明这一项关闭 | 保留 WA-009;本次重头文件 canary 存在 include 错误,其倍率不作为有效性能验收 | +| 24 崩溃留下 copy-on-read BMI | 无清理修复;0002记录 published BMI 身份不等于回收文件 | 保留 WA-011、4/16 GiB budget 与 sweep | +| 25 每次模块补全约 1 s | 0002减少 freshness validation;0006用索引跳过 Sema,快但有语义回归 | 不宣称完整根治;先保证 fallback,再做速度/质量双门槛 | + +UP-M1…M7 与 UP-P1/P2 属于 mcpp、openkal/PRoot,不应计入 clangd fork 的修复覆盖。 + +## 4. 实测结果与发布阻断 + +### 4.1 clangd 直接请求:快了,但丢失语义 + +同一真实文件、同一 mcppls-generated CDB,buffer 内在 `cli.process(app);` 后插入补全点。每个 prefix 请求 3 次,下表是中位数与单轮 item 数;绕过 mcppls 的 answer cache。 + +| prefix | 原版 23.1.0 | fork | 结果质量 | +|---|---:|---:|---| +| `nlohmann::j` | 1007 ms,22 items | 69 ms,12 items | 两侧有 json;数量/内容改变,尚无候选覆盖等价证明 | +| `std::ve` | 1143 ms,65 items | 68 ms,2 items | fork 有 vector,但混入全局 Qt 的 qVersion,缺构造函数候选 | +| `cli.` | 1035 ms,32 items | 78 ms,100 items | 原版含 addHelpOption/addOption 等成员;fork 返回 Counter/std::ranges 等全局候选 | +| `cli.ad` | 1239 ms,7 items | 75 ms,100 items | fork 返回 AdlTester/ADJ_ESTERROR 等,不含预期成员 | + +另一个沿用 fork 开发时 qt probe 的 16 轮 alternating-prefix 回放:fork p50 71.9 ms / p95 77.3 ms;vanilla p50 1073.6 ms / p95 3879.6 ms。vanilla 前数轮受后台索引/并行测试影响,后 8 轮约 988–1074 ms;因此不用该 p95 推导稳定态倍数或严格的首次就绪时间。`cold_ms` 只是首个请求延迟,不是工作区冷启动全程。 + +### 4.2 真实 VS Code:产品表现与缓存 + +每个 prefix 10 轮 buffer body edit + VS Code `executeCompletionItemProvider`;p50/p95 取后 9 轮,不包含第一轮。原版使用已安装 0.0.11,同基线的候选只生成了 0.0.12 版本与替换的 clangd。 + +| prefix | 0.0.11 + 原版 p50 / p95 | 0.0.12 test + fork p50 / p95 | 最后一轮候选数 原版 / fork | +|---|---:|---:|---:| +| `nlohmann::j` | 2.4 / 11.8 ms | 74.1 / 75.2 ms | 22 / 12 | +| `std::ve` | 3.7 / 4.6 ms | 72.6 / 81.5 ms | 65 / 2 | +| `cli.` | 1001.6 / 1021.7 ms | 77.6 / 94.6 ms | 32 / 100 | +| `cli.ad` | 2.0 / 2.7 ms | 75.5 / 82.6 ms | 32 / 100 | + +这里的数毫秒来自产品 answer cache / prefix reuse,不能读成 vanilla clangd 比 fork 快几十倍。原版前三类首个请求约 1003–1005 ms,前两类首次还出现了 fallback 的 lexical items;fork 候选持续落在约 70–95 ms,但成员候选错误与直接请求一致。`cli.ad` 原版可复用 `cli.` 的成员集合,由编辑器进一步筛选,故与 clangd 直接请求的 7 items 不矛盾。 + +这组测试是 VS Code 扩展宿主驱动真实 provider,不是逐键打开建议框、人工点击 acceptance 的交互测试。下一轮还需实际键入 `j → js`、`. → a → ad`、选中补全项并检查插入内容/resolve/snippet;不能用返回非空代替用户可用性。 + +### 4.3 根因与现有门槛的缺口 + +- 0006 的条件只判断 `Prefix.Name`、`Qualifier`、空 prefix 等,并未可靠排除 `.`、`->`。它的 `CurrentLine = Content.rsplit('\n').second` 取的是整个文件最后一行,不是光标所在行。qt-demo 末尾空行使空 prefix 也进入快速路径。 +- 有 `Preamble->RequiredModules` 就启用,没有落实设计里的 std-only、索引完整性或未命中回退。`std::` 的限定也只是文本猜测,不能替代 Sema 可见性。 +- 0004 的 range 从 `int before = 0; int inside = 1; int after = 2;` 请求 `[0:20, 0:34)`,返回 `[0,4,6,…,0,16,6,…]`,包含位于 char 4 的 before。与补丁声明的精确 start-within 切片不符;但 [LSP 3.17 semanticTokens](https://github.com/microsoft/language-server-protocol/blob/main/_specifications/lsp/3.17/language/semanticTokens.md) 允许返回更宽且完整正确的范围,也建议保留部分重叠token。因此这项是策略/验收缺口,**本次未证明协议错误,不作为成员补全同等级的发布阻断**。需要 start/end、空范围、UTF-16、部分重叠、同一行和跨行测试,避免简单丢掉 start 以前的token又引入新问题。 +- `inferred` 的 C7在模块接口新增导出 `greet2` 后等待180 s仍只有原有/lexical候选。保持**同一个0.0.12测试服务器**,只换回原版payload的clangd/kit,对照C7在2.5 s通过,整套7.2 s、0 failures。这是模块编辑后的质量回归,不能由常规 hover/definition 和首次 completion 成功覆盖;本次未进一步隔离0002与0006各自对该回归的贡献。 +- `ci/ci_build.sh` 的 lit-subset 列了 6 个老测试,未跑新增 range/tidy 专项;0006没有专用语义质量回归测试。 +- `tests/e2e/compare.py` 把“answered but no module symbols”当通过;这不足以验证模块导出符号。速度门槛也不能允许用错误全局候选替换成员答案。 +- ledger 写“只有 steady 可以 release”,但 release workflow 只依赖 package,没有执行该状态门槛或依赖质量/soak/VSIX验收。当前全系列均不是 steady。 + +### 4.4 其他验收 + +| 验收 | 结果与含义 | +|---|---| +| `cmake --build … --target clangd -j 4` | 退出 0;当前本地源码对应的构建可用 | +| patch ledger validator | 7 patches / 7 rows,通过;不代表产品正确 | +| 定向 LLVM lit | validation cache、stale lock、range、modules、module_dependencies、modules_no_cdb、pr218152,7/7;range 现有测试漏起始列 | +| installed VSIX 的 VS Code modules + semanticTokens suites | 12/12,0 failures;工作区 hash 未改变 | +| fork kill/restart 小循环 | 9 cycles:6 个 clean reply,3 个 kill;退出 0;不是 9 个回复,也没有验收 copy leak/长期 fan-out | +| `tidy-const-views` 产品 fixture | 0 failures,2.2 s;依赖保留的 WA-010,不能证明 fork 根因完全修复 | +| `typing-autosave` 产品 fixture | 0 failures,37.0 s;包含半成品导入、恢复、诊断定位、未保存 import;依赖 mcppls 原有 containment | +| `workaround-canaries` | 1 failure:WA-010 出现 [5,6],说明行为改变但未完全恢复正确;WA-001 仍挂起。WA-009 的 4.97×伴随 missing header,性能结论无效 | +| `inferred` 产品 fixture | 1 failure,185.9 s:C7新增模块导出 `greet2` 后completion仍不含它;其余检查通过 | +| `inferred` 原版对照 | 同一个0.0.12服务器 + 已安装0.0.11的原版payload:0 failures,7.2 s,C7用时2.5 s | + +本机曾空间耗尽,只删除了本轮隔离 clone 的 obj/pcm 中间文件后继续;保留测试包、源码和结果。VS Code 有系统 inotify/EMFILE 警告,不能把本次结果扩展为完整磁盘 watcher 验收。没有修改系统限额、停止用户进程或替换用户默认扩展。 + +## 5. 下个版本接入设计 + +### 5.1 两条版本轴和可追溯身份 + +现有 `packaging/payload.lock.json` 的 `clangd-version` 同时驱动 manifest 与 libc++ kit 匹配。直接改成 `23.1.0-mcppls.0` 会违反 kit 的完整字符串匹配;继续填 `23.1.0` 又隐藏真实 fork。这次测试正暴露这个缺口:hash 是 fork,VS Code 状态和 payload 仍报 23.1.0。 + +建议扩展 lock/manifest 的引擎元数据,不给 libc++ 虚构一个带 fork suffix 的版本: + +```json +{ + "llvm-base-version": "23.1.0", + "engine-version": "23.1.0-mcppls.1", + "engine-source": { + "repository": "Sunrisepeak/mcppls-clangd", + "commit": "", + "upstream-commit": "", + "patch-series-sha256": "", + "features": ["module-validation-cache", "stale-lock-recovery"] + } +} +``` + +`.1` 是修正后候选命名的建议,不是已经存在的发布身份。旧字段兼容迁移,完整 engine version 用于 report/diagnostics,LLVM base 用于 resource dir、kit 兼容;kit 本身仍是 libc++ 23.1.0。厂商后缀不应单独授权删除 workaround,features 还要匹配已验证的发行元数据/hash;用户替换的 clangd 以实际 capability/canary 为准。 + +需要改动的边界:`modules/pack` lock/trim/assemble/verify、`modules/base` 版本生成检查、`src/engine/payload.cpp` 的 kit 选择、报告和诊断 bundle、S4/schema/fixtures,以及编辑器状态显示。当前 parser 已保留完整 `--version` 后缀;问题主要在 manifest 提前给了旧版本,以及 kit equality。 + +### 5.2 四个平台与包格式 + +保留 `linux-x64 / linux-arm64 / darwin-arm64 / win32-x64` 单一平台表,替换每个平台的锁定输入,kit 依赖暂时不动。不能用一个共同 linux/mac artifact key 掩盖实际四个平台。 + +fork tarball 当前是 `clangd--/clangd/{bin,lib}`,现有官方 zip/LLVM tar 输入的 trim 路径假设需要适配。先给四种维护版归档写 trim fixtures,再导入固定 release asset 的 size/SHA-256;禁止使用 latest URL。 + +fork `package.sh` 当前没放 LLVM LICENSE.TXT,本轮从同基线源码补入才可 assemble。正式归档必须含 LICENSE、headers、artifact provenance 与不包含自身的 SHA256SUMS。当前脚本重定向到包内 SHA256SUMS 再 `find .`,有把该文件自身收入校验表的风险,需要排除并实际 `sha256sum -c`。 + +本轮本机构建的 ELF interpreter 是 `/home/speak/.xlings/data/xpkgs/xim-x-glibc/2.44.3/lib64/ld-linux-x86-64.so.2`,动态需求最高 GLIBC_2.38 / GLIBCXX_3.4.30。**这个测试包只适用于本机,不可作为通用 Linux release。** fork CI 的 ubuntu-22.04 构建也需检查 PT_INTERP/RPATH/动态依赖,并在最低支持系统验证;不能由本机运行成功推断可移植。 + +release 四平台构建 snapshot(run [37479646231](https://github.com/Sunrisepeak/mcppls-clangd/actions/runs/37479646231)):linux-x64、linux-arm64、darwin-arm64 package success,win32-x64 仍 in progress。该 snapshot 不是四平台产品验收,也不是 Windows crash 修复证明。 + +### 5.3 所有分发入口使用同一维护版 + +- VS Code/CLion/Zed 与完整 payload:由同一锁定输入组装,真正测试“安装的包”,覆盖用户 compiler、semantic-kit、无 SDK 等 profile。 +- xlings 当前只分 server 与 kit,clangd 依赖 `llvm-tools`/PATH;仅换 VSIX 不会让 CLI 用户用维护版。建议发布独立 `mcppls-clangd` xpkg(同 release asset/hash),让安装/启动解析其固定路径;不要把用户通用 llvm-tools 替换掉。若决定 CLI 继续原版,release notes 要明确分发差异。 +- 选择顺序:用户显式 `--clangd` → payload engine → 明确安装的 mcppls-clangd 路径 → PATH fallback;report 必须显示来源、version、hash、kit。现有显式 override 保持可用。 +- 回滚采用额外修正提交,恢复上一组输入并重新打包;测试候选保留方便 A/B。不额外在每个 VSIX 放两份庞大 clangd。 + +### 5.4 workaround 与稳定性 + +先保留 WA-001/002/003/004/006/007/008/009/010/011/012,以及 quarantine/StuckWatch/backoff/K-7/K-8。WA-005 与 Windows 死锁清理只能在各自回归与最老支持引擎策略满足后按维护版能力退休。 + +WA-012 的 adaptive budget 仍用于 Sema fallback。快速路径真的答到客户端以后再观察 budget 分布,不因为 version suffix 把预算保护全部关掉。索引质量门槛必须包括 UP-08/17;单纯 `isIncomplete=false` 的 client filtering 无法补回第一次已经丢失的成员或导出符号。 + +0007 默认不采集 minidump,mcppls 尚未传 `--crash-dumps-dir`;接入取证还要安排启动参数、与二进制匹配的 PDB、保留数量/字节预算和诊断导出规则。当前使用 full-memory dump,目录和上传应作为诊断功能明确控制;不以“打了这个 patch”宣称 UP-12/13/20 已关闭。 + +## 6. 执行顺序与发布门槛 + +| 阶段 | 工作 | 退出条件 | +|---|---|---| +| A:修正 fork 的可用性 | 0006真实光标行、成员/作用域门控、未命中回 Sema、模块编辑后索引/候选更新;0004明确range策略;补专用 lit/quality corpus | qt-demo 两种成员 prefix 的正确候选恢复;std 限定不混入全局 qVersion;新增模块导出立即可补全;range策略测试通过 | +| B:稳定 fork 工件 | 固定 upstream SHA、修 LICENSE/SHA256SUMS、完整版本/provenance、平台归档和最低系统构建 | 四平台 hash/headers/license/动态依赖验证;需要发布的 patch 达到 steady | +| C:mcppls接入 | 版本轴拆分、trim、kit匹配、report与分发解析 | 旧 payload 和用户原版 override 仍能正常启动;维护版身份和 kit 显示正确 | +| D:再次组装0.0.12候选 | 从 review 后的0.0.11基线生成版本,全平台正式方式打包 | unit/release checks、conformance、installed VSIX suites 全部通过,canary变化有逐项解释 | +| E:真实工程门槛 | qt-demo、mcpp、mcppls、xlings、Windows GalTranslPP,实时键入与选择补全;fan-out save、未保存import、close/reopen、kill/restart、缓存增长 | 成员/作用域/导出符号不回归;20+ warm requests 中正确快速路径 p95 <200 ms;Sema fallback按预算正常返回;无崩溃循环/失控缓存 | +| F:默认启用 | 锁定受验候选、报告review与变更记录 | review接受上述证据与各UP仍存的限制后切换默认 | + +性能 gate 比较的是**正确回答的请求**:必须验证结果包含预期符号、候选 scope、insertText/snippet、resolve;任何空结果、lexical fallback 或错误全局候选都不能当一次快速成功。原版 p50/p95 与 fork 分别在 core ready、cold start、body typing、prefix reuse、module edit invalidation 五种场景记录。 + +Windows验收单独包含 MSVC STL、现存 crash corpus、保存高 fan-out接口、dead/live lock owner、UTF-8 路径、PDB/二进制匹配;Linux小循环不能替代。cache验收统计死进程后的 copy-on-read 文件与 command dirs,不只是下一次 completion 有回复。 + +review 后优先实现 A/B/C;UP-01/02/10 与 UP-24 是后续主要稳定性补丁线,不能被“UP-25 p95已达标”覆盖。根治模块 Sema 补全(BMI completion tables 等)保留为独立研究任务,不把 ASTContext 对象缓存当成可直接实现的跨请求共享。 + +## 7. 复跑入口 + +本轮隔离目录保留 `/tmp/mcppls-0012-fork-review-hCVnxE/source`。本机源码、包、fixture与日志均可检视。脚本中的机器路径和VS Code版本是本轮固定值,换环境先调整。 + +```bash +# 真实 VS Code:安装候选并在 qt-demo 调用真实 provider +node .agents/docs/assets/2026-10-07-clangd-review/run_vscode.cjs \ + /tmp/mcppls-0012-fork-review-hCVnxE fork +# 原版对照:在独立 profile 使用已安装0.0.11的副本 +node .agents/docs/assets/2026-10-07-clangd-review/run_vscode.cjs \ + /tmp/mcppls-0012-fork-review-hCVnxE vanilla + +# 绕过产品缓存:成员/限定名补全和range边界 +python3 .agents/docs/assets/2026-10-07-clangd-review/direct_probe.py \ + /tmp/mcppls-0012-fork-review-hCVnxE/payload/clangd/bin/clangd \ + /home/speak/test/mcpp/qt-demo \ + /home/speak/.cache/mcppls/workspaces/qt-demo-b32b527216152f14/contexts/default/cdb +``` + +本轮保留线上历史与用户修改;只在 `.agents/docs` 新增分析和证据,正式接入待此方案review。 diff --git a/.agents/docs/2026-10-07-mcpp-format-review/README.md b/.agents/docs/2026-10-07-mcpp-format-review/README.md new file mode 100644 index 00000000..c3e0eb91 --- /dev/null +++ b/.agents/docs/2026-10-07-mcpp-format-review/README.md @@ -0,0 +1,20 @@ +# mcpp fallback formatting review + +The upstream configuration is a byte-preserving snapshot from mcpp commit +74bcb859e60afc71ad759540d2de5344dda400e9. Its SHA is recorded in snapshot.json. +The snapshot and named preset parse with clang-format 23 and both produce +expected.cppm. The engine golden/override and raw LSP fallback tests pass. +Product editor acceptance and final four-platform bytes remain pending. + +The maintained engine will register the named `mcpp` C++ preset from this +snapshot. Existing `.clang-format` discovery remains authoritative. The product +may select this fallback only when verified engine metadata declares +`format-style-mcpp`, and only by default for an mcpp project. Explicit user +fallback settings take priority. External or legacy engines receive no unknown +preset, and no configuration file is written into a user's project. + +The fixture covers global module fragments, import, constrained templates, +namespaces, lambdas, constructor initializers and long expressions. Final golden +output must be generated and checked with the same clang 23 formatter as the +maintained preset. A named preset and this snapshot must yield identical output; +project overrides and explicit user fallback are separate acceptance cases. diff --git a/.agents/docs/2026-10-07-mcpp-format-review/expected.cppm b/.agents/docs/2026-10-07-mcpp-format-review/expected.cppm new file mode 100644 index 00000000..c10ac313 --- /dev/null +++ b/.agents/docs/2026-10-07-mcpp-format-review/expected.cppm @@ -0,0 +1,23 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template +requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { +public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_; + } +private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/.agents/docs/2026-10-07-mcpp-format-review/input.cppm b/.agents/docs/2026-10-07-mcpp-format-review/input.cppm new file mode 100644 index 00000000..45eb6e55 --- /dev/null +++ b/.agents/docs/2026-10-07-mcpp-format-review/input.cppm @@ -0,0 +1,6 @@ +module; +#include +export module format.demo; +import std; +export namespace demo {template requires requires(T x){x+x;} T sum(T first,T second){auto combine=[&](T left,T right){return left+right;};return combine(first,second);} +class Buffer {public:Buffer(int capacity,int limit):capacity_(capacity),limit_(limit){} int scaled() const{return capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_;}private:int capacity_;int limit_;};} diff --git a/.agents/docs/2026-10-07-mcpp-format-review/snapshot.json b/.agents/docs/2026-10-07-mcpp-format-review/snapshot.json new file mode 100644 index 00000000..ab178a40 --- /dev/null +++ b/.agents/docs/2026-10-07-mcpp-format-review/snapshot.json @@ -0,0 +1,7 @@ +{ + "source-repository": "https://github.com/mcpp-community/mcpp", + "source-commit": "74bcb859e60afc71ad759540d2de5344dda400e9", + "source-path": ".clang-format", + "sha256": "e03547822b284dd66a266c18586575c71581b8a32bef02325851763b44dcb2c4", + "clang23-validation": "preset and snapshot produce identical golden output; two engine lit tests pass" +} diff --git a/.agents/docs/2026-10-07-mcpp-format-review/upstream.clang-format b/.agents/docs/2026-10-07-mcpp-format-review/upstream.clang-format new file mode 100644 index 00000000..8bc7128b --- /dev/null +++ b/.agents/docs/2026-10-07-mcpp-format-review/upstream.clang-format @@ -0,0 +1,132 @@ +# ----------------------------------------------------------------------------- +# mcpp-community C++ Style Configuration +# +# This configuration follows the style specification defined in: +# https://github.com/mcpp-community/mcpp-style-ref +# +# Maintained by: mcpp-community +# ----------------------------------------------------------------------------- + +Language: Cpp # Apply configuration to C++ + +# ----------------------------------------------------------------------------- +# Language Standard +# ----------------------------------------------------------------------------- +Standard: Latest # Always use the latest supported C++ standard + +# ----------------------------------------------------------------------------- +# Indentation +# ----------------------------------------------------------------------------- +IndentWidth: 4 # Use 4 spaces for indentation +TabWidth: 4 # Visual width of tab +UseTab: Never # Never use tabs + +# ----------------------------------------------------------------------------- +# Line Width +# ----------------------------------------------------------------------------- +ColumnLimit: 100 # Maximum line width + +# ----------------------------------------------------------------------------- +# Spaces +# ----------------------------------------------------------------------------- +SpaceBeforeParens: ControlStatements # Space before parentheses for control statements (if/for/while); function calls remain tight +SpacesInContainerLiterals: true # Enforce spaces in container literals +SpaceBeforeAssignmentOperators: true # Add space before assignment operators +SpacesInParentheses: false # No extra spaces inside parentheses +PointerAlignment: Left # Pointer/reference attaches to type +QualifierAlignment: Left # Place qualifiers like const to the left + +# ----------------------------------------------------------------------------- +# Braces +# ----------------------------------------------------------------------------- +BreakBeforeBraces: Attach # Opening brace stays on same line +AllowShortFunctionsOnASingleLine: Empty # Allow empty functions like `void f() {}` +AllowShortIfStatementsOnASingleLine: Never # Disallow single-line if statements +AllowShortBlocksOnASingleLine: Empty # Allow empty blocks on one line +AllowShortLoopsOnASingleLine: false # Disallow one-line loops + +# ----------------------------------------------------------------------------- +# Constructor Initializer List +# ----------------------------------------------------------------------------- +BreakConstructorInitializers: BeforeColon # Keep initializer list compact when short +ConstructorInitializerAllOnOneLineOrOnePerLine: true # Allow compact initializer lists +BreakConstructorInitializersBeforeComma: false # Do not break before commas + +# ----------------------------------------------------------------------------- +# Access Modifiers +# ----------------------------------------------------------------------------- +AccessModifierOffset: -4 # Align access modifiers with class indentation +EmptyLineBeforeAccessModifier: Never # Do not insert empty line before access specifiers +EmptyLineAfterAccessModifier: Never # Do not insert empty line after access specifiers + +# ----------------------------------------------------------------------------- +# Namespace Formatting +# ----------------------------------------------------------------------------- +NamespaceIndentation: None # Do not indent contents inside namespace +FixNamespaceComments: true # Enforce closing namespace comments +CompactNamespaces: true # Prefer namespace a::b instead of nested namespaces + +# ----------------------------------------------------------------------------- +# Switch / Case Formatting +# ----------------------------------------------------------------------------- +IndentCaseLabels: true # Indent case/default labels +IndentCaseBlocks: true # Indent statements inside case blocks + +# ----------------------------------------------------------------------------- +# Includes +# ----------------------------------------------------------------------------- +SortIncludes: true # Automatically sort includes +IncludeBlocks: Regroup # Regroup include blocks +IncludeCategories: + - Regex: "^<.*>" # Standard / third-party headers + Priority: 1 + - Regex: '^".*"' # Project headers + Priority: 2 + +# ----------------------------------------------------------------------------- +# Comment Alignment +# ----------------------------------------------------------------------------- +AlignTrailingComments: true # Align trailing comments +SpacesBeforeTrailingComments: 2 # Two spaces before trailing comments + +# ----------------------------------------------------------------------------- +# Parameter Formatting +# ----------------------------------------------------------------------------- +BinPackParameters: true # Allow parameters on same line +BinPackArguments: true # Allow arguments on same line + +# ----------------------------------------------------------------------------- +# Template Formatting +# ----------------------------------------------------------------------------- +AlwaysBreakTemplateDeclarations: Yes # Always place template declarations on their own line + +# ----------------------------------------------------------------------------- +# Operator Line Breaking +# ----------------------------------------------------------------------------- +BreakBeforeBinaryOperators: None # Break after operators + +# ----------------------------------------------------------------------------- +# Method Chain Formatting +# ----------------------------------------------------------------------------- +PenaltyBreakBeforeFirstCallParameter: 10000 # Avoid breaking chained calls unless necessary + +# ----------------------------------------------------------------------------- +# Lambda Formatting +# ----------------------------------------------------------------------------- +AllowShortLambdasOnASingleLine: All # Allow short lambdas on one line + +# ----------------------------------------------------------------------------- +# Using Declarations +# ----------------------------------------------------------------------------- +SortUsingDeclarations: true # Automatically sort using declarations + +# ----------------------------------------------------------------------------- +# Return Type Formatting +# ----------------------------------------------------------------------------- +AlwaysBreakAfterReturnType: None # Break return type only when exceeding ColumnLimit + +# ----------------------------------------------------------------------------- +# Concepts / Requires +# ----------------------------------------------------------------------------- +RequiresClausePosition: OwnLine # Force requires clause to a new line +IndentRequiresClause: false # Do not indent requires clause diff --git a/.agents/docs/2026-10-08-0.0.12-part2-linux-modules-performance-plan.md b/.agents/docs/2026-10-08-0.0.12-part2-linux-modules-performance-plan.md new file mode 100644 index 00000000..4637e6d8 --- /dev/null +++ b/.agents/docs/2026-10-08-0.0.12-part2-linux-modules-performance-plan.md @@ -0,0 +1,644 @@ +# 0.0.12 Part 2:本地 Linux 优先的 C++ Modules 深度性能优化 + +> **历史记录。** 0.0.12 的最终范围、决策与实施见 [Part 3](2026-10-09-0.0.12-part3-convergence-plan.md) §8。文中 `.agents/docs/2026-10-08-0.0.12-part2-evidence/`、`.agents/docs/assets/`、`tests/evidence/` 等原始证据路径位于 `mcpp-language-server-0.0.12-evidence.tar.zst`([evidence-0.0.12](https://github.com/Sunrisepeak/mcpp-language-server/releases/tag/evidence-0.0.12)),完整增量历史在 `archive/0.0.12-joint` 分支。 + +日期:2026-10-08;证据更新:2026-10-09。状态:**实施中;完整74 Ubuntu20干净构建、consumer、最终包和运行下限已通过,最终74 raw语境/性能/资源验收正在串行执行。私有77模块控制及原UP20严格健康通过;历史72完整分布已通过,但warm仍有约31ms差距。产品、跨平台和长期release资格尚未完成,两个PR均不合入。** + +目标:先在本地 Linux 深度定位并修复 mcppls-clangd 的 C++ Modules 性能问题,保证真实语义、输入失效、取消和资源边界;得到可复现的改善后,再扩展到 Windows 和 Apple Silicon macOS。达到 PR 合入标准后先向用户汇报,由用户 review 决定合入;发布另行决定。 + +## 1. 范围与既有方案的关系 + +本文件延续 [联合方案](2026-10-07-0.0.12-joint-release-plan.md) 的 W1–W8/G0–G4 正确性、身份和发布约束,但按用户最新指示修改执行顺序与平台范围: + +- 第一阶段只做本地 `linux-x64` 根因分析、实现和验证,优先 W1/W2 的扫描、preamble、BMI、Sema 与重复工作。Linux 已知可复现的正确性、crash/hang 回归仍阻断优化候选。 +- Linux 收敛后再做 `win32-x64` 与 `darwin-arm64` 原生验证和必要的平台修复;Linux Ubuntu 20.04 运行下限验证继续保留。`linux-arm64` 不增加本轮承诺。 +- **Intel macOS (`darwin-x64`) 不再属于本轮适配和验收范围。** 不继续调查其冷 references、关闭阶段或冷导航问题,不以 Intel CI 为本轮合入/发布阻塞项。 +- `246439b` 等 Intel 历史证据保持原样,不删除提交或改写失败结果;标注为范围外历史记录。已生成的 Intel 诊断载荷不再安排回放。 +- 同步 CI 矩阵、required checks(若配置)、payload/kit 目标及 PR 描述,使三平台声明与实际产物一致;不能只忽略一个红色 job 却继续承诺四平台支持。既有 Intel 产物是否保留历史下载,不等同于本轮承诺维护。 +- 产品层只承担编译画像、请求版本/调度、失效、观测和分发,不用答案缓存或后处理掩盖引擎扫描/Sema 性能问题。继续支持外部 clangd 配置。 + +本地适合缩短迭代和获取完整 trace。性能结论采用本机、同工具链、同输入的 baseline/candidate 对照;本机与 CI 的绝对耗时不直接比较,不假定快机器通过即可证明其他平台通过。 + +## 2. 历史基线、当前成果与未提交工作 + +以下表格保留最初固化的历史基线;当前候选与验证状态见文末,不以此表判定当前HEAD或构建进程。 + +| 对象 | 最初固化的历史状态 | +|---|---| +| 产品仓库 | `/home/speak/workspace/github/mcpp-language-server`,分支 `release/0.0.12-joint`,本轮证据提交 `2fdeba8`,最近推送头部 `236c947`;既有证据与三平台范围变更已推送,远端跟踪引用可能滞后,不据此判定未推送数量 | +| 引擎导出仓库 | `/home/speak/workspace/github/mcppls-clangd`,同名分支,本轮导出提交 `775723a`,最近推送头部 `d214029`;69 个补丁/69 条台账,0068/0069 尚未推送 | +| 本地 LLVM 验证源 | `/tmp/mcppls-joint53`,最终 joint67 `66ed2d104d8affc9e75c82a5b015f9e6869a6b00`,工作区干净 | +| 本地引擎二进制 | `/tmp/mcppls-joint53-build/full-consumers66/clangd`,SHA-256 `200acd4f71d3e8f9927d9923b7005db7b98923e42f42880ef5e39ef483ce6d49` | +| 上游 LLVM pin | `ea7d852a70e8bdfaf601d6626a760f9771b2c4b4`,LLVM 23.1.0 | +| 当前主候选 | `/tmp/mcppls-filtered-special-names` 源 `31c43d3a2`,本地引擎导出 `775723a`,0069/69 台账;匹配 Linux 分布通过,新的完整干净消费者构建正在运行,跨平台和分发资格未完成 | +| 私有 PCH 实验 | `/tmp/mcppls-pch-scan68-review`,9 个源/测试文件的未提交集成候选;涉及公共头文件的 141 个消费者已重建并链接,仅有初步正确性控制,尚无性能验收、没有 0068 导出 | + +此前 joint67 的 92 项本地针对性测试通过;公共头文件变更影响的 141 个消费者已重建。12 个 Qt 场景通过语义 smoke,48 次选定插入经原始 GCC 编译通过,尚未覆盖全部返回候选的插入组合。最终 UP20 原始项目回放零重启,8 个导入者重新发布约 4.11s,恢复约 4.26s;该产品二进制不同于早期基线,不能用作相同产品的严格性能对照。 + +这些是开发构建证据,不是最终干净构建/不可变分发资格。产品 payload 当前仍锁 stock clangd,不能将其 CI 结果称为 joint67 产品结果。 + +截至本次核对,两个正式仓库没有已跟踪文件的未提交改动。引擎本地 `a05fd0a` 已提交 `frontend_completion_consumers.py` 与 `prepare_libcxx_std_project.py`,前者七阶段实际通过,后者实际构建 native std/importer;stock 冷语义失败与原绑定负例仍保留。推导指引与 operator 后续源已提交 `31c43d3a2`,146 CompletionTest 通过,完整匹配 Linux 分布与 83 选定插入通过。产品已有两个非本任务未跟踪文件 `.agents/docs/2026-10.12-implementation-status-tmp`、`.zcodeignore`,保持原样。私有 PCH 负收益实验继续单独保存;推导指引和 operator 候选已导出 0069,最新身份与验收限制见末节。 + +## 3. 根因证据与分析边界 + +### 3.1 已证实的延迟缺口 + +最终 joint67 的 `std-qualified` 在 3 次启动、每次 30 轮中,186 个语义请求全部通过: + +| 阶段 | 样本 | p50 | p95 | 判定 | +|---|---:|---:|---:|---| +| cold-open | 3 | 2099.93ms | 3694.20ms | 单列冷启动,不混入 warm 门槛 | +| settled-warm | 93 | 169.43ms | 180.68ms | 通过 200ms | +| edited | 90 | 247.03ms | 257.89ms | 未通过 200ms | + +数据位于引擎 `tests/evidence/joint66-67/std-3x30.json`。从 257.89ms 到 200ms 至少需要约 22.4% 的 p95 改善;建议实现争取 160–180ms 的余量,但不把建议余量替换成新的硬门槛。 + +### 3.2 已有 trace 的归因 + +私有 trace-only 单轮中,edited 请求约 247.29ms,模块验证 82.95ms:canonical scanner lifetime 69.02ms(其中 getP1689 68.93ms),manifest admission 13.69ms。没有 publication wait;BMI freshness 两个稳定 generation 均命中。warm manifest lookup/replay 约 10.58–10.91ms。 + +标准库 completion 的 Sema 约 134–152ms,候选 populate 约 20–23ms、merge 约 12–13ms;JSON Sema 约 13–17ms。不能把嵌套 span 相加当总耗时,不能将返回候选数解释为遍历的声明总量。69ms 是本次扫描耗时,不是已证明可全部消除的收益。 + +现有证据优先指向:正文编辑触发完整 canonical 重扫、manifest 反复读入验证,以及标准库 Sema/候选处理成本。未证实等待锁、BMI 重建或产品缓存是这轮主要瓶颈;需由新的匹配 profile 验证,不提前指定唯一根因。 + +### 3.3 新增本地 profile 与候选边界 + +- **Manifest:**一次主重放观察到 622 个不同文件,每个路径因 Open/FileStat/Read 各开关一次,共读约 9.22MB;1710 次 stat 中 1053 次失败。代表性冷启动后 lookup 中位 wall 13.68ms,插桩计量的底层文件操作约 7.64ms。额外 shadow BLAKE3 约 2.17ms 只是分析开销,不是原实现 hash 的 exclusive 时间;目录迭代未完整计时,不能将剩余时间全归为 hash。 +- **Sema merge:**`std::ve` 的 6975 个语义候选最终返回 65 个;原路径即使 index slab 为空仍逐个生成 USR,单轮约 6.88–7.34ms。私有 empty-index 跳过候选已通过 136 项现有 CompletionTest 与 4 次真实语义/GCC 插入控制,但探索性 edited 仍约 261ms,未证明匹配 A/B 收益,不进入正式 series。 +- **PCH 集成:**已验证借用 prefix entry 在 eviction 后仍计费、当前完整正文可选择新的导入,以及 same-size/same-mtime header 改动使旧证明和新辅助尝试失效。仅 2 项初步集成控制,不代表宏状态、异常、取消、并发或性能通过。 +- **Linux canary:**最终 67 补丁允许正文新增 import 时保留经完整审计的 import-free PCH,不能以“不收缩”直接判错。修订的 canary 同时要求真实 typed Sema、正文保留的审计证明,以及 header 新增 import 后收缩;本地 fallback 与合法保留两条对照通过,最新原生 CI 仍需核对。 + +这些新 profile 带插桩开销,且开发构建期间机器负载不同;只支持成本定位,不替代 3×30 的正式分布或最终版本结论。 + +### 3.4 已排除的捷径 + +切换 DependencyDirectivesScan 的候选在现有磁盘/dirty-header `#error` 控制中失败,且 child FS 观察不完整,已拒绝。不得复活不完整 lexical import 指纹、忽略错误、关闭 PCH/BMI 校验或 index-only 任意候选路径。 + +### 3.5 以全头文件项目为直接参照,集中优化差额 + +按用户最新指示,首要性能参照是同一 Qt 项目的全头文件版本。固定源代码语义、补全位置、编译器/SDK、宏、优化参数和后台索引设置;仅改变依赖表达方式为 include 或 import,并记录不可避免的参数差异。由同一 mcppls-clangd 基线与候选分别跑两种输入,形成“全头文件/Modules × 基线/候选”四格对照,避免把不同引擎本身的差异误归因于 Modules。stock 对照仍保留,不能代替这个直接参照。 + +优先比较稳定后的正文编辑:等待/调度、扫描与输入验证、PCH/BMI 加载、Sema、候选处理、总响应。首次构建 BMI 与稳定请求分别报告。全头文件与 Modules 不要求内部执行相同,但相同有效补全的响应速度应尽量对齐;同时保留现有 200ms 绝对门槛。记录 Modules 相对全头文件的绝对差额和比例,而不是只报告达标。四格匹配分布已完成:每臂 3×30,edited p95 的全头文件 baseline/candidate 为 184.52/155.90ms,Modules 为 255.22/188.61ms。候选仍差 32.71ms(约 20.98%),继续按剩余差额定位,不宣称完全对齐。完整证据见 [实施状态](2026-10-09-0.0.12-part2-implementation-status.md)。 + +当前可用于排序的证据是:最终 67 基线单轮 edited 约 239–244ms;PCH 辅助扫描的短实验将 canonical 扫描降至约 32ms,但合并验证事务后 edited 仍约 323ms。该候选每次完整证明会读约 33.64MB PCH 和约 9.22MB其他输入,prefix/compiler/full 证明仍执行三组。上述数字来自短实验,不是正式 p95,也不是全头文件/Modules 的匹配差额;它们说明当前辅助路线的验证成本抵消了扫描收益,不能作为生产性能修复提交。 + +按分段差额选择最大增量,而不是固定优先扫描:本轮对照已经证明两侧 Sema 成本不同,因此首先优化导入声明的加载。扫描/验证作为后续路线,只有新的净收益证据才提高优先级。每个候选用一次短匹配对照筛选,无收益便停止扩大测试;不同时展开多条缺乏差额证据的优化路线。共享观察必须有当前输入一致性的证明,不能以路径或 size+mtime 命中跳过内容变化。 + +**首轮直接对照已完成:**同一最终 67 二进制、原源文件 URI/CDB/编译参数,使用未保存草稿切换 include/import;两侧各 1 次启动、1 轮正文编辑、4 次 completion,全部真实 Sema 与 GCC 选定插入通过。全头文件 warm 72.89/74.91ms、edited 177.18ms;Modules warm 175.05/178.57ms、edited 248.21ms。稳定语义执行分别约 52.80–56.29ms 与 132.35–135.71ms;edited 模块扫描/验证分别约 115.09ms 与 83.12ms。这一短、带 trace 的实验尚非正式分布,但已改变优化排序:优先调查 Modules 语义声明加载/候选遍历的约 80ms 增量,而不是假定两侧 Sema 成本相同。具体证据在引擎 `tests/evidence/part2-linux/textual-module-pair/`。 + +全头文件依赖须放在 Qt 之前以避免 `emit` 宏污染 ``;记录其额外宏/声明暴露,不能宣称全部 API 等价。复制到新路径的 Modules 对照曾使 PCH 输入重放失败、语义执行升至约 960ms,已排除;新增 `--draft-source` 探针保持原 URI、原磁盘源和实际插入编译上下文,避免该测量偏差。 + +### 3.6 已定位的主瓶颈与本轮优化决定 + +`DeclContext::lookups()` 会触发外部 namespace 的完整可见声明加载,而 clangd 模糊筛选发生在加载之后。Modules 的 `std` 表每次取约 17,192 个声明 ID,`GetDecl` 约 93–108ms;表枚举与其余工作约 4–5ms。因而本轮重点是减少不可能匹配名称的声明反序列化,而不是加速最终返回的 65 个候选排序。 + +生产候选采用补全专用接口,直接使用 clangd 现有 FuzzyMatcher;在外部名称表上先筛名称,再对保留名称加载全部声明。普通 lookup 和空补全词保持完整路径,非 identifier、using/inline namespace、重载与模板保持原语义;部分加载不能清除 external storage 标志。谓词绑定精确 source/context、同步作用域且仅消费一次;不改 BMI 格式、不缓存答案、不关闭 PCH/BMI 校验。详见 [接口设计](2026-10-09-part2-filtered-visible-lookup-design.md)。 + +已有无新增诊断插桩的 Modules 短 A/B/A(每臂 1 启动×5 轮):edited p95 从前后基线 247.26/252.40ms 降到 187.05ms,全部 36 次选定 GCC 插入通过;每次 65 个返回项的关键字段与实际编辑元组一致。候选 `std-qualified` 的独立 3×30 分布共 186 次真实 Sema 与实际 GCC 插入通过,warm/edited p95 为 117.54/192.28ms;edited 最大 204.59ms,1/90 超过 200ms。前者是短匹配收益证据,后者证明本地该语境的 p95 达标;不能把全头文件单轮 177ms 与候选 p95 192ms 当作严格对齐结论。 + +四格分布和选定声明加载边界已通过,0068 已导出至本地,68/68 台账检查通过;固定源全系列应用、11 修改文件字节核对与 configure 通过,完整构建与选定消费者运行通过(本地运行库配置见实施记录)。下一批交付为:完成分发身份与运行库资格;补齐剩余模块可见性、snippet/既有 resolve 契约与正确 stock 对照;分解剩余 32.71ms 差额和资源成本;以最终构建做产品闭环及三平台验证。扫描/PCH 实验与主候选分离,性能负例保留,当前不纳入正式优化补丁。 + +### 3.7 剩余差额:优先减少无关模板推导指引加载 + +直接对照的目的就是把优化集中到 Modules 额外付出的工作;当前绝对门槛已在开发候选通过,但与头文件版本对齐仍是优化目标。四格对照中的 p95 差额用于衡量结果;定位原因使用逐请求 span、声明数和 CPU,不能把两个分布的 p95 相减当作某一函数的耗时。 + +0068 的私有分组计量对四次 `std` 选择性加载得到: + +| 名称类别 | 每次加载的声明 ID | `GetDecl` 线程 CPU 范围 | +|---|---:|---:| +| 普通 identifier | 13 | 0.165–0.188ms | +| operator | 1,887 | 18.36–22.09ms | +| 模板推导指引 | 1,425 | 28.07–33.25ms | +| literal operator | 99 | 0.658–0.771ms | + +原记录、源和构建配方已归档至引擎 `tests/evidence/part2-linux/selected-decl-profile/`。这是带插桩且与干净构建重叠的成本定位;不用于延迟验收,也不预报能节省全部 28–33ms。线程 CPU、请求 wall 和 p95 差额不是同一指标。 + +**下一项最小候选:**推导指引的名称键携带所属模板的 identifier,复用当前名称谓词,仅加载匹配模板的全部指引。普通 lookup、空补全词保持原路径,部分加载保留 external storage;之后普通 CTAD 仍须能找到此前未加载的指引。不改 BMI 格式或公共接口,operator/literal/using 暂时保留原策略。 + +执行顺序:先验证未加载名称及后续普通推导指引查找,再验证模板/alias/snippet 返回与原路径一致;通过后做短匹配 A/B/A 和真实插入编译。只有净收益稳定、合法结果不丢失才导出下一补丁。operator 随后根据实际显示名称与 FuzzyMatcher 契约分析;不能直接按普通 identifier 判断或全部跳过。剩余扫描、manifest、候选 merge 再按更新后的 exclusive 成本排序。 + +候选 `5cd03e1fd` 已通过 144 项 CompletionTest 及 36 次真实 Sema/实际选定 GCC 插入;全部返回编辑字段一致。推导指引实测降为 48 IDs,GetDecl 线程 CPU 2.41–2.80ms。无并行编译的短 A/B/A edited p95 为 192.56/183.83/185.03ms;它只支持进一步调查,不证明完整分布或对齐。下一步核对 index 就绪时序与候选材料化成本,确认端到端净收益后再导出。证据在引擎 `tests/evidence/part2-linux/filtered-guides-candidate/`。 + +**头文件对齐的报告口径:**每次同时报告 warm/edited 的两模式 p50/p95、绝对差额、相对差额和尾部;cold 单列。对齐目标是让差额落入重复对照的实测波动范围,不能仅因 Modules 小于 200ms 就称已对齐。当前不新增未经用户 review 的比例硬门槛。头文件与 Modules 声明暴露不同,选定功能和实际插入必须等价,跨模式候选集合差异单列。 + +## 4. Linux 实施顺序与每阶段交付 + +### L0:固化可复跑基线,先消除 Linux 回归 + +1. 保存 `/tmp` 实验 patch、构建命令、日志与 SHA 到可追溯证据目录,避免仅依赖临时路径。正式导出仓库和 LLVM 工作树分开,既有 67 个补丁不混入临时插桩。 +2. 固定实际源 SHA、ordered patch digest、编译/链接参数、二进制/resource-dir 身份、CPU affinity/worker 数、工具链/CDB/source hash、后台索引和缓存策略。baseline 与 candidate 分别使用新建缓存,相同工作路径顺序运行;必要时交替 A/B,记录机器负载。 + 首先固定 §3.5 的全头文件/Modules 四格直接对照;先取得短样本的分段差额,再按差额决定生产优化顺序。 +3. 本地复现最新 Linux CI `37779932094` 的 third-party-import 失败:新增可构建导入后,preamble 大小前后均 `12187172`。核对实际导入可见性、诊断、generation 与断言时序,依据真实契约修实现或测试;不能仅删除“必须收缩”的断言让 CI 变绿。 +4. 固定 Qt 原始项目/CDB、mcpp `d1f1c98fa26d953e084a183a9672fc1e0ce63558` 的 UP20 输入,以及原方案 xlings 基线。GNU/MSVC/Clang 用户工程仍用自身编译器,不替换成 Clang 工程。 + +交付:Linux 正确性对照、可复跑基线 manifest 与命令;原始负例保留。出口:已知 Linux 新增回归修复或以证据明确其契约,关键 raw 语义/取消/crash canary 通过。 + +### L1:深入分解真实工作量 + +优先复用 trace-only 插桩;需要 CPU 栈或 allocation profile 时使用本机可用工具。profile 单独运行,最终延迟用无新增插桩的 release 构建。 + +| 路径 | 必须回答的问题 | 观测结果 | +|---|---|---| +| `ProjectModules.cpp` / `ModuleDependencyScanCache.*` | 谁在同一请求内重复 scan、stat/read/hash、manifest replay?为何 body edit miss? | 调用次数、字节数、正/负查询、hit/miss 原因、exclusive CPU/等待 | +| `Preamble.cpp` / `TUScheduler.cpp` | 请求等待、preamble 比较、重建、AST parse 的成本与触发条件是什么? | 文档版本与时间线、PCH reuse/rebuild/refusal 原因 | +| `ModulesBuilder.cpp` | 是否重复 provider 查询/构建/验证/复制 BMI,DAG 扇出怎样影响调度? | generation、实际任务/worker 峰值、lease/锁等待、缓存物理增长 | +| `CodeComplete.cpp` | std Sema 为何远高于 JSON?重复声明遍历、USR、过滤、排序/merge、分配各占多少? | 调用/候选工作量、CPU 栈和分配;保持候选来源与插入语义 | +| 产品与真实编辑器 | raw 改善能否传递到产品?是否存在版本等待、队列或旧回复? | 同源 payload 的 end-to-end 分段,缓存命中独立报告 | + +并测正文编辑、prefix/header 编辑、导出变化、CDB 更新、重复 no-op、首次加载和 provider 缺失。记录主进程与 scanner/worker 的 CPU、RSS 和物理缓存;逻辑 metadata 限额不代表所有物理分配已受限。 + +交付:耗时/字节/调用次数表与候选收益排序。出口:每个待优化点都有可复现成本、正确性契约和最小修改边界;不因已有 PCH 实验而跳过 Sema 分析。 + +### L2:按收益实施小步优化 + +根据 §3.5–3.6 的实际差额,本轮执行顺序为 **D 的选择性声明加载 → D 的推导指引/特殊名称剩余成本 → 按新差额排序 A/C 与候选处理 → E 的冷加载与大 DAG**。B 的 PCH 辅助实验目前净收益为负,暂停进入生产。以下 A–E 是路线标识,不代表执行优先级;不承诺所有路线都应实现。每次只加入一个可审阅生产变化,保留 baseline/candidate/消融结果;无收益或破坏正确性的候选撤回。 + +**A. 消除请求内重复扫描与验证。** 使用显式不可变的当前请求证明,绑定完整 draft、command、CDB generation、环境和完整观察输入。模块 names/textual 判定消费同一证明,避免一个请求得到 names 后又按原 full-main key 再扫一次。消费前验证证明适用性;不得跨编辑复用未验证的旧 token。保留原 key 的并发 publication 协调、取消和错误语义。 + +**B. PCH 辅助 canonical 全文扫描。** 已有前置测试及私有集成候选,尚未完成完整正确性和收益验证。只有当前 prefix 完全一致、原 canonical-prefix manifest 与实际 compiler manifest 都能独立重放、原 PCH 经 audit 不导入模块时才借用。实际 canonical scanner 仍读取当前完整正文至 EOF,判定 module role/imports,保留宏回调和真实错误。 + +- `PreambleData` 继续拥有已有 PCH;借用已计费的 immutable prefix cache entry,另为 compiler evidence 在同一个 32MiB/256 项总预算中预留容量。借用在 eviction 后仍计费,预算拒绝则回退;不能新增第二个未计费池。 +- 在 scanner 创建前准备拥有明确生命周期的 CI、完整当前 main、VFS;早期 hook 仅传必要 PCH/main 字段,保留原宏/UsePredefines/其他扫描选项,仅对齐已验证 Compatible 系统注释设置。 +- `DisablePCHOrModuleValidation=None`;不能开启 configuration mismatch 逃生通道。保留实际 compiler/PCH/BMI 内容与配置验证。 +- 独立验证 canonical prefix 的 driver/toolchain 观察和 compiler 观察。完整内容、负查询、原拼写、native alias partition 都参与证明;不能任意删除“主文件事实”。 +- 辅助 scan 生成 request-local proof;虚拟 PCH 路径/观察不进入普通 raw-FS memo。旧 PCH 只在调用方已有所有权覆盖的同步生命周期内借用。 +- prefix/header/CDB/env 变化、提供模块、证据过期/不完整、预算拒绝、PCH 不兼容/缺失/损坏等回退原 canonical 一次。取消立即退出,不把取消变成重试。 +- 必须专门验证宏状态等价性:例如 header 函数体含 `__COUNTER__`,当前正文再用 `#if __COUNTER__` 选择 import。clangd PCH 的 SkipFunctionBodies 与 canonical 全预处理可能不同,正常 PCH 校验并不足以证明等价;不等价则该路径回退或撤回,不能改宏来迁就优化。 +- 同一请求证明的创建及 names/textual/preamble 消费应统计完整 replay 次数;若每次都重复 prefix/compiler/full manifest 验证,可能吞掉扫描收益。减少重复必须保持消费时输入有效,不能直接跳过校验。 +- 该 PCH 实验验证完成前不导出正式补丁;0068 已用于独立的选择性声明加载。若公共布局变化,重建全部受影响消费者后才能运行集成二进制。 + +**C. 降低 manifest 验证成本。** 依据 L1 定位同一验证事务内的重复 open/read/hash/alias 检查和分配;使用被证明有效的同一快照,减少重复工作。不能仅凭 size+mtime 或保存计数跨事务认为输入未变;same-size/same-mtime、dirty overlay、负查询转正、CWD/路径别名必须仍能使结果失效。不得在 registry mutex 内执行文件 I/O。收益同时报告 CPU、读字节与持有内存,避免以常驻副本换隐藏的无界增长。 + +**D. Sema 与候选处理(当前第一优先级)。** 已证明主要增量在外部 namespace 声明反序列化,先实施 §3.6 的名称选择性加载。控制必须覆盖 external/module-local/TU-local 表、pending override/merged table、普通 lookup 后续完整加载、模块可见性、using/inline namespace、别名/遮蔽、重载/模板、fuzzy/空词,以及精确 source/context 与取消返回后的作用域恢复。更改 consumer virtual 接口后,干净构建必须覆盖 clangd、CIndex 与 interpreter 等受影响消费者。随后按剩余成本决定是否处理 empty-index 无效匹配/USR 生成、重复遍历、排序/merge 和分配;当前 empty-index 实验没有显著净收益,不纳入生产。USR/linkage 计算可能有缓存副作用,不能未经控制就改变顺序。保留重载、模板、成员/继承/可见性、snippet/resolve 和真实 Sema 来源;不跨 ASTContext 缓存裸 Decl 指针,不以截断合法候选换速度。更大的 BMI/AST summary 或序列化设计只有简单路径不足且证据充分时另出设计供 review。 + +**E. 冷加载与大 DAG。** 在编辑延迟收敛后分析 provider 表、单飞构建、transitive generation、BMI 校验/复制、worker 调度和失败传播;保留已实现预算、lease 和 worker 限制。先证明队列/依赖瓶颈,再改并行度;不直接加线程、放大栈或提高超时。 + +交付:每个修复对应根因、编号 patch、台账 evidence/scope/drop 条件及本地结果。上游缺陷新增归因/补偿前按 contributing skill 核对 #24;产品驱动错误在产品修复,不冒充上游问题。 + +### L3:本地 Linux 收敛与产品闭环 + +集成候选通过以下层级后才进入其他平台: + +1. 小步回归:选定现有单测与 raw 反例,覆盖内容/宏/import/role、脏缓冲、负查询、CDB/env、PCH 缺失/不兼容、alias、取消/关闭、预算拒绝和并发 publication。 +2. 探索性 Qt std/JSON 对照:真实 Sema 与实际 GCC 插入通过后才看速度;单轮只用于筛选,不当统计验收。 +3. 最终 Linux 分布:12 个既有语境分别至少 3 次独立启动、每启动 30 轮;cold/warm/edited 分开。计入错误/超时/缺候选,保留全部样本、nearest-rank p95 和缺失计数;编译选定插入并补足关键重载/snippet/resolve 边界,说明覆盖范围。 +4. 同一产品二进制只替换引擎的对照,再以最终同源 payload 跑真实 VS Code、inferred/C7、typing/import/autosave、UP20。raw 与产品缓存延迟分开,不以产品答案缓存证明 raw 改善。 +5. Linux 干净构建和导出 series 字节一致性验证;发布身份记录实际 built checkout,PR head 与 merge SHA 分列,资源文件也校验。完成候选阶段资源与恢复验证。 + +开发期间先用短控制和少量样本;只在实现稳定且有收益时运行一次完整分布。必要验证不省略,已通过检查不反复重跑。测试投入遵守此前用户要求:不超过实现时间的三分之一;若必要完整验收超预算,报告时间并调整批次/范围供 review,不降低门槛或称未执行为通过。 + +### L4:扩展到其余支持平台 + +Linux L3 通过后,用同一 LLVM pin、series digest、构建配方生成 Windows 和 ARM macOS 原生候选;不复制 Linux 对象或假定 ABI/文件系统相同。 + +- Windows:先解决有界采集后的 `module-faults` 原生失败;验证文件身份/共享模式、rename/delete、lease/锁、取消;UP12 最终同源 PDB/corpus 重放,UP13 缺失的真实输入继续补齐,不伪造 crash proof。 +- ARM macOS:验证 toolchain/SDK、路径与 VFS、生命周期、语义与请求延迟,必要的平台根因修复带本机证据。 +- 两平台分别记录本机 baseline/candidate、raw/产品、CPU/RSS/物理缓存、冷/温分布。CI 用于原生/可移植性与回归确认,不用调大门槛让慢机器掩盖问题;平台差异有证据后交用户 review。 +- 最终产品 lock/kit/包只声明 `linux-x64`、`win32-x64`、`darwin-arm64`;外部原版引擎继续支持。Intel 历史失败不再阻断,也不计作已修复。 + +## 5. 验收门槛与 review 检查点 + +| 检查点 | 必须给用户的证据 | 通过条件 | +|---|---|---| +| R0:本方案 review | Linux 优先顺序、三平台范围、候选风险与现有负例 | 用户已授权开始实现;阶段证据随实施记录 | +| R1:Linux 根因与设计 | 匹配 profile、成本表、Linux CI 反例、最小接口/失效与预算设计 | 已证明主要成本,优化不破坏真实语义与输入契约 | +| R2:Linux 性能收敛 | baseline/candidate 分布、插入、raw/产品闭环、资源及干净构建身份 | 普通/限定名 warm/edited p95≤200ms,模块成员≤300ms;真实语义/插入通过;CPU/RSS 无≥20%稳定期退化 | +| R3:PR 达到合入标准 | 最终头部所支持平台必要 CI 全绿、已知阻断修复、台账和剩余发布限制 | 向用户汇报并等待其 review 决定合入,不自动 merge | +| R4:发布资格 | 三平台不可变同源 kit/payload、真实 corpus、1000 saves、资源上限、7 次合格 nightly 与每支持平台≥2h RC soak | 达到原联合方案其余发布要求,再由用户决定发布 | + +R2 延续旧方案对约 1s 原版相同正确路径至少改善 50% 的对照要求;旧 stock 数值只作历史参考,新对照必须同工具链/输入。产品缓存命中 p95≤50ms,已有快速缓存不退化;新导出生效、导航、格式/诊断等原门槛保留,但 Intel 不再适用。 + +R3 和 R4 分开:可以在 PR 满足代码合入标准后先提交用户 review;不能把尚未完成的 nightly/soak/不可变包叫作发布通过,也不能用“发布阶段再看”隐藏已知正确性/性能失败。若某项必须作为合入条件,则在 R1 明确登记,不能临时移到发布阶段。 + +## 6. 交接与风险 + +- 不将 67 个补丁或一次 CI 全绿当成总体完成;每个 ledger 状态依据实际 root-cause/canary/适用平台提升。 +- 既有完整头部 native CI 中,`36687a9` 曾全绿;`145be1c` 的 Linux third-party-import 失败已按真实 PCH 契约补充 canary 和本地对照;最新 `d214029` 原生 CI 尚须确认,不报告引擎 PR 可合入。产品 `a432c28` Windows 稳定性失败的根因尚未闭环;`236c947` 已带有有界证据采集和三平台范围调整,需检查新结果。 +- PCH 路线主要风险是证据覆盖、别名身份、计费/eviction 生命周期和 request proof 被错误跨请求复用。前置 5 测试通过不代表这些集成风险已经消失。 +- 深度性能优化必须同时测内存、I/O、取消和冷加载;`128KiB` admission 或 manifest metadata 预算不自动限制 VFS 内部 full-buffer 分配。 +- 原始 trace-only/拒绝候选材料保留:引擎 `tests/evidence/joint66-67/{canonical-scan-attribution,directives-rejection}.json`;禁止把临时插桩或失败的 directives 模式导出为生产优化。 +- 私有 PCH 入口材料为 `/tmp/mcppls-pch-scan68-build/{prerequisite-controls.patch,prerequisite-identity.json,prerequisite-fields-narrow-final.log,integration-boundary.md}`。最终前置 diff SHA 为 `3b58dd50f3a8e2a049ae74b0263dfe231604353d91f48faeb651e0ac1c4bddb8`,测试二进制 SHA 为 `e71f4f3e4ee238270f2b0475ac517639f074db7a0f8146ef0e877b1faf815c1f`。 +- 所有新结果注明已实现/未实现、已测/未测、匹配对照/历史参考;不预报未经实测的倍数、完成百分比或交付日期。 + +## 7. 本次用户 review 核心点 + +| edited p95,匹配 3×30 | 全头文件 | Modules | 差额 | +|---|---:|---:|---:| +| 最新匹配基线67 | 180.13ms | 250.61ms | 70.48ms | +| 0069 开发候选 | 134.67ms | 144.09ms | 9.43ms | + +已完成:最新候选使 Modules edited p95 改善约 42.50%,同模式返回项编辑一致;0068 的 12 语境分布通过。未完成:0069 完整 12 语境资格、warm 剩余差额、最终构建/产品及跨平台资格。Linux 干净构建首次因磁盘写入空间不足终止,恢复后完整编译链接通过,16 lit、251 clangd 定向测试通过。AllClangUnitTests 首次启动缺少间接依赖的编译器运行库;明确设置本地运行库后,5 namespace、2 positive memo 测试及七阶段消费者探针通过。原始失败保留,这不证明分发包可迁移性。 + + +1. 平台收敛为 Linux x64、Windows x64、ARM macOS;Intel macOS 不适配、不作为验收阻塞。 +2. 先本地 Linux 全链路 profile 与最小根因修复,再其他平台;本地绝对速度不替代平台资格。 +3. 与同一项目的全头文件版本做四格匹配对照,报告差额;已定位的最大增量是导入声明反序列化,优先按名称选择性加载。推导指引与 operator 已按实际补全名称筛选;下一步完成新消费者资格并定位 warm 剩余差额,扫描/验证按剩余净收益排序;当前 PCH 辅助负收益实验不进入生产,最后处理冷加载/大 DAG。 +4. 保留真实 Sema、插入正确性、内容失效、正常 PCH/BMI 验证、取消与统一预算;普通/限定名 edited p95≤200ms 不降低。 +5. Linux 收敛后做三平台原生与产品闭环;合入达标先汇报供 review,发布长期验证单独如实跟踪。 + + +## 运算符名称筛选候选:完整 Linux 对照 + +私有源 `31c43d3a2` 在推导指引筛选之上,按实际补全 TypedText 筛选 operator 名称;consumer 谓词改为 StringRef。特别处理 `operatorco_await`,不使用其诊断显示名称 `operator co_await`。未知名称保守保留,普通查找及后续完整加载沿用原行为。全部 141 clangd 消费者和 7 相关 LLVM 对象已编译,146 CompletionTest 和 5 NamespaceLookupTest 通过;CIndex/interpreter 的新候选最终干净构建仍待完成。正式 series 仍为 68,候选未导出 0069。 + +无新增插桩的完整四格对照,每臂 3 启动×30 轮: + +| p95 | 全头文件 baseline67 | Modules baseline67 | 全头文件候选 | Modules 候选 | +|---|---:|---:|---:|---:| +| warm | 82.10ms | 173.32ms | 37.90ms | 76.16ms | +| edited | 180.13ms | 250.61ms | 134.67ms | 144.09ms | + +Modules edited 改善约 42.50%;候选两侧 edited 差距约 9.43ms(7.00%)。warm 仍差约 38.26ms,不能称所有阶段均已对齐。四臂共 744 次真实 typed Sema 全通过,各依赖模式内 186 个 baseline/candidate 回复的全部返回项编辑字段一致;跨模式候选数分别为 23 与 65,不断言候选集合相同。计时结束后的首个/末个/最慢回复抽样共 83 次实际 GCC 插入通过。 + +两次无效 Modules 计时保留并排除:第一次外部编译重叠;retry1 与本代理私有 clangd 计量同时运行,属于调度失误,编译进程监测未覆盖另一 clangd。最终采用单独 retry2;其他三个有效臂保留,计量报告结束早于 baseline-modules 开始约 37.42 秒。有效臂的 200ms 编译/ninja 采样均未观察到重叠、无错误且线程正常停止;不将其解释为整个主机绝对空闲。证据位于引擎 `tests/evidence/part2-linux/filtered-special-names-candidate/four-arm/`,包含原始无效记录与逐回复复算审计。 + +私有计量显示 `std::ve` 的 operator 选定 GetDecl 从 1,887 IDs 降到 0,推导指引保留 48 IDs;该计量与无效 retry1 重叠,只证明减少加载工作,不作延迟资格。最终同源消费者、12 语境、正确 stock 对照、产品与三平台/长期发布验收仍待完成,两个 PR 不合入。 + + +后续导出:本地 series 已新增 `0069-UP-25-selective-guide-operator-completion.patch`,69 补丁/69 台账检查通过,stabilizing;合成源提交 `499609a2a1503ea7fef404e5b72fbb2e9fa2a9f2`,series SHA `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。完整四格证据、两个无效计时和源身份已归档。独立干净目录 `/tmp/mcppls-part2-clean-special69/` 正从固定上游 tarball 应用完整 series 并重建全部消费者;当前仅构建启动,不作为通过证据。旧 0068 构建和基线保留,新候选尚未推送,PR 不合入。 + + +### 0069 干净消费者通过、正确 stock 路径与可移植包进度 + +Ubuntu24 本地干净构建已完整退出 0:16 lit、255 clangd 定向测试、5 NamespaceLookupTest、2 PositiveScanMemo 及 CLI/CIndex/interpreter 七阶段全部通过。实际二进制 SHA `80012b732be4c55a4d5df49087cb2856519f3f98116951e0ee5196e164607088`,源 `4b26052750b46f7fbfaceb5bd3c7c16b0d01f2ca`,series digest 保持 `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。12 语境短控制的 48 次检查与 52 次实际选定 GCC 插入通过,全部带数值门槛的短控制通过;这不是各 3×30 的完整分布。 + +stock 显式 `completion-parse=always` 的冷请求仍返回空结果,真实 Sema 失败;后续三次通过。日志观察到 preamble 先构建、std 模块随后发布,完整根因尚未闭环,不能只归因 auto 文本回退。该负例保留,不当作正确性能基线。同输入候选冷控制四次真实 Sema、四次实际 native 插入通过。 + +新增显式 AST-ready-only 测量模式,先等 documentSymbol,再请求 warm/edited,报告明确 cold completion 未请求;默认模式仍记录冷请求失败。阶段/草稿与资源观察不进入延迟计时的控制通过。相同 source/CDB/Clang/libc++ 输入的短 stock/candidate/stock 对照共 9 次真实 Sema、9 次实际 native 插入通过,各回复全部 18 项的关键字段及实际编辑一致;edited 为 79.71/14.49/82.97ms。该短样本支持继续完整验证,不作正式 50% 门槛结论;stock 冷失败单列,没有改写为通过。 + +资源探针增加补全请求前后的直接 CPU/RSS 快照,计量读取在请求计时之外;普通/延后回复与刻意慢观察器控制通过,共享 replay 四项 soak 控制通过。该工具能界定主进程稳定期 CPU 增量;子进程和硬内存上限仍待另验,不以工具测试替代资源资格。 + +可移植 Linux 包已开始在本地缓存的 Ubuntu20.04.6/glibc2.31/Clang12/CMake3.31 镜像中构建,镜像 SHA `96ddf5cedf5352ca5c4f1608185f4ddc885ca4ee51ff0a4ca461779e429dcb29`。使用同一只读应用源、全 69 series,关闭网络,保存对象/日志,具有明确总期限和容器清理。该构建尚未完成;完整最终 12 语境、stock 分布、资源和产品验收将绑定可移植包的最终字节,不将 Ubuntu24 开发构建代替下限分发资格。证据归档引擎 `tests/evidence/part2-linux/clean-selective69/`,本地提交 `fcce580`。两个 PR 不合入,新工作尚未推送。 + + +### Ubuntu20 最终包通过,最终字节验收开始 + +`/tmp/mcppls-part2-floor69/progress.json` 已记录完整流程退出 0:离线 Ubuntu20.04.6/glibc2.31/Clang12 全量构建,16 lit、255 clangd 定向、5 NamespaceLookup、2 PositiveScanMemo 及 CLI/CIndex/interpreter 七阶段均通过,打包成功。最终 stripped 二进制 SHA `b7eba8bfdd1c26ff93ba4fba53678916a9f8d3d4e79ce3cf1a97375a07593e8f`,fork `affe666292c6b53b842df1d217a811bdfc85e47c`、源 `4b26052750b46f7fbfaceb5bd3c7c16b0d01f2ca`、series `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。实际 glibc2.31 运行检测无问题,最高 GLIBC 符号要求 2.29,无动态 libstdc++ 依赖。该 floor 检查验证依赖解析与启动,不声称产品全工作流已在 Ubuntu20 运行。 + +最终包的 12 语境短控制已启动,采用匹配邻接 resource headers、fresh CDB/cache,检查实际包 SHA 和 floor verdict。native AST-ready stock/candidate/stock 完整 3×30 脚本已准备,逐请求核对 phase/draft/全部返回项关键编辑字段;计时全部结束后按每启动/阶段首个、末个、最慢回复选择实际 native 编译。CPU/RSS 将使用新边界计量复算主进程稳定窗口,保留 CPU tick 不确定区间,不代替子进程/硬内存验收。当前最终分布、资源与产品验收仍未通过;新工作未推送,两个 PR 不合入。 + + +最终 stripped 包短控制全部退出 0:12 语境共 48 次请求检查(其中 36 次要求 typed Sema、4 次 include、8 次空负例),52 次选定 GCC 插入全部通过,所有带数值预算的 warm/edited 短样本通过。native candidate 独立冷控制共 4 次真实 Sema、4 次 native 插入通过。匹配 AST-ready stock/candidate/stock 短对照 edited 为 86.88/17.49/90.03ms,9 次真实 Sema、9 次 native 插入、全部返回项编辑字段一致。零观察到的 compiler/ninja overlap,采样无错误且停止。短对照通过后已启动最终包 native AST-ready 3×30 完整 A/B/A;完整 12 语境分布仍待顺序运行。上述 stock 对照明确不请求 cold,不改写既有 stock 冷空回复失败。 + + +最终包的 native std AST-ready 匹配完整分布已退出 0:每臂 3 次启动×30 轮,stock-before/candidate/stock-after 各 183 次真实 typed Sema,共 549 次;全部返回项关键字段和逐请求 draft/phase 一致,49 次选定实际 native 插入通过(16/17/16)。edited p95 为 89.234/22.159/89.194ms,两侧均改善约 75.16%,满足该正确稳定路径 ≥50% 改善门槛;明确不包含 stock 冷请求,既有失败不改写。 + +主进程稳定资源窗口 CPU 保守区间为 before 23,240–23,360ms、candidate 13,100–13,220ms、after 23,250–23,370ms;采用保守的候选 CPU 上界/基线 CPU 下界,比分别约 0.56885/0.56860。每臂三次启动中最大观测 RSS p95 为 478,848/277,300/483,740KiB,比分别约 0.57910/0.57324;该 native 场景主进程未观察到 20% 退化,不外推所有场景、子进程或硬内存预算。完整 Qt 12 语境 3×30 正顺序运行,暂未有最终 verdict。floor 构建和短控制/native 分布归档 `tests/evidence/part2-linux/portable-selective69/`;最终产品、三平台和长期资格仍待完成。 + + +最终 Qt 完整分布已发现性能负例:first-column 全部 186 次语义请求和选定插入通过,但 edited p95 `201.221592ms`,超过 200ms;warm p95 `127.374283ms`。保留原报告,不提高门槛、不重跑挑选较快结果。完整矩阵仍在顺序运行。源码核查发现当前选择性外部名称加载只接入 qualified-id 的 DeclContext 路径;expression 的 Scope 查找仍走普通 LookupVisibleDecls,且选择性加载限定 NamespaceDecl、不包括 TU。这是下一步归因线索,尚未证明此次超标的 exclusive 根因。独立 first-column/ordinary trace 脚本已准备,须等完整矩阵结束且确认没有另一 clangd/编译进程才启动;trace 只作归因、不替代分布。 + + +### 最终 Qt 完整矩阵失败与 Scope/TU 修复候选 + +Ubuntu20 最终包的 12×3×30 分布实际终止退出 1:2232 次请求检查(1674 typed-Sema 要求、186 include、372 空负例)全部通过,251 次选定真实 GCC 插入通过;两个 edited 性能预算失败为 first-column 201.221592ms、ordinary 210.724679ms。std-qualified warm/edited p95 83.982920/156.240325ms,通过 200ms。原始全量报告、terminal verdict、插入与负载记录已归档 `portable-selective69`,不挑选更快重跑替代失败。 + +最终包独立 1×3 native trace(不是资格分布)显示首列/普通补全的语义执行约 75–80ms,edited 模块验证约 84–96ms;populate/merge 嵌套在语义执行内,不能相加。独立私有单对象计量确认每请求 TU 枚举 10,488 个声明,线程 CPU 中位枚举约 29.22/28.90ms、消费约 6.19/6.08ms,未启用名称筛选。该计量是 GCC 开发构建,只归因工作量,不将 CPU 数值当作最终 Clang12 包的净延迟收益。源、编译/链接配方和原报告归档 `unqualified-visible-lookup-profile69`。 + +私有源 `/dev/shm/mcppls-part2-unqualified70` 已将 completion 专用借用谓词接入普通名字/表达式的 Scope 查找,并允许 C++ TU 外部名称选择性加载;局部/using/隐藏/可见性遍历和普通 lookup 保留。只新增非 virtual Sema 方法,不改变类布局/已有 virtual ABI;两个 Sema 对象和 completion tests 重建,复用未变的69消费者。两项新增 PCH/文本遮蔽、using、inline namespace、重载/编辑字段与 TU 后续普通加载控制,以及146项既有 CompletionTest 通过。私有候选 SHA `b113434672d4a28ab600737e3acd3c5463618d306ff3b02c086a2f6a95e1669e`,最终全量干净构建仍待证明。 + +首列默认 top100 的短 A/B/A edited 为 182.78/156.07/197.59ms,但全部返回项对照失败,不能作为合格收益证据;前后同基线也不同,实际出现 std/chrono 等索引候选在截断边界交换,全部 typed Sema 和核心目标仍通过。另加不限 engine 返回数量且等待索引发布/正匹配的正确性短对照,三臂实际返回项和编辑字段一致(cold 90,stable 162/164),但初次工具错误要求 `isIncomplete=false`;原失败保留,改为离线核对实际字段和两侧相同的 legacy incomplete 标记,再完成实际插入,不重跑挑数值。该不限数量控制只证明实际返回答案一致性,不能宣称所有索引候选完全返回或默认工作负载性能已验收。候选尚未导出0070/推送,两个 PR 不合入。 + + +### 0070 正式导出与最终干净构建 + +Scope/TU 源提交 `3510dc8091144c9f6ed0a573a3a7931b9c10b32b` 已干净保存,合成导出 `441be72d5ca0274541bc1a1ad601425eb42c2887`、patch SHA `687c16bfc431b87c82eae34b1d86e14a447fcb7106559c61481649b1757df27e`。正式 series 为70补丁/70台账,SHA `710c2c8e380defe1be146a8a66f44d1c5e9216a6ebe4fde510372b516e22f424`,stabilizing;引擎本地提交 `5727d43`,未推送。默认限制且明确等待 std 索引发布/实际正匹配的首列与普通短 A/B/A 各1×5:edited p95 分别181.596/168.870/177.618ms与172.074/157.217/178.541ms,72次真实Sema、39次选定实际GCC插入通过。各默认返回项/编辑字段属于已验证的不限engine返回数量参考集合;不宣称top100截断集合跨进程完全相同。不限数量控制另有24次Sema/24次实际插入,原始错误完整标记断言和默认未稳定对照失败保留。 + +新的完整70series已从固定并验SHA的缓存tarball独立应用,源HEAD `100a1273fe05d674e67712b05343b29f19f8075b`。全tracked树逐路径mode/blob核对,与开发源只差`.mcppls-clangd-fetched-`这一fetch metadata marker,全部源码相同。源/对象分别位于`/dev/shm/mcppls-part2-floor70-source`、`/dev/shm/mcppls-part2-floor70-build`;最终包和日志保留在`/tmp/mcppls-part2-floor70`。首次启动在2GiB root预检处拒绝,没有启动Docker/编译;前次完整包约70.48MB,按仅包/日志落root重新核算为1GiB预留(超过前包4倍),另保留8GiB shared-memory预检后已启动离线Ubuntu20/glibc2.31/Clang12全量构建。该构建实际在编译中,尚未通过消费者/包/floor测试。旧69的源码、构建、二项性能失败及全部负例保留,不以开发短样本替代最终70验收。 + +证据:`portable-selective69`(完整最终69分布/负例)、`unqualified-visible-lookup-profile69`(工作量归因)、`unqualified-visible-candidate70`(候选源/编译/全部实验及修正)、`selective-unqualified-export70`(导出身份)。最终70分布、稳定资源、产品/kit/payload、VS Code、其他支持平台和长期发布门槛仍待完成;两个PR不合入。 + + +### 最终70产品验证准备与测量边界 + +完整70 Ubuntu20构建仍在运行,已观察到3859/4744;实际Docker/Ninja进程与原会话15745均存活,未启动性能测试、未重启构建。最终inferred产品脚本增加构建complete、实际floor problems为空、whole70 series摘要及最终二进制SHA检查,编译活动会阻止启动。脚本只完成语法检查,尚未有产品运行结果。 + +另准备固定inferred模块工程的std::vector产品补全短控制,复用已有conformance的completion-baseline和latency能力,分别观察编辑后产品/直接同引擎延迟及不改草稿的warm延迟。准备位于`/tmp/mcppls-part2-floor70/qualification/product-completion/`;`product-preparation-manifest.json`记录各脚本、fixture和命令的身份。产品控制须在独占raw计时结束后顺序运行。现有runner会在产品空闲时另启动direct clangd,因此该控制不代替独占raw性能资格;实际产品worker/index参数仍须核对。 + +能力审计确认:completion-baseline检查产品空答与engineShare,但不逐项核对直接引擎的实际答案/插入;不修改草稿的重复请求只能称warm请求,不能据此证明产品答案缓存命中。最终raw语义/选定插入仍独立验收;完整同产品只替换引擎A/B/A、显式缓存命中来源及50ms门槛、最终同源kit/payload、过程树资源、真实编辑器与长期资格均未完成。该准备不改变既有负例或发布门槛,两个PR不合入。 + + +存储前置检查发现root仅约2GiB空余,而旧69验收目录apparent bytes为2,170,635,769、旧四格为413,004,426;不能直接在root运行新一轮完整验收。新70准备目录已迁至`/dev/shm/mcppls-part2-floor70-qualification`,原`/tmp/.../qualification`通过symlink保持全部命令路径;搬迁时八个脚本字节摘要相同,此后统一加入至少6GiB可用空间前置检查并通过语法解析,产品准备manifest同步更新。搬迁后共享内存可用29,069,778,944 bytes;只处理新准备目录,旧证据/基线/构建不变。`qualification-storage.json`保存实测容量和路径。该RAM暂存必须在独占计时结束后归档至持久仓库;计时期间不压缩,也不将暂存称发布证据。 + + +### 最终70干净包与短控制通过 + +原会话15745实际终止退出0:完整4744构建配方、16 lit、257 clangd定向测试、5 NamespaceLookup、2 PositiveScanMemo、CLI/CIndex/interpreter七阶段通过,打包成功。最终stripped clangd SHA `5213fa91c24f93f9d3a6f625f4a0699f4ea93892063a7032b2b9ef34b13a179e`,build binary SHA `e41750e87b38c677ccbac57e58004e62ee7f3856fa16949379361e183e7e4ad2`,fork `c0efe0ce04a33faa185b044103f54644765f6053`,source `100a1273fe05d674e67712b05343b29f19f8075b`,series仍`710c2c8e380defe1be146a8a66f44d1c5e9216a6ebe4fde510372b516e22f424`。实际glibc2.31检查problems为空,最高GLIBC符号2.29,无动态libstdc++依赖;仅证明依赖解析/启动,不代替Ubuntu20全产品工作流。303 resource headers记录摘要。 + +计时监测补齐带版本号的Clang/GCC和native frontend进程;现场控制识别六个clang++-12及Ninja。新增简单clangd进程数监测首次误拒冷控制:四次Sema全部通过,但主clangd与fork子进程被当作两实例,实际退出1且未进入插入阶段。原驱动/报告/terminal记录保留。修正为记录父PID、process group和start ticks,按独立进程组判重叠;真实受控父子/独立组/清理控制通过。随后独立冷控制实际观察子PID父亲为主clangd且同组,4次真实Sema、4次实际native插入通过。该新控制改变监测方法,不改写原结果,也不扩大历史只采编译进程的证明范围。 + +最终包AST-ready短stock/candidate/stock共9次真实Sema、9次实际native插入,各返回项关键编辑字段一致;edited样本79.525/19.272/84.279ms。stock冷请求未请求,既有冷失败保留;短样本不作正式50%分布结论。零观察到的编译/独立engine组重叠,采样无错误并停止。最终完整12语境、native分布、四格及产品仍待顺序验证。当前包/日志/短控制/原监测负例与准备材料已持久归档引擎`tests/evidence/part2-linux/portable-selective70/`,不得将RAM暂存当作持久证据。两个PR不合入。 + + +最终70包12语境短控制会话93129实际退出0:48次请求检查(36 typed-Sema要求、4 include、8空负例),52次选定真实GCC插入全部通过,所有带数值预算的warm/edited短样本通过。first-column edited164.836ms、ordinary161.320ms、std-qualified156.221ms;零观察到编译及独立clangd进程组重叠、无采样错误且采样线程停止。按各phase/启动首个/末个/最慢选定插入,不代表全部回复逐项编译。材料持久归档portable-selective70并复核manifest;下一步完整12×3×30,短样本不替代正式分布。 + + +### 最终70完整矩阵逐语境通过,原调度失败保留 + +原完整矩阵会话1321实际退出1:11个语境各3启动×30轮全部完成且各自计时的编译/独立engine组采样无重叠;启动最后string前preflight观察Ninja/GCC/cc1plus,尚未开始该语境便停止。原terminal、阻塞PID、11项原报告保留;后续这些PID已结束,不作其工程/归属猜测。仅补跑此前未启动的string,同包/输入/3×30,会话16026实际退出0,不重跑已通过的11项、不将原调用写为退出0。 + +离线组合审计逐回复检查3启动、cold3/warm93/edited90、draft编辑输入一致、真实Sema/索引来源、空负例、资源采样与选定实际插入的精确首个/末个/最慢去重集合。共2232请求检查:1674要求typed Sema、186 include、372空负例;255次选定GCC插入全部退出0,proof CDB摘要一致,所有适用warm/edited预算通过。首列warm/edited p95为102.757/175.023ms,ordinary98.476/175.450ms,std-qualified81.146/157.616ms,均低于200ms。审计首次错误固定插入数为旧69的251,退出1负例保留;纠正为实际选择集合后通过,不重新计时或改变答案。 + +以上证明每语境完整分布覆盖与预算,不声称原整调用退出0,不代替CPU/RSS全部过程树、stock完整改善分布、四格header差额、产品/VS Code/三平台/长期发布资格。证据持久归档portable-selective70,包含两个调用、原失败、补跑、审计代码/数据与复核manifest;两个PR不合入。 + + +### 最终70 native受外部编译干扰,产品语义独立通过 + +完整native stock/candidate/stock会话19456实际退出1:before及candidate各3×30的183次Sema与各自负载记录通过,edited p95为88.969/23.522ms;after计时观察到编译进程重叠,timings无资格,原报告保留,未进入选定实际插入阶段。这不是正式完整A/B/A改善/资源结论。只读五秒进程归属观察捕获另一终端Claude→bash→mcpp→Ninja链,工作目录`/home/speak/workspace/openxlings/xlings`;未干预该会话。准备只替换无效after臂、复用未改的有效before/candidate并记录原报告SHA;尚未启动,须等稳定空闲窗口。 + +独立正确性变体保留最终build/floor/series/SHA检查,排除所有延迟/资源数字。最终70 engine、固定产品二进制与已安装stock kit的inferred会话83523实际退出0,initialize及17项fixture检查通过,含C7 greet2导出后补全、定义/引用/语义token。离线审计首次把initialize混入17项固定计数而退出1;原计数错误保留,按scenario精确ID集合与initialize分别核对通过,不重跑服务器。该结果不当作性能、≤5s新导出或同源不可变payload证明。原native失败/三个报告、归属观察、替换准备和产品检查已持久归档portable-selective70并复核manifest;完整native、四格、产品性能及其他发布门槛未完成,两个PR不合入。 + + +### 最终70真实VS Code C7正确性通过 + +外部xlings编译仍活跃时,不启动任何性能补测;继续独立正确性。现有VS Code modules suite缺少C7新增导出用例,已新增:保存greet.cppm中的greet2定义,真实editor completion provider必须返回该名字且Function kind,finally恢复main和module文本并保存;清理主文件失败也会执行模块恢复。TypeScript编译通过。 + +使用本机已安装VS Code1.108.0、独立工作区/user-data/cache、开发extension、最终70 engine SHA5213fa91…、固定产品SHA70156817…和stock kit。首轮会话1037退出1:新增断言错误要求label包含greet2(,实际VS Code已返回Function greet2,但()位于独立label.detail。保留原测试源/输出/失败及恢复后的工作区hash核对;修正为名字和Function kind后,会话32960实际退出0,9项模块测试全部通过(含C7、定义/hover/references、补全、无打断UI、日志等级),runner工作区unchanged检查通过。 + +所有时间/资源数字始终排除,不以此证明≤5s新导出、性能、autosave/1000saves、同源VSIX/payload或release。持久证据`tests/evidence/vscode-modules-final70/`包含两次实际运行、原断言失败、源/产物身份、日志、进程清理及manifest复核。native after和四格性能仍待无编译窗口;两个PR不合入。 + + +### 最终70 native完整有效三臂通过 + +15秒采样未观察编译/clangd后,仅补测此前受干扰的after臂,会话50007实际退出0;复用未改的原before/candidate,保留原after无效计时及原调用退出1。有效三臂各3启动×30轮AST-ready,共549次真实typed Sema,phase/draft与全部实际返回项的六个关键编辑字段一致;按首个/末个/最慢实际去重选定48次native插入,全部编译通过。对照明确不请求stock cold,既有冷失败不改写。 + +edited p95 before/candidate/after为88.969472/23.522489/87.982354ms,改善分别73.561%/73.265%,通过该正确稳定路径≥50%要求。主进程稳定CPU保守比0.57076/0.57863、各启动最大观测RSS p95比0.54694/0.54768,未观察到20%退化;不代替过程树或硬内存预算。独立审计检查逐回复真实Sema、三启动/阶段数、负载采样与实际选定回复集合;成功材料、原失败/复用出处/报告SHA均持久归档portable-selective70并复核manifest。下一步最终包四格header/modules对照,其他产品/平台/长期门槛仍待完成。 + + +### 最终70四格对照通过,warm差额继续归因 + +会话25963实际退出0;四臂各3×30,共744次typed Sema、80次实际选定GCC插入通过,同依赖模式内的所有实际返回项六个关键编辑字段与逐请求phase/draft一致。warm p95 baseline headers/modules为80.659/173.900ms,final70 headers/modules为38.752/82.453ms;edited为179.620/250.525ms与135.766/152.369ms。最终Modules相对baseline67 warm改善52.586%、edited39.180%;候选两模式edited差16.603ms(12.229%)、warm差43.701ms(2.128倍),不能称全部阶段已对齐。baseline67是GCC开发构建,final70是Clang12 floor构建,producer/LLVM pin/resource headers匹配但构建编译器不同,不把全部差额排他归因于代码。 + +主进程稳定CPU保守比headers0.80110、modules0.72055;最大观测RSS p95比0.90563/0.95158,无观察到20%退化,不含过程树和硬上限。逐回复/插入精确选择/负载与原字段检查的审计、四臂原数据和终止记录持久归档portable-selective70。下一步仅用最终70字节、相同header/modules drafts做独立1×3 trace归因,保留cold/索引稳定条件;trace不作为分布或收益资格,生产源码/二进制未改。 + +### warm细分归因:排除实例创建、字符串与清理的直接主因 + +最终70包独立1×3 trace会话47730退出0,16次真实Sema且采样未观察编译/独立engine组重叠。单个warm对照中validation差约2ms,semantic差约23ms,另有约23ms未标记时间;不能把未标记时间直接称为实例准备。候选数headers23/modules65,答案暴露范围不同,不能删有效答案换取对齐。 + +独立GCC70分析构建只替换CodeComplete.cpp计时对象、复用相同70 ABI消费者,不改变最终floor包。两轮细分会话65773/71226均退出0,各16次Sema通过;无采样编译/独立engine组重叠。第二轮warm span总和中位数(四个请求,非正式分布):headers/modules实例准备0.0368/0.0403ms、BeginSourceFile1.2768/1.2068ms、EndSourceFile0.0760/1.2226ms、保持原对象销毁顺序的清理区间0.4211/1.0927ms。这些不是约20ms以上未标记差额的直接主因;先前清理假说未获支持,保留原结果,继续定位具体未覆盖区间。 + +结果组装headers/modules0.1944/7.8295ms,候选组装0.1128/7.6948ms;其中候选completion string仅0.0190/0.0542ms,最终Builder.build仅0.0069/0.0192ms,文档SymbolID0.0180/0.0309ms。剩余热点在builder构造/add路径,而不能笼统称字符串生成或SymbolID。下一步细分构造中的scope打印、文档获取/格式化、include准备,以及Sema跨度内的未覆盖区间。所有span嵌套不可相加;GCC私有分析构建不是Clang12最终包,不使用这些短计时作为发布收益资格。原trace、两个分析源码/配方、报告、独立审计和terminal均持久归档portable-selective70并复核manifest。生产代码和发布二进制未改,两个PR不合入,release目标仍未完成。 + +继续核对第二轮原trace时,未覆盖差额已明确为独立的`Completion textual validation`:一个warm请求21.430ms,四个warm span总和中位数20.5548ms;headers没有此span。它位于module validation结束后、prepareCompilerInstance之前,执行`getTextualPreambleInputs`再与旧TextualModuleInputs比较。原审计列表漏列这个新增span,已补列并重新离线计算,无计时重跑。下一步直接分析该验证的输入依赖、warm重复计算与安全复用条件;不能绕过真实文本/宏/编译选项变化的失效检查。归档移除本轮误带入的运行时`.cache`副本,原RAM运行数据保留,trace/报告/输入CDB及manifest仍完整。 + +第三轮私有细分会话17019退出0,16次真实Sema及负载采样通过。四warm中位数:Modules候选组装7.9384ms、builder构造7.6551ms、initial add7.4942ms,其中文档获取/格式化7.3941ms;qualified scope0.0317ms、completion string0.0558ms。headers对应文档0.0082ms。因此候选构造主因已收敛到文档路径,不能称为候选数比例或scope打印本身。clang getCompletionComment会走ASTContext.getRawCommentForAnyRedecl,并可能调用ExternalSource.ReadComments;需进一步确认加载代价,保留模块/本地文档与annotation,不靠删文档获得收益。 + +文本验证源码同时揭示同一补全请求的重复工作:getRequiredModuleNames先canonical scan/manifest replay完整draft,getTextualPreambleInputs再验证完整draft的ordinary TU角色,最后验证prefix无import;相同完整draft被单独验证两次。优化设计为单次完整scan返回required names与ordinary-role proof,再独立验证prefix;backend不支持联合证明时继续保守回退。仅请求内共享已验证结果,不跨请求跳过内容/环境/编译参数/宏/负依赖验证;若改ProjectModules虚接口,必须完整重编所有消费者,私有旧ABI复用不可作为资格。该设计尚未实施生产代码。第三轮源码/构建配方/原trace/报告/terminal与独立审计均持久归档;release目标仍未完成,两个PR不合入。 + +### 0071联合验证已实现,私有语义和短A/B/A通过 + +独立候选源码commit`0ea8fbc5f46c38e9abcde6ef2b360829fdbc1d0d`实现请求内联合验证:builtin canonical scanner一次返回required modules和ordinary-TU证明,prefix仍独立验证ImportFree;unknown backend保留既有保守查询。结果只保留在此次completion调用中,无跨请求答案缓存,不省略内容/文件操作/命令/CDB/环境/负查找验证。新增接口放在既有virtual接口末尾,但仍要求重编所有消费者。 + +私有构建会话78393退出0,141个既有clangd消费者全部重新编译、两目标链接成功,复用未改且兼容的LLVM/Sema70对象;不是全量clean portable build。新测试覆盖warm只重放一次full draft加一次prefix、body draft变更、module-unit角色拒绝、command不匹配与无import。会话42682退出0,154项测试通过(148项completion及6项textual/joint controls);测试耗时和资源不作性能资格。 + +同GCC配方的headers/modules短A/B/A会话69028退出0,各1启动×3轮,共48次真实typed Sema;每模式before/candidate/after的全部实际返回项编辑字段与documentation一致。零采样编译/独立clangd组重叠、采样无错且已停止;计时全部结束后32次首/末/最慢实际去重GCC插入全部编译通过。Modules warm p95为70.534/61.332/75.116ms,edited141.666/133.207/137.271ms(准确原值以报告为准);减少一次full replay已获得实测收益,但短样本不替代正式分布或final70 Clang12包的资格。header短样本warm39.106/43.243/30.918ms,存在波动,不据此宣布headers退化或Modules已对齐。 + +export commit`8329943aace616c54b8f7cfda46221d7950a43e0`仅六个源码/测试文件,0071 patch SHA`08108c13c835c9b22bbebcbd09c33ddcc0df16fb549e86b85515e0f033c9094b`;在完整floor70源码上apply --check通过,ledger检查71 patches/71 rows通过,状态stabilizing。证据`tests/evidence/part2-linux/joint-completion-inputs71/`持久保存全部consumer日志/配方、源码身份、154测试原日志、六臂报告与32插入、可对压缩归档重放的独立审计,manifest复核。最终70证据仍只证明原字节;0071全量portable rebuild及正式矩阵/native/four格/product/资源/三平台/长期release资格未完成。下一步完成文档热点分析,再决定是否一并进入新的完整生产构建。两个PR不合入、暂未push,目标保持完整。 + +### 文档查询已确认批量加载;顺序插入小实验不扩大 + +0071私有文档分层trace会话76507退出0,16次Sema通过。一个warm请求的64次raw lookup总计7.827ms,首个不返回comment的查询单独7.794ms;annotations/parse均约十几微秒。随后独立ASTReader计数会话21978退出0,16次Sema通过:Modules每次大加载75840个RawComment、3个cursors,12次非零加载中位7.6445ms(含AST更新等调用,不全是completion);headers不读取RawComment记录。四个warm中的raw lookup总和中位7.7745815ms。证实热点是首次查询触发批量反序列化,而非格式化或全部候选各自昂贵。仍需保留真实模块文档,不能省掉加载冒充收益。 + +私有ordered map hint实验源码`c0797b7a4`仅在ReadComments中利用writer已有的文件内source order;map在重复/非单调输入下仍保留原键值语义,不改ABI/布局/BMI或引入缓存。会话50680两对象构建与三个链接成功;会话29045退出0,168个completion/文档测试通过。单独profile会话98698退出0,16次Sema通过,读取同样75840记录,四warm raw lookup中位7.032608ms,约减少0.742ms。无插桩私有短A/B/A会话66772退出0,48次真实Sema与35次选定GCC插入通过,全部实际返回编辑字段和documentation一致;但host波动可见,Modules edited没有稳定净收益。因此停止扩大该实验,保留在私有分支,不导出生产0072;正式series仍为71。 + +两次分析构建准备错误已保留:CodeCompletionStrings实际来自静态archive,ASTReader旧私有对象有completion-spelling别名。原脚本假设对象名而assert失败,编译成功后因缺link recipe退出1;修正配方后仅重link,原失败不改写。后续性能运行开始前所有编译/链接已实际终止。上述三profile、原源码/配方/negative terminal、ordered experiment源与168测试、短六臂/35插入、独立可重放audit/manifest均持久归档`tests/evidence/part2-linux/documentation-replay-profile71/`。 + +### 候选数量差异的解释修正:构造函数组合重复三次 + +逐项核对0071短控制的一个settled warm回复,headers23项、Modules65项在label/kind/newText/insertTextFormat上具有完全相同的23种组合:两类class各一次,21个constructor组合在Modules中各重复三次。此前将数量差异直接解释为标准库暴露范围不同,对这个请求缺乏证据,现明确修正;本对照仍有宏/行号/文档等差异,不能据这四字段证明整个API或Decl身份等价。 + +下一步直接追踪ResultBuilder::MaybeAddConstructorResults的调用次数、Record与Ctor canonical身份、限定符/可见性/优先级与声明来源,确认重复发生在class处理还是constructor lookup。仅在证明同一语义结果被重复生成后修生成路径;不在产品层截断答案,不按显示文本盲目去重,保留真正不同的重载、模板与annotation/documentation。正式0071完整生产构建、分布、产品、资源和三平台/长期资格仍未完成,两个PR不合入。 + +### 0072已确认并修正同一canonical构造函数重复生成 + +私有声明身份profile会话28328退出0,headers/modules共16次typed Sema,各模式16次构造函数展开。每次vector展开,headers为13条记录/13个canonical,Modules为39条记录/同样13个canonical、每个三次;_Vector_base分别为8/8和24/8。每个class只展开一次,重复来自constructor lookup中的重声明记录。身份只在同一次展开内比较,不跨请求比较指针;profile不作性能资格。 + +0072在MaybeAddConstructorResults的一次展开内以canonical Decl归并,保留后遇到声明的细节,与普通completion的处理一致;不同普通/模板构造函数仍保留。没有显示文本筛选、结果截断、跨请求缓存、公共接口/布局或BMI格式变化,lookup本身仍需加载记录。候选源`788d49b9a62bb3d87eedcdeeaf46e3efa62a1c20`、export源`c7be7d78277f34d280260658077ef21653e3ce29`两文件字节一致;patch SHA`f43ba0fe80d6dac66de1d58ed0284124a6ddeed5785303e1f1013a6e740282c9`,72 patches/72 rows台账通过,状态仍stabilizing。顺序注释插入实验未纳入series。 + +新增真实模块回归ConstructorsFromSharedHeaderModulesAreUnique:两个模块global fragment与importer包含同一类模板header,包含普通及函数模板三个构造重载。旧71 Sema配新测试实际返回9条,baseline fixture退出1;新72返回3条,candidate fixture退出0。另169项既有completion/documentation/constructor signature测试通过,测试时间与资源全部排除。 + +私有短headers/modules A/B/A会话87948退出0,各1启动×3轮,共48次真实typed Sema、33次选定真实GCC插入全部通过。Modules返回65→23,仅消除canonical重声明的多重出现,全部不同编辑字段组合与documentation保留;headers完整23项multiset不变,before/after完整multiset一致。不宣称旧65项与新23项multiset相同。两二进制在同一数据盘,采样未观察编译/独立engine组重叠,无采样错误且已停止。Modules warm短p95约61.52/56.82/57.55ms,edited129.52/135.84/134.67ms,仍存在波动,不能据此声称稳定端到端收益或完整对齐。证据持久归档引擎`tests/evidence/part2-linux/canonical-constructor-completion72/`,含原profile编译负例、声明身份、baseline失败/new通过、169测试、六臂原报告、33插入和可重放audit。 + +### 完整72源准备通过,挂载启动失败已定位并独立重试 + +从校验过的pin tarball离线准备全72系列,source会话6279退出0;完整tracked tree与上述私有72候选相比仅fetch metadata不同,生产源码全部一致。新source HEAD`82cdc7777e9dec4712b5913a8cfd31ea3634b99b`,whole-series SHA`b53e91d831b3b45944d7bc2904145221497333dca2e890e75e7c5cfc3ed3b7df`。root仅约377MiB空余,保留旧材料,新输出放`/home/data_disk/codex-mcppls-part2-builds/portable72`,source/objects仍在共享内存。 + +首次floor72调用实际退出126:Docker在挂载`/tmp/mcppls-part2-floor72`符号链接时stat permission denied,容器未启动、无编译。原run.log/progress.json/command.json保留。两个只读挂载控制分别验证真实数据盘路径和source路径均可成功;不修改目录权限或Docker全局配置。retry1只将bind source解析为真实路径,单独保存命令、日志、progress与container ID。会话26699已实际启动Ubuntu20/Clang12/Ninja全4744配方;构建期间暂停所有延迟测量,不能将running状态称为构建通过。 + +下一步基于完整72最终包的实际SHA、resource headers、source/series和floor检查重建资格身份,先做语义短控制,再执行最终字节完整矩阵/native/header对照及产品闭环。70的成功结果仅证明70字节;71/72私有短控制不替代完整干净构建、最终分布、过程树资源、同源payload、三平台或长期release门槛。两个PR不合入,目标保持完整。 + +最终72 Qt短控制和3×30完整矩阵驱动已准备在新`floor72/qualification`目录,仅通过AST语法检查、未运行引擎。共用identity前置检查要求retry1实际complete、portability problems为空、精确source/fork/pin/series、包内声明SHA与实际二进制相符,并记录全部resource headers摘要;保存preparation manifest。原70驱动/结果保持不变。新identity检查在任何engine测量前执行,构建未完成时不能运行资格。完整矩阵的逐回复审计、native和header对照还需按72实际产物继续准备;不能把准备脚本称为验收通过。 + +### 最终72验收准备补齐逐回复审计与匹配基线 + +完整12语境逐回复/输入/选定插入集合/负载审计、native 3×30 stock/candidate/stock与header/modules四格驱动已准备,均仅AST语法检查。新完整矩阵审计要求12个语境实际完成,不沿用70的“11项加string补跑”历史分支。四个驱动在当前构建仍running时实际执行前置拒绝,均退出1且包含明确build未完成原因,未启动engine、计时、插入编译或创建结果目录;negative记录单独保存。这是检查保护有效,不是性能验收。 + +四格基线从67 GCC开发构建改为已验收的70 Clang12 Ubuntu20包,使新增71/72与70采用相同构建配方;旧67收益证据不变。最终70 clangd和stock clangd分别复制到新qualification数据盘,逐字节摘要核对为`5213fa91c24f93f9d3a6f625f4a0699f4ea93892063a7032b2b9ef34b13a179e`与`c52547480ebac0f2887bb70e34bdfb54a0841d6bc84881c21e66de81c1bf2b0b`,原文件/包保持不变。native原版构建配方不据此称相同,但实际baseline字节、资源头、输入与存储条件固定。 + +四格语义比较包含全部不同编辑字段与documentation,header要求完整multiset相同,Modules只允许kind Constructor的已证实canonical重声明多重出现消失,其他kind的完整multiset相同;不同constructor组合仍全部保留。不能继续套用旧65项与新23项multiset必须相同的断言。native仍要求所有实际返回编辑字段multiset一致。 + +驱动末尾新增显式性能门槛:候选warm/edited p95≤200ms;native对两侧stock edited均至少改善50%;已有稳定主进程CPU/RSS比较必须有数据且无≥20%退化,失败保留summary并退出。未将旧“答案一致即可打印PASS”的行为当发布资格。主进程检查仍不覆盖后代/物理缓存,过程树资源、产品缓存来源及≤50ms、新导出≤5s、冷/温导航、1000 saves和三平台长期资格继续保持未完成。全部准备版本和摘要分别保存,未覆盖历史驱动。 + +### Linux进程树资源观察器已准备,真实引擎资格尚待执行 + +现有project_completion.Resources仅读取主进程stat/status,不能支持后代或物理缓存声明。独立准备ProcessTree与resource-only replay wrapper:以PID/start ticks固定root身份,递归发现后代并继续跟踪已观察到的reparented进程;读取own及已wait子进程CPU计数、smaps_rollup RSS/PSS/private clean+dirty。一次观察前后成员身份或reap计数变化则拒绝,CPU区间计入时钟量化误差;stable reducer要求真实请求边界顺序、观察器完成/清理及无稳定期采样缺口。 + +实际Python parent/fork控制通过:子进程32MiB分配可见、CPU工作可见,wait后CPU仍由parent reaped counters覆盖、PSS下降,root身份不匹配被拒绝。普通与deferred的真实framed mock-LSP回放通过两进程边界CPU/时钟检查和退出后无残留;这里只是观察器控制,不是clangd语义证明。初次stable reducer退出1暴露记录时间问题:后台异常处理在释放snapshot锁后记录时间,将启动期观察误标为稳定期缺口。原代码/原回放/失败保留,TreeChanged改为异常产生时保存实际观察时间,第二次framed控制及stable reduction通过;observer error、缺boundary及稳定期membership gap三个负例均拒绝。 + +资源wrapper显式标记latency_qualification=false,其回放的所有延迟均排除。PSS读取和全树遍历有扰动,不与raw延迟验收混用。PSS是共享mapped pages的比例分摊,RSS sum重复计共享页,均不是completion cache物理分配账本;周期观察不证明所有短命未观察子进程/逃逸。生产engine、series、运行构建未改;真实engine/product资源A/B/A、cache物理预算及1000 saves仍未通过。 + +上述20个源码/真实控制文件与原失败已持久保存于[resource preparation evidence](2026-10-08-0.0.12-part2-evidence/resource-preparation72/README.md),含逐文件manifest和可只读重放的audit-tree-controls.py。归档审计实际通过;准备不是release完成。下一步在干净72完成和raw延迟资格结束后,独立运行资源回放,再据实际过程树数据判断20%门槛。 + +独立resource-four-arm驱动也已准备:70/72×headers/modules各3启动×30轮,调用resource-only wrapper与stable tree reducer,保留全部语义/选定插入检查,分别比较CPU保守区间和RSS sum/PSS/private页的各启动最大观测p95,显式拒绝≥20%退化。驱动不包含延迟门槛,其报告标记所有计时无资格;不作物理缓存/短命逃逸/长期稳定声明。构建running时实际前置拒绝、无结果目录/engine启动,记录与identity依赖一并持久保存。真正资源回放仍待最终72字节及raw资格完成后运行。 + +### 最终72同源Linux kit与产品C7准备 + +70产品/VS Code证据使用stock kit,不能移作最终同源payload证明。现在从相同离线Ubuntu20镜像实际采集4025个C/kernel头文件及两份license至新数据盘目录,逐文件SHA与包版本记录:libc6-dev 2.31-0ubuntu9.18、linux-libc-dev 5.4.0-216.236;仅输入采集,不是kit生成、性能或完整Ubuntu20产品资格。原stock kit与旧构建均未改。 + +新kit配方要求clean72身份、raw完整matrix审计和native/four-arm显式门槛通过后执行:使用完整72不可变源树与该构建实际clang producer,resource headers来自最终包,kit的C/kernel头来自上述Ubuntu20捕获。生成前核对source HEAD/无tracked改动及全部sysroot摘要,输出producer/tool/source/kit摘要;生成后再核对source未改。当前只准备并完成语法检查,未复制producer或生成kit。配方在构建running时实际前置拒绝,原negative单独保存。host generator和本地kit仍不能证明全产品glibc下限、immutable payload或三平台分发。 + +新的inferred/C7产品驱动固定原产品二进制SHA70156817…,改用尚待生成的72本地kit;必须验证kit complete、每个kit文件摘要和engine metadata完全匹配才启动。仅语义集成,无产品缓存命中/≤50ms或产品性能声明;当前实际前置拒绝、未启动产品。持续源码审计未发现completion答案缓存,不能将重复unchanged请求称cache hit,也不新增答案缓存掩盖引擎成本。≤50ms来源与其适用性仍需按真实路径证明。 + +输入捕获、两个配方/命令/negative与identity依赖已持久保存于[kit/product preparation](2026-10-08-0.0.12-part2-evidence/kit-product-preparation72/README.md),12文件manifest复核通过。所有最终产品/raw/资源/编辑器资格仍按其实际执行结果验收;两PR继续不合入。 + +### 最终72干净包与12语境短控制实际通过 + +原retry1会话26699实际退出0:全4744配方完成、16 lit、259 clangd定向测试(含新增联合验证和构造函数回归)、5 NamespaceLookup、2 PositiveScanMemo及CLI/CIndex/interpreter七阶段通过。最终stripped clangd SHA`696e8caa5246525669583eb0f999f23cb21a87191f3b1be59a0c3952a5d1a0b1`,build binary SHA`b3a011e1de4ce743bd95f906ade073b498df4a54754bc9bd6dccc139aeb64d2a`,fork`c30429fbe876c10b7dbe372a42e2d4b867b5970c`,source`82cdc7777e9dec4712b5913a8cfd31ea3634b99b`,whole-series`b53e91d831b3b45944d7bc2904145221497333dca2e890e75e7c5cfc3ed3b7df`。实际glibc2.31 dependency/startup检查problems为空、最高GLIBC符号2.29,无动态libstdc++依赖;仍不代替Ubuntu20全产品资格。原挂载启动退出126与物理路径修正保留。 + +确认无观察到的编译/engine活动后,会话20250实际退出0:最终包12语境各1启动×1轮,48次请求检查(36要求typed Sema、4 include、8空负例),52次首/末/最慢选定GCC插入全部通过,各适用warm/edited短预算通过。first-column warm/edited86.216/153.346ms、ordinary80.794/155.039ms、std-qualified66.859/131.667ms。各语境采样无编译或独立engine组重叠、无错误且已停止;不证明完全空闲/全过程树资源,也不逐回复全部编译。 + +在短计时实际结束后,将完整构建/原启动失败/最终身份及resource headers、12短原报告/插入/负载/驱动持久归档引擎`tests/evidence/part2-linux/portable-canonical72/`,412文件manifest复核。没有在延迟测量期间压缩归档。下一步正式12×3×30,然后native/four-arm/product/资源;不得将上述短样本或已完成70分布当72 release资格。 + +原UP20 mcpp固定源`d1f1c98fa26d953e084a183a9672fc1e0ce63558`与现有prepared workspace的482个代码/配置文件只读核对无差异。新最终72单次fan-out驱动沿用原URI/工作区、同产品/runner及0–7 CPUs;复制原8-importer流程并额外要求restarts=0,必须先验证完整72 kit来源。未运行UP20,也不是1000 saves。源内容在前后核对,仅必要时恢复此驱动的精确已知interface edit,不覆盖意外变更。 + +kit生成和两个产品语义驱动补充了按PID/start ticks跟踪的owned descendant/group清理;真实Python parent与detached child的控制通过,调用方存活。正常成功退出后若仍需强制清理,驱动记录失败,不把清理掩盖为产品正常关闭。周期发现未观察到的快速逃逸仍不获证明。旧准备版本保留,真实产品生命周期尚待执行。原source audit、fan-out准备、cleanup代码/控制及9文件manifest持久保存于[UP20 preparation](2026-10-08-0.0.12-part2-evidence/up20-preparation72/README.md)。 + +### 最终72完整12语境通过,native短控制通过 + +原正式会话89823退出0,12语境各3启动×30轮完整完成,不需要补跑。逐回复独立审计退出0:2232请求检查(1674要求typed Sema、186 include、372空负例),263次实际首/末/最慢去重选定GCC插入全部通过,phase/draft/真实来源及精确选定集合核对通过,各适用预算通过。warm/edited p95:first-column82.929497/165.051612ms,ordinary91.827560/166.456794ms,std-qualified72.722900/145.368447ms;module-member58.863241/133.420346ms。所有负载采样无观察到的编译/独立engine组重叠,无错误且已停止。 + +最终72 native candidate冷控制会话60947退出0:4次真实Sema及4次实际native插入通过,cold2132.329327ms;不作cold对照或冷导航预算证明。随后AST-ready stock/candidate/stock短会话96001退出0,9次真实Sema和9次实际native插入通过,全部实际返回项六个关键编辑字段multiset一致。edited短样本82.552488/19.928177/80.887687ms,无采样重叠/错误、采样停止;尚不作正式50%分布或稳定资源改善结论,stock冷失败不改写。 + +原矩阵/263插入及可对压缩原报告只读重放的audit-matrix-archive.py、两个native短驱动/原报告/13插入已持久补齐portable-canonical72,533文件manifest复核;归档矩阵审计实际重放通过。压缩仅在所有计时实际结束后进行。下面进入native正式3×30,再进入同Clang12 recipe的70/72 header/modules对照;Linux产品/过程树与其他release门槛仍未完成。 + +### kit输入收敛到包所有权,配置环境也固定为Ubuntu20 + +检查准备配方发现先前捕获整个/usr/include的4025文件超出官方kit配方的包列表。保留原捕获及证据,新建按`dpkg -L libc6-dev linux-libc-dev`选择的1422个C/kernel头;所选字节全部与原捕获一致,包版本和两份license来源相同,不把其他构建依赖头文件纳入新kit。没有修改已安装stock kit,也尚未生成新kit。 + +生成配方改为在相同离线Ubuntu20镜像执行,而非host配置后仅换头文件:完整72 source/producer、C/kernel输入及configure的OS/toolchain环境同时固定,实际cmake/ninja/compiler版本将在执行时记录;容器Git safe.directory仅写容器,不改host。单独container ID负责超时回收,仍要求raw门槛与source/engine摘要通过才启动。只读确认固定产品binary为statically linked;这不能代替真实完整Ubuntu20产品回放。筛选输入、容器配方与旧版本已持久保存于[owned kit input evidence](2026-10-08-0.0.12-part2-evidence/kit-owned-inputs72/README.md),10文件manifest复核;kit/product资格仍待执行。 + +### 最终72 native完整三臂通过 + +原会话23965退出0:stock/candidate/stock各3启动×30轮AST-ready,共549次真实typed Sema,47次按首/末/最慢去重选定native插入全部通过;所有实际返回项六个关键编辑字段、phase和draft一致。cold baseline明确不请求,原冷失败不改写。独立审计逐回复真实来源、3×30阶段数、实际p95排序、负载与精确选定回复集合通过,proof CDB摘要唯一。 + +warm p95 before/candidate/after88.066913/20.129784/86.430674ms,edited89.780771/23.926179/89.662240ms;对两侧edited改善73.3504%/73.3152%,通过相同正确路径≥50%门槛。主进程稳定CPU保守比0.570884/0.580465、各启动最大观测RSS p95比0.542600/0.542437,无≥20%退化;不含全部后代或物理缓存。各臂无采样编译/独立engine组重叠、无错误且采样停止;显式性能门槛均通过。 + +原三臂/47插入与可重放audit-native-archive.py持久补齐portable-canonical72,558文件manifest复核,压缩归档后的只读独立审计通过。下面进入70/72同Clang12 recipe的header/modules四格3×30;产品/资源/平台/长期资格仍未完成,不能只以native收益宣布release。 + + +### 2026-10-09 最终72同配方头文件/Modules四格分布完成 + +原正式四格会话43088退出0,portable70与final72均为Clang12/Ubuntu20配方、相同upstream pin,实际二进制复制至同一数据盘。各3启动×30轮,744次typed Sema检查、82次首/末/最慢去重选定GCC插入全部通过。独立audit及压缩原报告只读重放通过;全部不同编辑字段与documentation保留,headers完整multiset不变,Modules仅消除已证明的canonical构造函数重声明多重出现。全量原报告/驱动/插入/工作负载持久补齐引擎`tests/evidence/part2-linux/portable-canonical72/`,590文件manifest(生成的module cache保留于数据盘、排除出Git证据);压缩发生在所有raw计时结束后。 + +| 同配方四格 p50/p95(ms) | warm | edited | cold | +|---|---|---|---| +| portable70 headers | 29.573391 / 40.484414 | 129.047922 / 141.677506 | 1810.161405 / 1810.307432 | +| final72 headers | 29.811177 / 40.152919 | 129.662332 / 136.773706 | 1716.840876 / 1723.587425 | +| portable70 Modules | 73.505177 / 84.757711 | 146.740873 / 157.166119 | 2384.759488 / 4395.261447 | +| final72 Modules | 62.324950 / 71.132441 | 135.461788 / 144.506764 | 2437.864455 / 4230.403477 | + +final72 Modules与headers的warm p95仍差30.979522ms(约77.2%),edited差7.733058ms(约5.65%);warm p50也存在32.513773ms差额,不能归为单纯尾部波动,更不能宣称完全对齐。差额是模式整体比较,不是某函数exclusive成本。相对portable70 Modules,warm/edited p95分别改善约16.1%/8.05%;这仅隔离71/72的增量,不替代此前67或stock对照。主进程CPU保守比headers1.004198、Modules0.955539;RSS观测p95最大比0.998277/0.998347,显式200ms与20%门槛通过。各臂负载采样无观察到编译/独立engine组重叠、无错误且停止,不证明全部后代或缓存物理预算。 + +在raw验收与归档完成后,独立resource-four-arm会话61105已启动。其所有elapsed times明确排除延迟资格,真实进程树CPU/RSS/PSS/private结果尚待完成;不与kit生成或其他编译同时运行。产品、kit、warm剩余差额、1000 saves、其他平台及长期发布资格仍未完成,两PR不合入。 + + +### 2026-10-09 独立进程树资源回放完成、同源kit开始执行 + +原resource会话61105虽退出0并打印PASS,candidate-modules退出期实际出现采样线程未捕获`KeyError: VmRSS`,异常没有进入errors;该轮明确排除资源资格,原四臂报告/日志/插入及negative保留。v2将实际退出/僵尸进程分类为TreeChanged,其他意外观察器异常进入errors并停止采样。真实Linux未reap僵尸与注入RuntimeError控制通过,不以模拟答案证明引擎语义。 + +v2会话6288退出0,每臂3启动×30轮,744次typed Sema通过。独立审计重新计算真实请求边界/CPU区间/内存窗口,逐条核对所有草稿、phase、完整编辑及documentation multiset与既有raw四格一致;固定engine/source/CDB/context/position身份,因此复用此前82次实际插入编译证据,不重复编译同样编辑字段。所有v2日志无未捕获Traceback,观察器无errors、稳定期成员/reap缺口、残留owned进程或未停止线程,负载无观察到编译/独立clangd组重叠。 + +| observed tree candidate/baseline | CPU保守比 | RSS sum p95最大比 | PSS p95最大比 | private p95最大比 | +|---|---|---|---|---| +| headers | 1.003426 | 1.000245 | 1.000134 | 1.000120 | +| Modules | 0.957780 | 1.120489 | 1.034287 | 1.034416 | + +均通过小于1.20的显式门槛,Modules RSS sum增长约12.05%仍如实保留。PSS为共享mapped pages的比例分摊、RSS sum重复计共享页;这些观测不能证明completion cache物理分配、快速未采样子进程或长期增长预算。此阶段所有elapsed times无延迟资格,不替代raw分布。原失败/v2全部报告、控制、观察器、可对压缩报告只读重放审计已持久保存portable-canonical72,655文件manifest,归档审计实际通过;压缩发生在测量全部结束后。 + +资源审计/归档完成后,same-source-kit/build-kit.py会话11452开始执行,要求最终72 identity、完整matrix audit及native/four-arm raw门槛通过。使用同72全源码与实际clang producer、1422个已捕获Ubuntu20 C/kernel头文件及离线容器。kit尚在执行,未宣称完整同源payload或产品通过。warm对齐、产品/编辑器/UP20、缓存物理预算、1000 saves、平台和长期资格仍待完成,PR不合入。 + + +### 2026-10-09 同源kit与首次inferred产品闭环完成 + +kit会话11452实际退出0,离线Ubuntu20容器使用cmake3.31.10/ninja1.10.0与实际72 clang23.1.0-mcppls.0,配置/安装headers与modules完成;3241文件、约20.5MB。原kit recipe已有的大小写冲突筛选剔除8个Linux kernel头文件,日志保留,不宣称捕获1422文件全部原样进入最终kit。identity保存3241逐文件hash、完整source/producer/engine/input摘要与实际容器命令。owned cleanup无错误/强制终止/残留且watcher停止。当前只是本地同源kit,payload.lock与三平台不可变交付尚未更新。 + +产品会话56722退出0:固定server SHA70156817…配final72及新kit,fresh inferred workspace/cache,17检查全部通过,总7.408390207s。新导出C7补全包含greet2(),实际检查2.528703344s,小于5s;first-navigation since-start4.356191235s。这是一次真实样本,不能证明五次启动导航中位数或实际VS Code资格。产品正常关闭,owned cleanup无错误/强制终止/残留、watcher停止。kit与产品原日志/identity/measure/配方/摘要持久保存[kit/product execution](2026-10-08-0.0.12-part2-evidence/kit-product-execution72/README.md)。 + +原UP20 pinned source/workspace、8CPU affinity与固定产品/新kit的一次保存fan-out会话7273已启动,要求8 importer与恢复检查、零restart及482源文件恢复校验。尚在执行,不能提前报通过或称1000 saves。warm差额、产品对照/缓存来源、完整Ubuntu20产品、真实编辑器、物理预算与长期/多平台资格继续待完成;两PR不合入。 + + +### 2026-10-09 原UP20最终72一次保存fan-out通过 + +会话7273实际退出0,原pinned source/workspace/8CPU/CDB profile、固定server与final72,一次真实接口export保存及恢复,8 importer在12.134779389s republish,probe3.206949562s清除,交互恢复12.269041162s,restarts/errorSamples/completionsUnanswered均0。13次interactive completion p50 20.101620ms、p95/max1184.047660ms;原fixture仅限制errorStates0/restarts0/recoverSeconds60,没有interactive200ms门槛。因此本轮仅证明原一次fan-out fixture通过,不能宣称编辑期间交互性能已达标,后续必须按请求时间线分析1.18s尾部。整体116.297509529s、first diagnostics91.180708992s,不是冷导航分布。 + +482 source文件全部恢复;owned cleanup无错误/TERM/KILL/残留,watcher停止。原debug log、actual measure/identity/source-audit/fixture/命令持久保存[UP20 execution](2026-10-08-0.0.12-part2-evidence/up20-execution72/README.md),压缩仅在该进程终止后。1000真实saves与RSS增长、长期资源/多平台/完整发布资格仍未完成;两PR不合入。下一步优先核对UP20该次尾部与产品等待/引擎工作时间线,再继续实际编辑器和发布剩余门槛,不扩大重复已通过raw测试。 + + +### 2026-10-09 UP20尾部时间线与产品cache审计更正 + +只读核对该次原debug log:route.cppm两次真实clangd completion分别在11:16:20.944/22.076进入,回复分别2011/7295ms;恢复probe binfmt.cppm实际97ms。保存期间存在模块任务构建/复用,11:16:22.076产品event loop记录352ms timers阻塞(启动loaded model960ms及恢复后336ms另列)。这说明该fan-out请求不同于已通过的稳定raw正文编辑;尚不能把p951.18s完整归因于timers或Sema,后续应针对真实请求分解等待/scan/build/Sema,并定位timers慢操作。 + +更正前面“未发现completion答案缓存”的源码审计:实际workspace.cpp已有C-2 lateAnswers/lateCompletions,answered_late按URI/word key/lifetime复用迟到语义答案,finish_job仍标core engine。因此现有engineShare不能证明每次请求都执行引擎;本轮13个product请求仅出现两次route engine请求,快速尾随回复必须单列来源,不能冒称raw速度。该机制是既有产品代码,本轮优化没有新增它;raw矩阵/native/four-arm均直接驱动clangd,不受此产品复用机制影响。后续产品≤50ms cache-hit资格必须用实际C-2命中计数/请求来源与新执行隔离,不继续沿用“无答案缓存”前提。只读triage的原日志SHA/行号、source SHA及局限已存UP20 execution/tail-triage.json。 + +### 2026-10-09 保存触发冗余全项目规划:实测定位与生产候选 + +原UP20主线程strace诊断退出0,真实一次接口保存/恢复及482文件恢复检查通过。该轮所有elapsed times排除延迟和资源资格;perf task-clock因本机权限被拒,未改系统权限。两次timer窗口约360/353ms,各有176次prime文件读取、无prime写入;所追踪file/write调用的内核时间各小于1ms,但没有追踪read/close、其他线程或完整CPU,不能据此声称全部耗时来自某一个函数。诊断记录、原压缩trace和窗口计数在[UP20 profile](2026-10-08-0.0.12-part2-evidence/up20-profile72/README.md)。 + +源码链路确认:近期编辑的didSave无条件schedule_replan,timer执行normalize全项目计划,再engine.apply,读取全部prime并重新序列化数据库。生产候选在保存仍交给engine之后,仅当草稿和新读磁盘的module/role/import结构均与上次计划一致、每个对应planned entry覆盖扫描imports、且无standInsDeferred时跳过此次重新规划;没有清除此前安排的其他规划,没有新增答案缓存。真实Workspace/index/planner单元回归:旧实现4项中仅正文保存不重规划控制失败;候选最终5项/16断言全部通过,覆盖新import、deferred stand-in、磁盘/草稿不一致和producer遗漏的条件import。 + +同Clang22.1.8/27d66c923d5b4fe8配方的原服务器与全target已完整保留于数据盘;候选实际构建退出0,server SHA227fda4f294faa048be41d357bac18adb95d094ba27a7fff56d46bb0dcd01516,原server SHA30878460e9423e956d8ce5d14a9ec323313e06841e57c3a1799fb47f9524267d。新server配final72/同源kit的inferred 17检查通过,C7为2.518705229s。注意C7 runner edit只修改未保存buffer,这证明草稿新导出可见性,不能作为didSave证据;新save-plan fixture使用type-text/save真实写盘并发送didSave,资格仍待执行。 + +正在串行执行原UP20原URI/CDB/source/8CPU的同配方产品baseline/candidate/baseline三臂,固定原runner、final72与kit,各fresh cache并200ms负载采样;未完成前不宣称性能改善。候选只是本地修改,PR不合入。raw warm剩余约31ms差距、真实编辑器、缓存物理预算、1000 saves、完整交付及多平台/长期release门槛均继续待完成。 + +### 2026-10-09 保存优化同配方UP20三臂与实际save conformance完成 + +三臂实际退出0,独立live audit核对真实二进制hash、runner/engine/kit/source/fixture/CPU/URI匹配;每臂零restart/error/unanswered、482文件恢复、normal owned cleanup和200ms workload采样均通过,无观察到外部编译/独立engine重叠。completion p95 baseline-before/candidate/baseline-after为1178.419326/1053.521949/1168.414754ms,相对两侧改善10.598721%/9.833221%。原服务器两侧都出现350ms级save/restore timer警告,候选没有slow-timer warning;不把无警告解释成零timer成本。8 importer republish分别11.735644/12.637576/12.434433s,没有改善;剩余约1.05s尾部仍需定位。本轮每臂仅一次真实保存,既有C-2复用计入product回复,不能冒称raw Sema多启动分布或release通过。 + +新save-plan fixture真实写盘、didSave及watched通知,6检查全部通过,耗时5.449107s:新增export后补全包含added(),新增export import后包含extra(),原original()均保留。该fixture加入三平台常规CI名单,本地只证明Linux执行,其他平台仍待实际验证。单元/构建/草稿与保存conformance/三臂原日志及live audit已保存[save-plan evidence](2026-10-08-0.0.12-part2-evidence/save-plan72/README.md),49文件manifest;压缩后只读archive replay实际通过,不把archive replay说成重新构建二进制。原build/二进制/失败scaffold及全部cache保留数据盘,Git证据排除生成cache和二进制。 + +本次提交前`mcpp run -p devtools -- check all`最初暴露已有证据脚本未登记,补齐43份逐路径用途说明(含此次新增脚本)后实际退出0;schema/traceability validate退出0、0 failures。原始日志和patch以gzip保存原字节,避免为了whitespace检查改写原始证据。 + +### 2026-10-09 UP20引擎语义健康审计发现准入负例 + +继续读取三臂完整engine log,分别发现29/31/27次`Failed to build module prerequisites`,全部原因是owned module cache的`payload or generation admission exhausted`。原fixture的errorSamples0是产品status计数,不等于engine构建没有失败;此前“原fixture通过”和p95数字保持原记录,但这些回放不能证明完整模块语义健康,更不能作为release通过。逐条日志行、原SHA和实际engine completion回复时长补入[semantic health audit](2026-10-08-0.0.12-part2-evidence/save-plan72/semantic-health-audit.json)。候选三次实际engine completion为1981/7067/102ms,不能以C-2快速复用掩盖前两次执行。 + +当前owned cache默认逻辑预算1GiB、4096槽;单worker默认输出256MiB+capture64MiB,最多两个worker。结束后的账本仅约344MiB并不能证明运行时容量足够;准入按预留envelope计费。maintenance每轮collect32槽,空闲节奏5s,owned collect结果没有驱动MoreCopies的100ms继续扫描,这也是待实测的回收候选,尚未声称是唯一原因。启动独立诊断回放,用nonblocking shared ledger flock读取一致快照、立即解锁后验证双bank XXH3 checksum;没有修改账本或租约、没有主动回收。该诊断所有耗时和资源排除资格,等待真实pressure与reservation快照再决定生产修复,不提高预算或关闭准入来掩盖问题。 + +诊断v2实际退出0、source恢复/owned cleanup通过,观察器225个有效一致快照、335次nonblocking忙跳过、无errors且线程停止。42个pressure快照均请求335544320字节,27个快照剩余字节不足,零个槽表满;最多496/4096槽、最大charge1073511464字节。确认观察到字节预算压力,不能归因于4096槽耗尽;pressure标记可能在容量释放后暂留,不把全部42个快照都说成当时不可准入。instrumented回放64次准入失败,不能与此前未插桩失败数或耗时比较。初次诊断因xlings Python不能按soname加载系统xxhash库,在启动server前失败;已停止仅该owned parent、固定实际系统库路径并通过真实已结束账本的checksum控制,再开始v2。 + +原日志/原始账本快照压缩、失败启动和观察器源码文本归档[admission diagnostic](2026-10-08-0.0.12-part2-evidence/up20-admission72/README.md)。私有独立source worktree `/dev/shm/mcppls-part2-admission73-source`已实现typed容量压力与有deadline/cancel的reserveUntil候选,worker只能使用原期限剩余时间,其他错误不重试、不绕过准入、不加大预算;补了真实reservation的并发publication、取消、超时/非法envelope三个测试。当前候选未编译/未测试/未追加生产series,patch快照明确unqualified;下一步构建并执行这些控制,然后实际UP20验证。原最终72source/build/package保留,release仍未完成。 + +### 2026-10-09 私有准入候选已编译并完成首次真实回放,仍不晋升 + +同离线Ubuntu20镜像/Clang12配方增量构建:重编ModuleBuildCache、ModulesBuilder及测试对象,复制独立clangDaemon archive再链接,原final72 source/build/bin只读保留。首次生产对象编译和链接成功;7测试中5通过,取消/超时两个测试先用llvm::Failed()消费Expected错误、再取文本而失败,属于断言脚手架问题。保留原失败;修正ASSERT_FALSE后只重编测试对象,复用字节相同的生产archive/engine。中间一次Docker mount参数拼接失败发生在编译前,亦保留。v3实际退出0,7项控制(3新、4旧OwnedPayload租约/身份)全部通过。实际engine SHA3dccd2cef598d3706e2fba0a742c62f5f6078dde7f2377fe299391c842bc824f,PRIVATE incremental、不是clean release build。 + +真实原UP20一次保存回放结束:原fixture通过,capacity admission拒绝0、worker admission deadline拒绝0、restart/errorStatus/unanswered0;482文件恢复,正常owned cleanup,无观察到额外编译/独立engine重叠。但新增whole-log严格wrapper实际退出1:有一次route.cppm prerequisite `Task was cancelled`。引擎请求3在03:13:56.876收到实际cancelRequest,03:13:57.428出现该失败,随后03:13:57.434仍返回普通completion result(100项),不是cancel error;记录相关性而不自动豁免该失败,不把退出1改写为语义健康通过。产品此前已结束这个请求,取消后的late回复不应据此当成新的正常语义成绩。 + +8 importer republish34.776417s、恢复34.904969s、whole约191.4s;本轮明确correctness-only,所有elapsed/resource排除性能资格。此前约12s路径存在27–31次真实模块构建失败,不能当作完整正确语义的匹配性能baseline;仍须分解新增实际构建/等待成本并解决取消语义,再完成正确路径的性能对照。私有候选尚未追加生产series,最终72包/kit/既有raw资格不改写,不能宣布release完成。 + +三次build原记录、实际回放原log/负例/measure/provenance/workload与修正后的private patch保存[admission candidate controls](2026-10-08-0.0.12-part2-evidence/admission73-controls/README.md),29文件manifest。日志仅在实际回放退出后压缩,生成cache和binary保留数据盘、不入Git;下一步针对private正确路径做请求等待/准入/构建分段和取消检查。 + +### 2026-10-09 依赖闭包修复:有效回归与原 UP20 严格健康通过 + +准入等待解决暂时容量拒绝后,继续诊断发现每个 producer 的缓存键绑定整个 build-wave 已完成模块快照,包含无关 root。实际 Shared→Base→Leaf 只应依赖这条链;另一个 consumer 导入或编辑 Noise 也改变 Shared generation,导致多余构建、复制、发布与容量压力。这是 fork 自有 planner/cache 的过度绑定,不新增 upstream 缺陷声明。生产 0074 保存每个 node 的传递依赖闭包,派发 immutable filtered snapshot;未知/prebuilt leaves 保守保留。0073 typed capacity-pressure 等待仍在原 worker deadline 内且可取消,不增加预算、不驱逐活租约、不重试 corruption/identity/I/O 错误。 + +有效 baseline-v4 仅两项无关 root 的 Shared generation 等值断言失败,真实传递 Leaf 编辑失效控制通过;candidate-v2 全部77项 PrerequisiteModulesTests通过。较早 malformed 同行 import、错误稳定路径假设和 deleted-move 编译脚手架失败完整保留,不充作产品缺陷。候选增量 Clang12/Ubuntu20 engine SHA c6e0226543c1b1c5248c3d0f2d93cb1f6ed197966dc70522e4f04c42505c84af;不是最终干净发布构建。 + +原UP20固定 URI/CDB/source/8CPU、同产品server/runner与原72 frontend/resource/kit的一次严格回放实际退出0:prerequisites失败、准入拒绝、restart/errorStatus/unanswered均0,482源文件恢复、normal owned cleanup通过。2072 tasks中85次实际构建,上一准入候选2067 tasks/526 builds;观察到恢复5.129297235s、8 importer republish5.010125993s、probe2.603316186s。该回放显式 correctness-only,所有时间/资源排除资格;不能声明新导出≤5s、正式多启动分布或fresh Sema比例。既有C-2 engineShare仍可能含缓存复用。 + +独立 admission-only stage logger 回放严格wrapper退出1,保留四个cancelled prerequisite负例;2054 tasks的分段wall总和有并发重叠,不是exclusive CPU或请求critical path。生产series没有导出该logger。原始命令/日志/失败/manifest与哈希校验共64文件归档引擎 `tests/evidence/part2-linux/producer-closure74/`;原Data/RAM源码/构建/缓存保留。series现为74补丁,74 ledger rows检查通过,0073/0074均stabilizing;尚未推送,PR不合入。 + +下一步完整74 series从固定tarball干净应用、Ubuntu20所有consumer编译/测试/最终包与floor检查,再以最终字节完成正确语义下的Linux性能/资源对照。原warm约31ms差距、真实保存/VSCode/缓存物理预算/1000 saves/完整交付、Windows与ARM macOS原生、7nightlies和各平台2h soak等release门槛继续保留;Intel macOS排除。 + +### 2026-10-09 全74干净源一致性完成,Ubuntu20构建已实际启动 + +引擎本地提交59f49b2,series SHA3d4a5c31a24b70a14eba8e64a786ed542332e3afdec9db8749b9fe74c2c28ea2;固定tarball重新fetch/apply全部74补丁退出0,合成LLVM source HEAD26f25781727292d9ebc91afa1d68be5bfe29a04a。受跟踪全树与已通过77测试/UP20的私有源83740693f完全一致,差异列表为空。旧72/私有候选原source/build/package保留。 + +`/home/data_disk/codex-mcppls-part2-builds/portable74/`保存preparation/source-progress、原命令与日志。初次Docker执行在compiler启动前被Git safe.directory检查拒绝,原progress/run.log/配方保留;retry将global safe.directory设置放到预检之前。retry脚本初始文件名替换误改source-progress路径,也在启动container之前失败,原脚本快照保留,修复后启动。实际新container d638c901edec正在编译;会话10834、retry1-progress为running,不能提前当作构建/测试/package/floor通过。离线Ubuntu20/Clang12、6CPU/6jobs/无ccache,源码与repo只读;完整4744构建步骤及全部consumer gates沿用原配方,生成目标全新。 + +已准备最终74身份门控和raw12语境/stock三臂/header-module四格/独立资源脚本,均未执行;要求实际retry1 terminal complete、source/fork/series/包hash及floor全部匹配。四格baseline改为同配方最终72,严格要求编辑/文档字段multiset和重复次数完全一致,取消此前仅允许constructor去重的差异豁免。本轮没有并行计时。1000 saves、C-2实际命中计数(已有completion.late.arrived/served)、新exports、VSCode及其余release要求继续待验,不以准备脚本替代执行证据。 + +### 2026-10-09 最终74串行验收已排队,构建中的门控负例通过 + +当前完整74 Ubuntu20构建container仍实际存活,尚未形成测试/package/floor verdict。最终字节identity模块在实际running build下拒绝启动计量,保存 `portable74/qualification/build-running-preflight-negative.json`。串行driver已启动(会话21052,PID2624204),绑定实际Docker CLI PID2613777/start_ticks13739873及container d638c901edec862b1c84381f9f7b3f935e9a0088d7bc744f8de1e0fd0a3086d6;目前状态waiting-for-live-build、stages为空。等待的是已核验运行句柄,非仅凭running文件假定仍活。构建失败或句柄丢失没有自动重建/重跑。 + +构建真实complete并通过source/fork/series/package SHA与floor门控后,driver依次执行matrix-control、header/module四格、12语境3×30、stock/candidate/stock native与独立observed-tree资源回放;任一实际失败即停止后续步骤、保留负例。manifest固定每份脚本SHA,单独driver progress/log保存实际执行和退出码;不把staging manifest的prepared状态称为验收通过。尚无新74延迟/资源结果,也没有发布、native Windows/ARM macOS、完整产品payload或nightly/soak资格声明。 + +原private回放的构建次数已独立按logger-prefixed `Module build task ... started` / `Built module ... to`重算,排除LSP JSON中的源文本:admission-only2067 tasks/526 builds,closure2072/85。日志原SHA/regex/逐模块计数保存在引擎producer-closure74/task-counts.json;manifest扩展为64原文件加1派生报告,全部65 stored/raw SHA复验通过。新增引擎证据暂不提交,以保持正在打包构建的fork HEAD59f49b2不变;源码/series未改变,PR不合入。 + +### 2026-10-09 最终74逐回复审计与同源kit已串行排队 + +完整构建仍实际运行,已进入clangd/Clang测试对象编译;没有提前声明consumer通过。新增post-raw driver(会话54104)绑定实际存活的serial-suite PID2624204/start_ticks13801151,只在其真实complete后运行四份逐回复审计,再生成新74同源Linux kit。失败即停止,不重启前序任务。审计核对所有raw语义来源、文档草稿、cold/warm/edited请求数、实际选定插入集合与nearest-rank p95;四格不再豁免constructor重复。选定first/last/slowest的实际数量随最慢样本位置变化,不照搬旧72运行的82项固定数量,完整集合仍必须逐项相等。尚未执行这些审计或生成kit。 + +新kit配方绑定完整74源码26f25781727292d9ebc91afa1d68be5bfe29a04a、新干净构建的实际clang producer和最终resource headers,并要求raw/resource各审计通过。仅复用同一固定Ubuntu20离线镜像中先前捕获的libc6-dev/linux-libc-dev拥有的1422个C/kernel头文件及许可证;逐文件hash已在新目录核对一致,保留reuse provenance,不冒称重新捕获。新目录 `portable74/same-source-kit/`,旧72 kit/capture全部保留;不在性能/资源计时期间运行kit编译。不可变payload锁、Linux完整产品运行下限、真实编辑器/1000 saves和其他平台/长期门槛仍待完成,PR不合入。 + +### 2026-10-09 全74 Ubuntu20干净构建、consumer、package和floor实际通过 + +会话10834实际退出0,retry1-progress complete;全4744步骤的新源/新build离线Ubuntu20/Clang12构建完成。16 lit、263 clangd控制(含新的准入等待/取消/deadline及依赖闭包控制)、5 NamespaceLookup、2独立PositiveScanMemo、CLI/PCH/CIndex/interpreter七consumer阶段全部通过;最终stripped package的能力canary与source/build identity检查成功。没有用private增量binary替代最终包。 + +实际最终engine SHA54fad6acab66d45f07ea1f080db56571b0ec4e3527496d0b10620fb0e522ace5,未strip build SHA1b731977d0278156742e7bcf1738e4f19e8d55b7cddbbb50fd1ef168845b4443,fork59f49b213f60444615659955f481ad7ae2ffb924,LLVM tree26f25781727292d9ebc91afa1d68be5bfe29a04a,series3d4a5c31a24b70a14eba8e64a786ed542332e3afdec9db8749b9fe74c2c28ea2。实际303 resource headers已绑定final-package-identity。glibc2.31 dependency/startup检查problems为空、最高GLIBC符号2.29、无动态libstdc++依赖;仍不代表完整产品Ubuntu20离线安装通过。 + +串行验收driver已从真实build terminal自动进入matrix-control.py,尚在运行;四格/完整12语境分布/native三臂/独立资源及逐回复审计、同源kit仍未通过,不能提前继承旧72性能成绩。当前正在计时,不压缩归档或启动其他编译/profile/独立engine。所有原始source/build/bin及首次Git所有权预检失败保留,待本批计时结束再归档。raw warm剩余差额、产品C-2实际来源/新exports/导航、VSCode/1000 saves/完整交付、其余平台与nightly/soak等原release要求继续待验;PR不合入。 + +### 2026-10-09 最终74短控制与完整四格通过,raw warm差额仍在 + +新54fad6ac包的12语境短控制实际退出0,全部真实语义、选定GCC插入及有数值门槛的短检查通过;不是3×30分布。随后header/module × final72/final74四格各3启动×30轮实际退出0,744 typed Sema和83选定GCC插入通过,编辑/文档字段的全部multiset与重复次数在对应模式内严格一致,没有constructor差异豁免。最近一次动态selected count为83,后序审计按真实first/last/slowest集合核对,不套用历史82。 + +| p95 | final72 headers | final72 Modules | final74 headers | final74 Modules | +|---|---:|---:|---:|---:| +| warm | 36.827849ms | 72.636054ms | 40.918935ms | 72.661976ms | +| edited | 134.845953ms | 145.773551ms | 141.786559ms | 146.862755ms | + +新74模块warm/edited与72基本相同;这两补丁没有宣称改善稳定raw补全。新74两模式warm仍差31.743041ms(约77.6%)、edited差5.076196ms(约3.58%),不能称已全头文件速度对齐。主进程稳定期candidate/baseline保守CPU比例headers1.026892/modules1.006011,RSS比例0.997717/0.951807,均通过<1.20;不是descendant/硬物理缓存预算或长期资格。精确逐回复审计和独立observed-tree回放仍排队。 + +会话21052已实际进入完整12语境3×30分布,不能提前报告全部语境通过。后序raw/native/resource审计及同源kit保持串行。产品driver(会话15094)绑定已验证存活的post-raw PID2638269/start_ticks13867327,仅在其实际完成全部审计与新kit后,依次执行新最终包+固定227fda4f服务器/c45bd02d runner的inferred、真实save-plan和原UP20严格whole-log健康回放;目前waiting,未执行产品。原UP20的482源码在准备时再次核对恢复,执行前后仍必须核对;不可用private c6e022候选的通过替代final54fad6包。产品这些回放均不宣称延迟/资源/1000 saves/发布资格。PR不合入,warm成本与其余完整release门槛继续待完成。 diff --git a/.agents/docs/2026-10-08-client-crash-recovery.md b/.agents/docs/2026-10-08-client-crash-recovery.md new file mode 100644 index 00000000..03a736fe --- /dev/null +++ b/.agents/docs/2026-10-08-client-crash-recovery.md @@ -0,0 +1,179 @@ +# VS Code client crash recovery evidence (0.0.12) + +## Failure and scope + +Product CI run `37658653689`, Intel macOS main VSIX suite, failed during the +server crash-loop test. Its log reports `Unexpected SIGPIPE`, duplicate command +`clangd.applyFix`, disposed pending responses, and destroyed-stream writes. +The downloaded authoritative log is `/tmp/joint-product-37658653689-failed.log`. +This record concerns the extension lifecycle; it does not establish the cause of +the macOS extension-host SIGPIPE or an engine crash. + +The installed dependency is `vscode-languageclient` **10.1.1**, resolved in the +extension lockfile. Relevant shipped source is +`editors/vscode/node_modules/vscode-languageclient/lib/common/client.js`: + +- `start()` (line 916) owns an internal `_onStart` promise separately from its + async continuation, awaits initialize, then returns that promise. +- `doInitialize()` (line 1103) sets Running before awaiting the initialized + notification and registering features. Its failure path calls `void stop()`. +- `handleConnectionClosed()` (line 1441) disposes the connection, awaits the + custom closed handler, clears features and resets `_onStart`. Restart then + starts the same client immediately. +- `lib/common/executeCommand.js` registers commands one at a time and stores + their disposables only after the loop completes. + +Resetting the start promise while its initialization continuation is still live +can orphan a rejected promise. Calling stop on a dead Starting client also +rejects. Reusing that client can overlap initialization and feature cleanup; +duplicate command registration in the macOS log is consistent with that race. +The overlapping-command explanation is an inference from source and the CI log, +not a Linux reproduction of the exact duplicate-command stack. + +## Implemented lifecycle + +The custom close handler waits for the original start promise to settle after +the library has disposed the transport, before the library clears features and +resets its promise. Automatic recovery returns DoNotRestart to the library and +queues disposal plus a fresh client in the host's existing lifecycle queue. +The three-crash budget is preserved. Automatic recovery skips `onStarting`, +preserving the existing behavior of not repeating conflict detection prompts. + +`ServerLanguageClient.stop()` suppresses a failed shutdown only after that +client's transport has closed; other stop failures propagate. Together these +library guards are registered as **WA-VSCODE-003 / +[UP-V1](https://github.com/Sunrisepeak/mcpp-language-server/issues/24#issuecomment-6044639460)**. +Remove them only when +an updated upstream library handles initialization interruption without an +orphaned start promise or unhandled shutdown rejection, demonstrated by running +the initialization-crash test with the guards removed. Fresh-client recovery +can remain an extension lifecycle choice. + +`runningClient()` becomes available only after `client.start()` completes, +including feature registration, rather than at the earlier Running transition. +The crash-loop test therefore kills fully initialized clients for its budget +checks and separately kills a replacement process during initialization. + +## Linux proof + +The real payload in `editors/vscode/payload` and installed VS Code 1.132.0 at +`/home/speak/.xlings/data/xpkgs/xim-x-code/1.132.0/code` were used with: + +```sh +MCPPLS_E2E_EDITOR=/home/speak/.xlings/data/xpkgs/xim-x-code/1.132.0/code \ +MCPPLS_E2E_ONLY=zCrashLoop.test.js npm test +``` + +The added initialization test polls for the newly spawned server PID, excluding +the previous server still shutting down, asserts the client is not initialized, +and sends SIGKILL. Recovery must register `clangd.applyFix` and answer a cache +request. The suite records unhandledRejection events and requires zero. + +- Negative control: compile HEAD's original extension against the new tests. + **1 passing, 2 failing**, about 5 seconds. The initialization test reports + `failed to initialize: Pending response rejected since connection got disposed`; + teardown captures two disposed-response rejections and two + `Client is not running and can't be stopped ... starting` rejections. + Log: `/tmp/mcppls-client-crash-baseline-red.log`. +- Fixed lifecycle: **2 passing**, about 6 seconds, zero captured unhandled + rejections. Initialization interruption recovers; manual restarts do not use + the crash budget; the third running-server crash stops recovery and creates + the report; manual restart works afterward. + Log: `/tmp/mcppls-client-crash-settled.log`. +- `npm run compile`, 115 unit tests and `git diff --check` passed. +- Final recovery-flag and conflict-prompt assertion run: **2 passing**, about + 6 seconds; no repeated conflict prompt and zero captured unhandled rejections. + Log: `/tmp/mcppls-client-crash-final.log`. + +An earlier exploratory attempt missed the replacement startup because PID +selection included both old and new children. It timed out and is not counted +as proof. The corrected PID selection produced the negative and positive +controls above. Another intermediate fresh-client-only version recovered but +still emitted unhandled rejections; it was not treated as a completed fix. + +The fixed Linux run still logged a library message-queue write-after-end error +during deliberate SIGKILL. It was handled and did not appear in the suite's +unhandled-rejection collection. Temporary logs and compiled negative-control +files remain outside the PR; fixed source and compiled output were restored. + +## Remaining verification + +Intel macOS CI must verify the original VSIX scenario. Linux evidence does not prove macOS SIGPIPE +resolved, and no root-cause verdict is claimed for that signal. This change also +does not prove absence of all engine crashes or meet the complete joint release +gate by itself. + +## SIGPIPE follow-up: the host did not terminate from the signal + +The original Intel macOS log distinguishes the bootstrap diagnostic from the +test failure: + +| UTC time | Authoritative event | +|---|---| +| 17:40:19.169 | bootstrap-fork.js logs `Unexpected SIGPIPE` | +| 17:40:19.807 | the same host reports duplicate `clangd.applyFix` | +| 17:40:22 | the host reports disposed-response and destroyed-stream rejections | +| 17:41:34.591 | the test fails while waiting for the third-crash notification | +| 17:41:34.603 | extension-host PID 7304 exits with **code 0**, signal `unknown` | +| 17:41:34.927 | editor test harness exits with code 1 | + +It is therefore incorrect to describe this CI result as an extension host +killed by SIGPIPE. It remained alive for approximately 75 seconds after the +diagnostic and exited when the failed test runner requested shutdown. + +VS Code's [bootstrap signal handler](https://github.com/microsoft/vscode/blob/main/src/bootstrap-node.ts) +logs an Error once; it does not throw it or exit the process. The same handler +is present in the locally installed 1.132.0 `out/bootstrap-fork.js`, matching +the bootstrap frame in CI's 1.141.0 stack. Node also documents that +[SIGPIPE is ignored by default](https://github.com/nodejs/node/blob/main/doc/api/process.md). +An installed signal listener can observe a broken-pipe write without the +process terminating. + +A controlled Linux probe used the extension's installed `vscode-jsonrpc` +`StreamMessageWriter`, the same writer used by the language client's stdio +transport. The child closed only stdin and remained alive briefly; the parent +wrote one JSON-RPC notification, handled the writer rejection and observed +SIGPIPE. Run this from `editors/vscode`: + +```js +const {spawn} = require('child_process'); +const {StreamMessageWriter} = require('vscode-jsonrpc/node'); +const child = spawn('/bin/sh', ['-c', 'exec 0<&-; sleep 0.1'], + {stdio: ['pipe', 'ignore', 'ignore']}); +const writer = new StreamMessageWriter(child.stdin); +let signals = 0, errors = 0, writeFailure; +process.on('SIGPIPE', () => signals++); +writer.onError(() => errors++); +setTimeout(() => writer.write({jsonrpc: '2.0', method: 'closedReaderProbe'}) + .catch(error => { writeFailure = error.code; }), 20); +child.on('close', (code, signal) => console.log({code, signal, signals, + errors, writeFailure})); +``` + +Observed result on Node 26.7.0: child code 0, child signal null, one SIGPIPE, +two writer error events, rejected write `EPIPE`, and parent process exit 0. +This establishes the exact stdio-writer mechanism for a harmless signal +diagnostic under a closed-reader condition; it does not identify the specific +file descriptor that produced the original native macOS signal. + +The CI signal immediately follows a failed notification send to a deliberately +killed language server. A stale write to that server's stdin is the leading +source-supported inference. The original log has no descriptor or syscall +trace, so console or other extension-host IPC writes cannot be excluded. +The corrected client lifecycle addresses the reproduced initialization and +rejection failures. Native CI should require successful recovery and no +unhandled rejection; a handled broken-pipe diagnostic during deliberate +SIGKILL alone is not evidence of a host crash. No process-wide signal +suppression, editor bootstrap change or deadline increase is justified here. + +## Follow-up: failed request writes orphan an async executor (UP-V2) + +Authoritative current product CI run `37686772481`, product revision `ee49d82`, still fails on Intel macOS. `/tmp/mcppls-product-current-ci-failed.log` retains the exact failing case: `server crash loop`, `"after all" hook for "a restart is not a crash; the third crash stops the restarts and offers the report"`. Its assertion captures two unhandled `ERR_STREAM_DESTROYED` errors. Each stack starts at Node `_write`, `Writable.write`, `vscode-jsonrpc/lib/node/ril.js:90` (`WritableStreamWrapper.write`), then `common/messageWriter.js:141` (`StreamMessageWriter.doWrite`) and `:132`. This is distinct from the startup ownership defect above. The native extension host exits with code 0; the test runner exits 1. + +The locked `vscode-jsonrpc` is 9.0.2. In `lib/common/connection.js`, `sendRequest()` uses `new Promise(async (resolve, reject) => ...)` at line 1124. The executor awaits `messageWriter.write()` at line 1137. On failure, its catch rejects the actual request with `MessageWriteError` and then throws the original error at line 1150. That throw rejects the async executor's discarded promise. Catching the public request correctly cannot own the second promise. The cancellation helper already catches its returned cancellation promise, so this evidence points to request writing, not an unhandled cancellation notification. + +A deterministic Linux probe using the actual dependency creates a `PassThrough` output, destroys it, creates a real `StreamMessageWriter` and JSON-RPC connection, and calls `sendRequest('probe').catch(...)`. Without the wrapper, the bare connection caller receives code -32099 (`MessageWriteError`) and a separate process event reports `ERR_STREAM_DESTROYED`. A stronger matched before/after probe also disposes the connection on close, as LanguageClient does: both callers then receive -32097, but only the baseline emits the extra rejection. `/tmp/mcppls-jsonrpc-write-repro.js` with `baseline` exits 1, with `fixed` exits 0; JSON results are `/tmp/mcppls-jsonrpc-write-before.json` and `/tmp/mcppls-jsonrpc-write-after.json`. This directly reproduces the library defect. The native stack does not reveal which two original requests were writing; the source and controlled probe establish the defect without inventing those requests. + +WA-VSCODE-004 wraps each LanguageClient message writer. A failed write invalidates the protocol stream; the wrapper owns that write promise, reports the error and connection closure, ends stdin so a live server receives EOF, and normal connection disposal rejects outstanding requests. It does not register a process-wide rejection listener in production. With the wrapper, the controlled request receives code -32097 (pending response rejected on disposal) and no independent rejection. A second test verifies that a live transport returns its result and propagates a real server `InvalidParams` error unchanged. Both transport unit tests pass in 40 ms. Registry: [UP-V2](https://github.com/Sunrisepeak/mcpp-language-server/issues/24#issuecomment-6047724985). + +The actual Linux VS Code 1.132.0 development-path run with the existing assembled payload and `MCPPLS_E2E_ONLY='**/zCrashLoop.test.js'` passes both crash-loop tests in 5 s, leaves no unhandled rejection in the suite's collector, exits 0, and reports an unchanged workspace. Log: `/tmp/mcppls-crash-stream-fixed.log`. All 117 extension unit tests pass (56 ms), and TypeScript compilation succeeds. This confirms current Linux recovery behavior; it is not a negative baseline for the intermittent native failure. The deterministic failed-write probe is the negative control. A new native Intel macOS VSIX run is still required before claiming that native regression fixed. Remove the wrapper only after an upstream upgrade passes the deterministic failed-write regression with the guard absent. diff --git a/.agents/docs/2026-10-09-0.0.12-part2-implementation-status.md b/.agents/docs/2026-10-09-0.0.12-part2-implementation-status.md new file mode 100644 index 00000000..9e76c8c6 --- /dev/null +++ b/.agents/docs/2026-10-09-0.0.12-part2-implementation-status.md @@ -0,0 +1,267 @@ +# 0.0.12 Part 2 实施状态:Linux 性能根因与候选 + +> **历史记录。** 0.0.12 的最终范围、决策与实施见 [Part 3](2026-10-09-0.0.12-part3-convergence-plan.md) §8。文中 `.agents/docs/2026-10-08-0.0.12-part2-evidence/`、`.agents/docs/assets/`、`tests/evidence/` 等原始证据路径位于 `mcpp-language-server-0.0.12-evidence.tar.zst`([evidence-0.0.12](https://github.com/Sunrisepeak/mcpp-language-server/releases/tag/evidence-0.0.12)),完整增量历史在 `archive/0.0.12-joint` 分支。 + +日期:2026-10-09。本记录对应 [Part 2 方案](2026-10-08-0.0.12-part2-linux-modules-performance-plan.md)。用户已授权实施;两个 PR 不合入,发布资格仍未达到。 + +## 已完成的证据与范围调整 + +- 维护目标为 `linux-x64`、`win32-x64`、`darwin-arm64`;保留 Ubuntu 20.04 运行下限。Intel macOS 历史失败保存,不继续适配或作为门槛。 +- 已推送 PR 的引擎是 67 个补丁/67 条台账;本地已导出 0069/69 台账,最新候选进度见末节。PR head `d2140299d1a68a68d15acfb5f9ccec844621eea0` 的 CI `37797560280` 三平台与 Ubuntu 20.04 全部通过;实际 built merge checkout 为 `771501f43131a716419f07068b33a16fded8d49b`。这不包含私有 PCH 集成候选。 +- Linux third-party-import 原失败已解释并补齐契约:正文导入可保留完整审计的 import-free PCH;header 导入必须收缩。原生 Linux 的 12,187,172-byte PCH 在正文阶段合法保留,header 阶段收缩到 251,880 bytes。ARM macOS、Windows 均走保守收缩路径。三场景与五次实际 typed Sema 均通过,原始 artifact 归档在引擎 `tests/evidence/part2-linux/third-party-contract/`。 +- Manifest 插桩发现:622 个路径各 open/close 三次,只读一次,共约 9.22MB。代表性 replay 计量的底层 FS 成本约 7.53ms;额外 shadow hash 约 2.17ms,不能作为原 hash 的 exclusive 时间。需要文件会话来源证明才能合并重复 open;目前没有生产路径缓存优化。 +- 空 index 的 USR 候选通过 136 项 CompletionTest 和此前四次 GCC 插入,但短 A/B/A 的 edited 中位数仍约 240ms,没有关键收益,暂不导出。 + +## 当前 PCH 集成候选:正确性初步通过,性能负例 + +私有源 `/tmp/mcppls-pch-scan68-review` 基于最终 joint67 `66ed2d104d8affc9e75c82a5b015f9e6869a6b00`,涉及公共头文件的 141 个消费者已重建后才执行。已通过借用 entry eviction 后仍计费、当前正文选择新 import、same-size/same-mtime header 失效、`__COUNTER__` 函数体影响正文条件导入,以及选定现有前缀/alias/dirty-header 控制。不能据此称完整正确性通过。 + +首次原始 Qt std 探索回放四次真实语义与选定 GCC 插入均通过,但 cold 约 7.31s、warm 约 434/309ms、edited 约 1.33s,明显回退。精确 diff、构建配方、身份、报告与 trace 保存到引擎 `tests/evidence/part2-linux/pch-first-negative/`,没有导出 0068。 + +早期实验定位了两个候选实现问题: + +1. 成功路径反复重放 canonical-prefix/compiler/current-full manifests。源码计数有四次 prefix+compiler 成对验证、约五次 full manifest 验证,单次 proof revalidation 实测约 33–76ms。先设计同一 validate-and-consume 事务,保留输入变化、重建及可能 I/O 后的必要验证,不跨请求复用旧证明。 +2. 编辑触发 fresh scan 时,在读 PCH 前因宏向量顺序不同被误拒绝;随后候选拒用 PCH,语义执行增至约 1.19s。LLVM `DependencyScannerImpl.cpp` 已在 hook 前调用 `canonicalizeDefines`,候选却与普通 invocation 的原宏顺序比较。实际 Qt 两侧宏/value 集合一致。本地候选已对临时 owned PP 副本使用同一 LLVM 函数后比较,并补上 RAW 命中时实际宏/UsePredefines 来源与 PCH 产物完整性控制;不改真实宏或关闭 PCH 校验。这些属于候选实现问题,不能称为新的上游缺陷。 + +宏比较修复和验证事务合并后,PCH 辅助 Qt edited 单轮仍约 323ms;每次完整证明读约 33.64MB PCH 与 9.22MB其他输入,重复验证抵消扫描收益。missing/corrupt/same-size-mtime disk PCH 三项实际负例已能拒绝 RAW 证明并恢复 typed Sema,但新增产物读取成本尚未性能验收。该路线保留为未导出的实验,不作为主性能修复。 + +## 当前重点:按名称选择性加载导入声明 + +同引擎、原 URI/CDB/参数的全头文件/Modules 对照,全部真实 Sema 与 GCC 插入通过:短样本 edited 约 177ms/248ms,稳定语义执行约 53–56ms/132–136ms。Sema/ASTReader 插桩确认 Modules 的 `std` 查找约 17,192 个 ID,`GetDecl` 约 93–108ms,是主要增量。 + +私有选择性加载原型将 `std::ve` 加载降至 4,649 个 ID,Qt edited 单轮约 188ms、warm 114–118ms;真实 Sema/GCC、using/inline namespace/重载/fuzzy 控制及 136 项 CompletionTest 通过。只证明初步收益,不是 p95 资格。证据归档在引擎 `tests/evidence/part2-linux/{textual-module-pair,visible-lookup-profile,filtered-lookup-candidate}/`。 + +[正式接口设计与进度](2026-10-09-part2-filtered-visible-lookup-design.md):独立源 `/tmp/mcppls-filtered-lookup-formal` 已实现消费者显式提供名称谓词、clangd 复用实际 FuzzyMatcher、精确 source/context 的同步加载作用域,以及部分加载保留 external storage。新接口新增 consumer virtual 方法,全部 141 个 clangd 消费者与 7 个相关 LLVM 对象已重建并成功链接。140 项 CompletionTest 通过,包含普通 lookup、递归与取消返回作用域控制;不表示即时取消延迟资格已通过。无新增诊断插桩的各 1×5 短 A/B/A 中,候选 warm/edited p95 为 112.82/187.05ms,前后基线为 168.44/247.26 与 179.36/252.40ms;全部 36 个请求与选定 GCC 插入通过。证据位于引擎 `tests/evidence/part2-linux/filtered-lookup-formal/`。尚非 12 语境或正式 3×30 验收;这次短测对应正式导出前的开发候选;后续 0068 导出见下文。 + +其余 11 个 Qt 语境各 1×1 的 smoke 已完成,44 次语境检查全部通过:32 次要求真实 Sema 的回答、4 次 include 和 8 次注释/字符串空结果控制;48 次实际选定 GCC 插入全部通过。该矩阵部分时段与单测重编译重叠,延迟不作正式验收。短 std A/B/A 的基线与候选各次 65 个返回项,全部 label/kind/实际编辑元组一致。普通查找控制已补强并通过:被排除名称在选择前后均确实未加载,之后普通 lookup 可找到,完整加载可关闭 external storage。源码本地提交 `7db2e70ab` + `55dee6865`,当时未导出,当前 0068 尚未推送到 PR;证据位于引擎 `tests/evidence/part2-linux/filtered-lookup-matrix-smoke/`。 + +**关键 std-qualified 3×30 已完成并达到该语境的 Linux p95 门槛。** 3 个 cold、93 个 warm、90 个 edited 请求全部通过真实 Sema,186 次实际选定 GCC 插入全部编译通过,零缺失。warm p50/p95 为 107.58/117.54ms;edited 为 181.44/192.28ms,三个启动各自 edited p95 为 188.96/188.74/196.51ms。edited 最大 204.59ms,有 1/90 次超过 200ms,保留完整尾部,不把 p95 门槛解释为每次均≤200ms。cold p95 3535.89ms 单列。引擎测量期间没有并行编译;所有插入编译在测量结束后运行。证据位于引擎 `tests/evidence/part2-linux/filtered-lookup-std-3x30/`。这不证明其余 11 语境或最终发布资格。 + +**其余 11 语境的 3×30 分布也已完成。** 与 std 相同引擎 SHA,全部 2,046 次语境检查通过、零缺失,所有请求 reader 和资源 sampler 均正常退出;带数值门槛的语境 warm/edited p95 全部通过。ordinary/first-column edited p95 为 184.06/184.38ms,其他正例最高为 module-member 139.71ms;注释/字符串 372 次均保持空结果。加上 std,共 2,232 次语境回复,其中 1,674 次要求真实 typed Sema 全部通过、include 186 次。其余语境的 GCC 插入按每启动/每阶段首个、末个与最慢的不同回复抽样,对所有 expected symbols 共编译 246 次;与 std 全部 186 次合计 432 次通过。不能称 2,232 个回复全部编译或覆盖所有候选组合。原始报告、实际编辑/编译证明、SHA 与逐条复算审计归档到引擎 `tests/evidence/part2-linux/filtered-lookup-matrix-distribution/`。 + +新增精确 source/context 绑定和 namespace alias/名称遮蔽控制通过,CompletionTest 总计 142 项通过。后者比较真实 PCH 外部声明与相同的普通本地声明,包含签名、snippet、kind、bundle 与 qualifier;它不替代真实 Modules 的表合并/override/可见性或 LSP resolve 验证。 + +## 正式 0068 导出与干净构建进度 + +完整四格匹配对照已完成,每臂 3 启动×30 轮、186 次真实 Sema;全部引擎测量结束后,81 次按首个/末个/最慢回复抽样的实际 GCC 插入通过。原 URI、CDB 字节、参数、原磁盘源均保持;每臂使用独立新缓存。数据位于引擎 `tests/evidence/part2-linux/filtered-lookup-four-arm/`。 + +| 相同 std-qualified 场景 | 全头文件 baseline | Modules baseline | 全头文件 candidate | Modules candidate | +|---|---:|---:|---:|---:| +| warm p95 | 82.10ms | 176.53ms | 54.16ms | 117.18ms | +| edited p95 | 184.52ms | 255.22ms | 155.90ms | 188.61ms | + +Modules edited p95 改善 26.10%,全头文件改善 15.51%;两侧 edited 差额从 70.70ms 降到 32.71ms。候选 Modules 仍比候选全头文件慢约 20.98%,不能称完全对齐。每种依赖模式内,基线/候选全部 186 个回复的所有返回项关键字段和实际编辑元组一致;全头文件每次 23 项,Modules 每次 65 项,不断言跨模式候选集相同。 + +另有两项真实 Modules ASTReader 控制通过:五个独立模块的名称表、普通查找触发表合并、后续模块更新表,均保留所有重载;选定加载不加载被排除名称,之后普通 lookup 仍能加载它们,最终全量加载可正确关闭 external storage。连同既有三项,NamespaceLookupTest 共 5 项通过;CompletionTest 142 项通过。局部测试的编译/链接失败原记录保留,最终成功日志和精确配方在引擎 `tests/evidence/part2-linux/selective-lookup-export68/`;局部对象测试不替代干净构建。 + +**正式 series 已新增 `0068-UP-25-selective-external-namespace-completion.patch`,引擎本地提交 `b053791302aa4695d0e5c2281df73b0307e2b3a3`,68 补丁/68 台账检查通过,状态 stabilizing。** 导出源为 `c3af7d1512fa708470b128c091f55afaa2dee546`,合成导出 commit `c74a6aa5f650e26907703832d04ba4a3c7899dfa`;未混入 PCH 辅助或 empty-index 负收益实验。三平台 CI 配方新增 CompletionTest/NamespaceLookupTest 运行,完整重建 AllClangUnitTests、CIndex test tool 和 clang-repl 消费者。 + +Linux 新构建 `/tmp/mcppls-part2-clean-selective68/` 已从校验通过的固定上游 tarball 提取、应用完整 68 series;所有 11 个修改源文件与已测源 SHA 逐一匹配,configure 通过,完整构建/测试正在运行。series SHA `ca95a5118281de2d0ac427823db0fb04ea2d77b53bb9d91aa9c693313807ab9e`。尚未生成最终合格 kit/payload,也没有推送该新补丁或合入 PR。 + +已找到本地官方 stock 23.1.0 二进制 `/home/speak/.local/share/mcppls/payload/clangd/bin/clangd`,报告 LLVM pin 相同,SHA `c52547480ebac0f2887bb70e34bdfb54a0841d6bc84881c21e66de81c1bf2b0b`;匹配的正确 stock 路径尚未实际测试,不能以找到二进制代替性能资格。 + +## 尚未闭环的验收 + +| 项目 | 当前判定 | +|---|---| +| edited p95 ≤ 200ms | 12 语境本地 3×30 完成,带性能门槛的语境全部通过;最终同源资格尚未验收 | +| PCH 失败/缺失/损坏、完整宏与命令、取消/并发/资源控制 | 未完整验证;仅选定控制通过 | +| 12 语境各 3 启动×30 轮、实际插入和边界、匹配 stock A/B | 开发候选分布与选定插入通过;四格分布和选定 Modules 表边界通过;stock、resolve/可见性和最终同源构建仍待完成 | +| 同一产品仅换引擎、raw/cache 分开、VS Code/C7/UP20 | 未完成 Part 2 最终闭环 | +| 干净构建、最终 series 字节一致性、三平台同源不可变 kit/payload | 68 series 干净源应用及 11 文件字节一致通过,Linux 完整构建运行中;最终 kit/payload 未完成,产品 lock 仍为 stock | +| Windows 稳定性旧失败根因、同源 PDB/corpus 的 UP12/UP13 | 未闭环;产品 `236c947` CI `37797556975` 已完成 success,但使用 stock payload,不证明新引擎最终稳定性或历史失败根因已修复 | +| 1000 saves、资源上限与增长、7 次合格 nightly、每平台 ≥2h RC soak | 未完成最终候选资格 | + +性能负例只用于定位;不以单轮通过、正式67 CI 全绿或旧产品结果替代最终发布证据。完整门槛继续按 Part 2 与其引用的联合方案执行。 + +## 后续核验:干净消费者与剩余声明成本 + +完整 0068 干净构建已编译链接通过。首次 build 因磁盘空间写入失败;同一源/参数/对象构建在专用 tmpfs 编译临时目录继续,保留原失败日志。16 lit 和 251 clangd 定向测试通过。AllClangUnitTests 随后因 libclang 的间接 libstdc++ 依赖缺少可见运行库而启动失败;可执行文件 RUNPATH 不传递给该共享库。显式选择本地编译器运行库后,5 NamespaceLookupTest 和 2 PositiveScanMemo 测试通过,没有改源或重编译来处理此失败。这不替代最终包的运行库/可迁移性验证。 + +新增消费者探针已实际运行:CLI 与 CIndex 在文本/PCH 两种输入保留 vector 两个重载和 version,返回逐行一致;interpreter 普通声明执行 smoke 通过。七个阶段退出均为 0。首版探针的 PCH 构建/补全阶段同名,导致日志覆盖;首版结果保留,修订版使用七个独立阶段和日志重新验证,作为有效证据。探针接入 CI,跨平台运行尚未完成。完整日志、工具 SHA、原失败、运行库来源和消费者证明位于引擎 `tests/evidence/part2-linux/clean-selective68/`。 + +0068 剩余加载的私有分组计量已归档 `tests/evidence/part2-linux/selected-decl-profile/`。四次 std 加载各含普通名称 13 IDs、operator 1,887 IDs、推导指引 1,425 IDs、literal operator 99 IDs。推导指引 GetDecl 线程 CPU 为 28.07–33.25ms;operator 为 18.36–22.09ms。计量与编译重叠,只支持成本定位,不支持端到端延迟结论。 + +下一私有候选按推导指引所属模板 identifier 应用既有谓词;operator/literal/using 保持原策略。生产对象已编译链接,alias/snippet 与普通声明返回对照通过;普通指引查找测试修正真实反序列化前置条件和隐式 guide 的 FunctionTemplateDecl 包装断言后,144 项 CompletionTest 全部通过。私有源提交 `5cd03e1fd`,尚未导出 0069,尚无最终性能验收。 + +正确 stock 原生 libc++ 探索也已归档 `tests/evidence/part2-linux/native-libcxx-stock-exploration/`:实际 Clang 编译器构建 std BMI/importer;stock 冷回复未返回目标真实类型,随后三次真实 Sema 通过,0068 四次通过。原 fixture 只绑定 vector 第一模板参数,导致两侧插入均编译失败;保留原失败,对同一实际返回编辑补齐 allocator 后,stock 可用三次、候选四次插入全部编译通过。准备脚本已修正未来绑定,但原报告不改写。这些测量与编译重叠,不满足 stock 性能对照或冷正确性门槛。 + +最终同源 payload、产品闭环、剩余性能差额、资源资格、三平台与长期发布验证均继续待完成;两个 PR 不合入。 + +### 推导指引候选的实际结果与下一步 + +私有源 `5cd03e1fd` 已编译链接,144 CompletionTest 全通过;同一新增查找测试替换回 0068 ASTReader 后按预期失败,证明它能检测原路径提前加载被排除模板的工作。短 A/B/A 的 36 次真实 Sema 与 36 次选定实际 GCC 插入通过,各回复全部 65 项关键返回字段及实际编辑一致。该轮遭遇外部 xlings 并行编译,延迟全部排除资格。 + +候选私有计量的四次 std 加载均为普通 ID 13、operator 1,887、推导指引 48、literal operator 99。推导指引 GetDecl 线程 CPU 为 2.41–2.80ms,相比 0068 的 1,425 IDs 和 28.07–33.25ms 明确减少了工作。计量仍只作归因。 + +外部编译结束后的无新增插桩各 1×5 A/B/A:edited p95 为 baseline-before 192.56ms、candidate 183.83ms、baseline-after 185.03ms;warm p95 为 118.80/113.07/112.39ms。36 次真实 Sema 和全部返回项编辑字段一致;未重复 GCC 编译,同 SHA 引擎的选定插入证明保留在前一组控制。短样本差额小,不能宣称已稳定改善 28ms 或已与头文件版本对齐。 + +补充单轮 native trace:edited Sema semantic execution inclusive 为 85.43/64.39ms,populate 为 19.71/27.02ms,merge 为 8.67/18.36ms;populate/merge 嵌套在 semantic execution 内,不能相加。两侧标准库 index 就绪时序不同,这些 wall span 不是匹配分布,也不能将多出来的 merge 成本全部归因于筛选。下一步控制 index 时序并区分 Sema 本体、候选材料化与 merge exclusive 成本,验证净收益后再决定导出;operator 仍是已计量的后续重点。 + +全部源 diff、编译/链接命令、失败与成功日志、反向控制、原报告、负载记录及 trace 已归档引擎 `tests/evidence/part2-linux/filtered-guides-candidate/`。引擎本地证据提交 `a05fd0a`(干净构建/消费者)与 `b0ac773`(私有指引候选),均未推送;正式 series 仍为 68 补丁。 + + +## 运算符名称筛选候选:完整 Linux 对照 + +私有源 `31c43d3a2` 在推导指引筛选之上,按实际补全 TypedText 筛选 operator 名称;consumer 谓词改为 StringRef。特别处理 `operatorco_await`,不使用其诊断显示名称 `operator co_await`。未知名称保守保留,普通查找及后续完整加载沿用原行为。全部 141 clangd 消费者和 7 相关 LLVM 对象已编译,146 CompletionTest 和 5 NamespaceLookupTest 通过;CIndex/interpreter 的新候选最终干净构建仍待完成。正式 series 仍为 68,候选未导出 0069。 + +无新增插桩的完整四格对照,每臂 3 启动×30 轮: + +| p95 | 全头文件 baseline67 | Modules baseline67 | 全头文件候选 | Modules 候选 | +|---|---:|---:|---:|---:| +| warm | 82.10ms | 173.32ms | 37.90ms | 76.16ms | +| edited | 180.13ms | 250.61ms | 134.67ms | 144.09ms | + +Modules edited 改善约 42.50%;候选两侧 edited 差距约 9.43ms(7.00%)。warm 仍差约 38.26ms,不能称所有阶段均已对齐。四臂共 744 次真实 typed Sema 全通过,各依赖模式内 186 个 baseline/candidate 回复的全部返回项编辑字段一致;跨模式候选数分别为 23 与 65,不断言候选集合相同。计时结束后的首个/末个/最慢回复抽样共 83 次实际 GCC 插入通过。 + +两次无效 Modules 计时保留并排除:第一次外部编译重叠;retry1 与本代理私有 clangd 计量同时运行,属于调度失误,编译进程监测未覆盖另一 clangd。最终采用单独 retry2;其他三个有效臂保留,计量报告结束早于 baseline-modules 开始约 37.42 秒。有效臂的 200ms 编译/ninja 采样均未观察到重叠、无错误且线程正常停止;不将其解释为整个主机绝对空闲。证据位于引擎 `tests/evidence/part2-linux/filtered-special-names-candidate/four-arm/`,包含原始无效记录与逐回复复算审计。 + +私有计量显示 `std::ve` 的 operator 选定 GetDecl 从 1,887 IDs 降到 0,推导指引保留 48 IDs;该计量与无效 retry1 重叠,只证明减少加载工作,不作延迟资格。最终同源消费者、12 语境、正确 stock 对照、产品与三平台/长期发布验收仍待完成,两个 PR 不合入。 + + +后续导出:本地 series 已新增 `0069-UP-25-selective-guide-operator-completion.patch`,69 补丁/69 台账检查通过,stabilizing;合成源提交 `499609a2a1503ea7fef404e5b72fbb2e9fa2a9f2`,series SHA `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。完整四格证据、两个无效计时和源身份已归档。独立干净目录 `/tmp/mcppls-part2-clean-special69/` 正从固定上游 tarball 应用完整 series 并重建全部消费者;当前仅构建启动,不作为通过证据。旧 0068 构建和基线保留,新候选尚未推送,PR 不合入。 + + +### 0069 干净构建与最终测量准备 + +干净源 `/tmp/mcppls-part2-clean-special69/llvm-project` 已完整应用 69 series,HEAD `4b26052750b46f7fbfaceb5bd3c7c16b0d01f2ca`;全部 11 修改文件同开发候选字节一致,configure 通过。完整消费者构建进程仍实际存活,尚未完成编译/消费者测试;不将 0068 的通过记录移作 0069 资格。已准备最终 12 语境短控制和 3×30 分布脚本,构建未通过时禁止启动。 + +引擎本地 `5c072d6` 补齐请求发送/观察回复与 /proc 采样的共同 `time.monotonic_ns` 时间标记,普通和延后回复的真实子进程关联控制通过,共享 replay 的四项 soak 回归控制通过,并接入 verify-series。历史资源记录没有此标记,不能可靠分离冷/稳定期;当前只验证计量管线,尚未证明最终稳定期 CPU/RSS 无 20% 退化。采样不包含子进程,也不证明硬内存上限。 + +正确 stock 短对照已准备但未运行:两侧显式 `--completion-parse=always`,保持同一实际 Clang/libc++ 输入并要求真实 Sema。既有 stock 默认 auto 冷请求的两个标识符回复继续作为负例保留;该对照不能替代产品默认冷行为验收。两个 PR 仍不合入。 + + +### 打包源绑定与开发候选产品语义 + +引擎本地 `79ae8d6` 修正独立 LLVM_DIR 打包时仍从仓库默认 llvm-project 取 canary 的问题。package_identity 显式接收实际源目录,核对 CMake 源路径、源提交和 patch marker,拒绝脏源;能力 canary 从已核对源树读取,包身份记录 llvm-tree-commit。独立目录正例及错误目录/提交、脏源、旧 marker 四个负例通过;当前干净 0069 源目录也实际核对通过。series digest 不变,当前编译不重启。最终 stripped 包的能力执行仍待构建结束后完成。 + +开发候选产品 inferred smoke 的 17 项检查全部通过,包括 C7 新导出生效、限定名补全、诊断、定义/hover、references 和 semantic tokens,实际返回 ID 与 fixture 逐项一致。初次以裸私有 binary 启动时缺少邻接 resource headers,探测失败并找不到 stddef.h;已取消无效运行,保留原失败,再以 SHA 不变的 binary 和匹配 LLVM23 headers 正常目录布局、独立工作区/缓存运行通过。不能将配置负例归为引擎回归。 + +该组明确观察到并行编译负载,所有时间/资源数值排除资格;它只用于提前发现产品语义集成问题,不替代最终干净引擎/kit/payload、同一产品 A/B 或真实 VS Code 验收。证据在引擎 `tests/evidence/part2-linux/filtered-special-names-candidate/product-inferred-development/`。两个 PR 不合入。 + + +### 0069 干净消费者通过、正确 stock 路径与可移植包进度 + +Ubuntu24 本地干净构建已完整退出 0:16 lit、255 clangd 定向测试、5 NamespaceLookupTest、2 PositiveScanMemo 及 CLI/CIndex/interpreter 七阶段全部通过。实际二进制 SHA `80012b732be4c55a4d5df49087cb2856519f3f98116951e0ee5196e164607088`,源 `4b26052750b46f7fbfaceb5bd3c7c16b0d01f2ca`,series digest 保持 `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。12 语境短控制的 48 次检查与 52 次实际选定 GCC 插入通过,全部带数值门槛的短控制通过;这不是各 3×30 的完整分布。 + +stock 显式 `completion-parse=always` 的冷请求仍返回空结果,真实 Sema 失败;后续三次通过。日志观察到 preamble 先构建、std 模块随后发布,完整根因尚未闭环,不能只归因 auto 文本回退。该负例保留,不当作正确性能基线。同输入候选冷控制四次真实 Sema、四次实际 native 插入通过。 + +新增显式 AST-ready-only 测量模式,先等 documentSymbol,再请求 warm/edited,报告明确 cold completion 未请求;默认模式仍记录冷请求失败。阶段/草稿与资源观察不进入延迟计时的控制通过。相同 source/CDB/Clang/libc++ 输入的短 stock/candidate/stock 对照共 9 次真实 Sema、9 次实际 native 插入通过,各回复全部 18 项的关键字段及实际编辑一致;edited 为 79.71/14.49/82.97ms。该短样本支持继续完整验证,不作正式 50% 门槛结论;stock 冷失败单列,没有改写为通过。 + +资源探针增加补全请求前后的直接 CPU/RSS 快照,计量读取在请求计时之外;普通/延后回复与刻意慢观察器控制通过,共享 replay 四项 soak 控制通过。该工具能界定主进程稳定期 CPU 增量;子进程和硬内存上限仍待另验,不以工具测试替代资源资格。 + +可移植 Linux 包已开始在本地缓存的 Ubuntu20.04.6/glibc2.31/Clang12/CMake3.31 镜像中构建,镜像 SHA `96ddf5cedf5352ca5c4f1608185f4ddc885ca4ee51ff0a4ca461779e429dcb29`。使用同一只读应用源、全 69 series,关闭网络,保存对象/日志,具有明确总期限和容器清理。该构建尚未完成;完整最终 12 语境、stock 分布、资源和产品验收将绑定可移植包的最终字节,不将 Ubuntu24 开发构建代替下限分发资格。证据归档引擎 `tests/evidence/part2-linux/clean-selective69/`,本地提交 `fcce580`。两个 PR 不合入,新工作尚未推送。 + + +### 稳定期资源复算与最终字节探针准备 + +引擎本地 `affe666` 提供 `tests/probes/resource_window.py`:稳定期从首次 AST-ready 补全前的直接快照到最后回复后的快照,CPU 包含其间 AST 工作,排除 cold;保留 utime/stime 的计数分辨率不确定区间。语义失败(包括 cold)、缺失边界、采样错误/未退出、时钟乱序、CPU 倒退和非有限 RSS 都拒绝资格。纯控制和真实子进程端到端共三项资源控制通过。该工具只复算主进程资源,不证明子进程预算或硬 RSS 上限;正式资源比较尚未执行。 + +Ubuntu20 下限构建进程已实际核验仍存活,clangd 已链接,AllClangUnitTests 对象仍在编译,尚未进入完整测试/最终包能力与 floor 验证结论。最终探针位于 `/tmp/mcppls-part2-floor69/qualification/`,显式指向该构建的 stripped 包和资源目录,检查包 SHA/实际 floor verdict,再运行短控制和完整分布。当前没有启动最终延迟测试。两个 PR 仍不合入。 + + +### Ubuntu20 最终包通过,最终字节验收开始 + +`/tmp/mcppls-part2-floor69/progress.json` 已记录完整流程退出 0:离线 Ubuntu20.04.6/glibc2.31/Clang12 全量构建,16 lit、255 clangd 定向、5 NamespaceLookup、2 PositiveScanMemo 及 CLI/CIndex/interpreter 七阶段均通过,打包成功。最终 stripped 二进制 SHA `b7eba8bfdd1c26ff93ba4fba53678916a9f8d3d4e79ce3cf1a97375a07593e8f`,fork `affe666292c6b53b842df1d217a811bdfc85e47c`、源 `4b26052750b46f7fbfaceb5bd3c7c16b0d01f2ca`、series `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。实际 glibc2.31 运行检测无问题,最高 GLIBC 符号要求 2.29,无动态 libstdc++ 依赖。该 floor 检查验证依赖解析与启动,不声称产品全工作流已在 Ubuntu20 运行。 + +最终包的 12 语境短控制已启动,采用匹配邻接 resource headers、fresh CDB/cache,检查实际包 SHA 和 floor verdict。native AST-ready stock/candidate/stock 完整 3×30 脚本已准备,逐请求核对 phase/draft/全部返回项关键编辑字段;计时全部结束后按每启动/阶段首个、末个、最慢回复选择实际 native 编译。CPU/RSS 将使用新边界计量复算主进程稳定窗口,保留 CPU tick 不确定区间,不代替子进程/硬内存验收。当前最终分布、资源与产品验收仍未通过;新工作未推送,两个 PR 不合入。 + + +最终 stripped 包短控制全部退出 0:12 语境共 48 次请求检查(其中 36 次要求 typed Sema、4 次 include、8 次空负例),52 次选定 GCC 插入全部通过,所有带数值预算的 warm/edited 短样本通过。native candidate 独立冷控制共 4 次真实 Sema、4 次 native 插入通过。匹配 AST-ready stock/candidate/stock 短对照 edited 为 86.88/17.49/90.03ms,9 次真实 Sema、9 次 native 插入、全部返回项编辑字段一致。零观察到的 compiler/ninja overlap,采样无错误且停止。短对照通过后已启动最终包 native AST-ready 3×30 完整 A/B/A;完整 12 语境分布仍待顺序运行。上述 stock 对照明确不请求 cold,不改写既有 stock 冷空回复失败。 + + +最终包的 native std AST-ready 匹配完整分布已退出 0:每臂 3 次启动×30 轮,stock-before/candidate/stock-after 各 183 次真实 typed Sema,共 549 次;全部返回项关键字段和逐请求 draft/phase 一致,49 次选定实际 native 插入通过(16/17/16)。edited p95 为 89.234/22.159/89.194ms,两侧均改善约 75.16%,满足该正确稳定路径 ≥50% 改善门槛;明确不包含 stock 冷请求,既有失败不改写。 + +主进程稳定资源窗口 CPU 保守区间为 before 23,240–23,360ms、candidate 13,100–13,220ms、after 23,250–23,370ms;采用保守的候选 CPU 上界/基线 CPU 下界,比分别约 0.56885/0.56860。每臂三次启动中最大观测 RSS p95 为 478,848/277,300/483,740KiB,比分别约 0.57910/0.57324;该 native 场景主进程未观察到 20% 退化,不外推所有场景、子进程或硬内存预算。完整 Qt 12 语境 3×30 正顺序运行,暂未有最终 verdict。floor 构建和短控制/native 分布归档 `tests/evidence/part2-linux/portable-selective69/`;最终产品、三平台和长期资格仍待完成。 + + +最终 Qt 完整分布已发现性能负例:first-column 全部 186 次语义请求和选定插入通过,但 edited p95 `201.221592ms`,超过 200ms;warm p95 `127.374283ms`。保留原报告,不提高门槛、不重跑挑选较快结果。完整矩阵仍在顺序运行。源码核查发现当前选择性外部名称加载只接入 qualified-id 的 DeclContext 路径;expression 的 Scope 查找仍走普通 LookupVisibleDecls,且选择性加载限定 NamespaceDecl、不包括 TU。这是下一步归因线索,尚未证明此次超标的 exclusive 根因。独立 first-column/ordinary trace 脚本已准备,须等完整矩阵结束且确认没有另一 clangd/编译进程才启动;trace 只作归因、不替代分布。 + + +### 最终 Qt 完整矩阵失败与 Scope/TU 修复候选 + +Ubuntu20 最终包的 12×3×30 分布实际终止退出 1:2232 次请求检查(1674 typed-Sema 要求、186 include、372 空负例)全部通过,251 次选定真实 GCC 插入通过;两个 edited 性能预算失败为 first-column 201.221592ms、ordinary 210.724679ms。std-qualified warm/edited p95 83.982920/156.240325ms,通过 200ms。原始全量报告、terminal verdict、插入与负载记录已归档 `portable-selective69`,不挑选更快重跑替代失败。 + +最终包独立 1×3 native trace(不是资格分布)显示首列/普通补全的语义执行约 75–80ms,edited 模块验证约 84–96ms;populate/merge 嵌套在语义执行内,不能相加。独立私有单对象计量确认每请求 TU 枚举 10,488 个声明,线程 CPU 中位枚举约 29.22/28.90ms、消费约 6.19/6.08ms,未启用名称筛选。该计量是 GCC 开发构建,只归因工作量,不将 CPU 数值当作最终 Clang12 包的净延迟收益。源、编译/链接配方和原报告归档 `unqualified-visible-lookup-profile69`。 + +私有源 `/dev/shm/mcppls-part2-unqualified70` 已将 completion 专用借用谓词接入普通名字/表达式的 Scope 查找,并允许 C++ TU 外部名称选择性加载;局部/using/隐藏/可见性遍历和普通 lookup 保留。只新增非 virtual Sema 方法,不改变类布局/已有 virtual ABI;两个 Sema 对象和 completion tests 重建,复用未变的69消费者。两项新增 PCH/文本遮蔽、using、inline namespace、重载/编辑字段与 TU 后续普通加载控制,以及146项既有 CompletionTest 通过。私有候选 SHA `b113434672d4a28ab600737e3acd3c5463618d306ff3b02c086a2f6a95e1669e`,最终全量干净构建仍待证明。 + +首列默认 top100 的短 A/B/A edited 为 182.78/156.07/197.59ms,但全部返回项对照失败,不能作为合格收益证据;前后同基线也不同,实际出现 std/chrono 等索引候选在截断边界交换,全部 typed Sema 和核心目标仍通过。另加不限 engine 返回数量且等待索引发布/正匹配的正确性短对照,三臂实际返回项和编辑字段一致(cold 90,stable 162/164),但初次工具错误要求 `isIncomplete=false`;原失败保留,改为离线核对实际字段和两侧相同的 legacy incomplete 标记,再完成实际插入,不重跑挑数值。该不限数量控制只证明实际返回答案一致性,不能宣称所有索引候选完全返回或默认工作负载性能已验收。候选尚未导出0070/推送,两个 PR 不合入。 + + +### 0070 正式导出与最终干净构建 + +Scope/TU 源提交 `3510dc8091144c9f6ed0a573a3a7931b9c10b32b` 已干净保存,合成导出 `441be72d5ca0274541bc1a1ad601425eb42c2887`、patch SHA `687c16bfc431b87c82eae34b1d86e14a447fcb7106559c61481649b1757df27e`。正式 series 为70补丁/70台账,SHA `710c2c8e380defe1be146a8a66f44d1c5e9216a6ebe4fde510372b516e22f424`,stabilizing;引擎本地提交 `5727d43`,未推送。默认限制且明确等待 std 索引发布/实际正匹配的首列与普通短 A/B/A 各1×5:edited p95 分别181.596/168.870/177.618ms与172.074/157.217/178.541ms,72次真实Sema、39次选定实际GCC插入通过。各默认返回项/编辑字段属于已验证的不限engine返回数量参考集合;不宣称top100截断集合跨进程完全相同。不限数量控制另有24次Sema/24次实际插入,原始错误完整标记断言和默认未稳定对照失败保留。 + +新的完整70series已从固定并验SHA的缓存tarball独立应用,源HEAD `100a1273fe05d674e67712b05343b29f19f8075b`。全tracked树逐路径mode/blob核对,与开发源只差`.mcppls-clangd-fetched-`这一fetch metadata marker,全部源码相同。源/对象分别位于`/dev/shm/mcppls-part2-floor70-source`、`/dev/shm/mcppls-part2-floor70-build`;最终包和日志保留在`/tmp/mcppls-part2-floor70`。首次启动在2GiB root预检处拒绝,没有启动Docker/编译;前次完整包约70.48MB,按仅包/日志落root重新核算为1GiB预留(超过前包4倍),另保留8GiB shared-memory预检后已启动离线Ubuntu20/glibc2.31/Clang12全量构建。该构建实际在编译中,尚未通过消费者/包/floor测试。旧69的源码、构建、二项性能失败及全部负例保留,不以开发短样本替代最终70验收。 + +证据:`portable-selective69`(完整最终69分布/负例)、`unqualified-visible-lookup-profile69`(工作量归因)、`unqualified-visible-candidate70`(候选源/编译/全部实验及修正)、`selective-unqualified-export70`(导出身份)。最终70分布、稳定资源、产品/kit/payload、VS Code、其他支持平台和长期发布门槛仍待完成;两个PR不合入。 + +### 2026-10-09 依赖闭包修复:有效回归与原 UP20 严格健康通过 + +准入等待解决暂时容量拒绝后,继续诊断发现每个 producer 的缓存键绑定整个 build-wave 已完成模块快照,包含无关 root。实际 Shared→Base→Leaf 只应依赖这条链;另一个 consumer 导入或编辑 Noise 也改变 Shared generation,导致多余构建、复制、发布与容量压力。这是 fork 自有 planner/cache 的过度绑定,不新增 upstream 缺陷声明。生产 0074 保存每个 node 的传递依赖闭包,派发 immutable filtered snapshot;未知/prebuilt leaves 保守保留。0073 typed capacity-pressure 等待仍在原 worker deadline 内且可取消,不增加预算、不驱逐活租约、不重试 corruption/identity/I/O 错误。 + +有效 baseline-v4 仅两项无关 root 的 Shared generation 等值断言失败,真实传递 Leaf 编辑失效控制通过;candidate-v2 全部77项 PrerequisiteModulesTests通过。较早 malformed 同行 import、错误稳定路径假设和 deleted-move 编译脚手架失败完整保留,不充作产品缺陷。候选增量 Clang12/Ubuntu20 engine SHA c6e0226543c1b1c5248c3d0f2d93cb1f6ed197966dc70522e4f04c42505c84af;不是最终干净发布构建。 + +原UP20固定 URI/CDB/source/8CPU、同产品server/runner与原72 frontend/resource/kit的一次严格回放实际退出0:prerequisites失败、准入拒绝、restart/errorStatus/unanswered均0,482源文件恢复、normal owned cleanup通过。2072 tasks中85次实际构建,上一准入候选2067 tasks/526 builds;观察到恢复5.129297235s、8 importer republish5.010125993s、probe2.603316186s。该回放显式 correctness-only,所有时间/资源排除资格;不能声明新导出≤5s、正式多启动分布或fresh Sema比例。既有C-2 engineShare仍可能含缓存复用。 + +独立 admission-only stage logger 回放严格wrapper退出1,保留四个cancelled prerequisite负例;2054 tasks的分段wall总和有并发重叠,不是exclusive CPU或请求critical path。生产series没有导出该logger。原始命令/日志/失败/manifest与哈希校验共64文件归档引擎 `tests/evidence/part2-linux/producer-closure74/`;原Data/RAM源码/构建/缓存保留。series现为74补丁,74 ledger rows检查通过,0073/0074均stabilizing;尚未推送,PR不合入。 + +下一步完整74 series从固定tarball干净应用、Ubuntu20所有consumer编译/测试/最终包与floor检查,再以最终字节完成正确语义下的Linux性能/资源对照。原warm约31ms差距、真实保存/VSCode/缓存物理预算/1000 saves/完整交付、Windows与ARM macOS原生、7nightlies和各平台2h soak等release门槛继续保留;Intel macOS排除。 + +### 2026-10-09 全74干净源一致性完成,Ubuntu20构建已实际启动 + +引擎本地提交59f49b2,series SHA3d4a5c31a24b70a14eba8e64a786ed542332e3afdec9db8749b9fe74c2c28ea2;固定tarball重新fetch/apply全部74补丁退出0,合成LLVM source HEAD26f25781727292d9ebc91afa1d68be5bfe29a04a。受跟踪全树与已通过77测试/UP20的私有源83740693f完全一致,差异列表为空。旧72/私有候选原source/build/package保留。 + +`/home/data_disk/codex-mcppls-part2-builds/portable74/`保存preparation/source-progress、原命令与日志。初次Docker执行在compiler启动前被Git safe.directory检查拒绝,原progress/run.log/配方保留;retry将global safe.directory设置放到预检之前。retry脚本初始文件名替换误改source-progress路径,也在启动container之前失败,原脚本快照保留,修复后启动。实际新container d638c901edec正在编译;会话10834、retry1-progress为running,不能提前当作构建/测试/package/floor通过。离线Ubuntu20/Clang12、6CPU/6jobs/无ccache,源码与repo只读;完整4744构建步骤及全部consumer gates沿用原配方,生成目标全新。 + +已准备最终74身份门控和raw12语境/stock三臂/header-module四格/独立资源脚本,均未执行;要求实际retry1 terminal complete、source/fork/series/包hash及floor全部匹配。四格baseline改为同配方最终72,严格要求编辑/文档字段multiset和重复次数完全一致,取消此前仅允许constructor去重的差异豁免。本轮没有并行计时。1000 saves、C-2实际命中计数(已有completion.late.arrived/served)、新exports、VSCode及其余release要求继续待验,不以准备脚本替代执行证据。 + +### 2026-10-09 最终74串行验收已排队,构建中的门控负例通过 + +当前完整74 Ubuntu20构建container仍实际存活,尚未形成测试/package/floor verdict。最终字节identity模块在实际running build下拒绝启动计量,保存 `portable74/qualification/build-running-preflight-negative.json`。串行driver已启动(会话21052,PID2624204),绑定实际Docker CLI PID2613777/start_ticks13739873及container d638c901edec862b1c84381f9f7b3f935e9a0088d7bc744f8de1e0fd0a3086d6;目前状态waiting-for-live-build、stages为空。等待的是已核验运行句柄,非仅凭running文件假定仍活。构建失败或句柄丢失没有自动重建/重跑。 + +构建真实complete并通过source/fork/series/package SHA与floor门控后,driver依次执行matrix-control、header/module四格、12语境3×30、stock/candidate/stock native与独立observed-tree资源回放;任一实际失败即停止后续步骤、保留负例。manifest固定每份脚本SHA,单独driver progress/log保存实际执行和退出码;不把staging manifest的prepared状态称为验收通过。尚无新74延迟/资源结果,也没有发布、native Windows/ARM macOS、完整产品payload或nightly/soak资格声明。 + +原private回放的构建次数已独立按logger-prefixed `Module build task ... started` / `Built module ... to`重算,排除LSP JSON中的源文本:admission-only2067 tasks/526 builds,closure2072/85。日志原SHA/regex/逐模块计数保存在引擎producer-closure74/task-counts.json;manifest扩展为64原文件加1派生报告,全部65 stored/raw SHA复验通过。新增引擎证据暂不提交,以保持正在打包构建的fork HEAD59f49b2不变;源码/series未改变,PR不合入。 + +### 2026-10-09 最终74逐回复审计与同源kit已串行排队 + +完整构建仍实际运行,已进入clangd/Clang测试对象编译;没有提前声明consumer通过。新增post-raw driver(会话54104)绑定实际存活的serial-suite PID2624204/start_ticks13801151,只在其真实complete后运行四份逐回复审计,再生成新74同源Linux kit。失败即停止,不重启前序任务。审计核对所有raw语义来源、文档草稿、cold/warm/edited请求数、实际选定插入集合与nearest-rank p95;四格不再豁免constructor重复。选定first/last/slowest的实际数量随最慢样本位置变化,不照搬旧72运行的82项固定数量,完整集合仍必须逐项相等。尚未执行这些审计或生成kit。 + +新kit配方绑定完整74源码26f25781727292d9ebc91afa1d68be5bfe29a04a、新干净构建的实际clang producer和最终resource headers,并要求raw/resource各审计通过。仅复用同一固定Ubuntu20离线镜像中先前捕获的libc6-dev/linux-libc-dev拥有的1422个C/kernel头文件及许可证;逐文件hash已在新目录核对一致,保留reuse provenance,不冒称重新捕获。新目录 `portable74/same-source-kit/`,旧72 kit/capture全部保留;不在性能/资源计时期间运行kit编译。不可变payload锁、Linux完整产品运行下限、真实编辑器/1000 saves和其他平台/长期门槛仍待完成,PR不合入。 + +### 2026-10-09 全74 Ubuntu20干净构建、consumer、package和floor实际通过 + +会话10834实际退出0,retry1-progress complete;全4744步骤的新源/新build离线Ubuntu20/Clang12构建完成。16 lit、263 clangd控制(含新的准入等待/取消/deadline及依赖闭包控制)、5 NamespaceLookup、2独立PositiveScanMemo、CLI/PCH/CIndex/interpreter七consumer阶段全部通过;最终stripped package的能力canary与source/build identity检查成功。没有用private增量binary替代最终包。 + +实际最终engine SHA54fad6acab66d45f07ea1f080db56571b0ec4e3527496d0b10620fb0e522ace5,未strip build SHA1b731977d0278156742e7bcf1738e4f19e8d55b7cddbbb50fd1ef168845b4443,fork59f49b213f60444615659955f481ad7ae2ffb924,LLVM tree26f25781727292d9ebc91afa1d68be5bfe29a04a,series3d4a5c31a24b70a14eba8e64a786ed542332e3afdec9db8749b9fe74c2c28ea2。实际303 resource headers已绑定final-package-identity。glibc2.31 dependency/startup检查problems为空、最高GLIBC符号2.29、无动态libstdc++依赖;仍不代表完整产品Ubuntu20离线安装通过。 + +串行验收driver已从真实build terminal自动进入matrix-control.py,尚在运行;四格/完整12语境分布/native三臂/独立资源及逐回复审计、同源kit仍未通过,不能提前继承旧72性能成绩。当前正在计时,不压缩归档或启动其他编译/profile/独立engine。所有原始source/build/bin及首次Git所有权预检失败保留,待本批计时结束再归档。raw warm剩余差额、产品C-2实际来源/新exports/导航、VSCode/1000 saves/完整交付、其余平台与nightly/soak等原release要求继续待验;PR不合入。 + +### 2026-10-09 最终74短控制与完整四格通过,raw warm差额仍在 + +新54fad6ac包的12语境短控制实际退出0,全部真实语义、选定GCC插入及有数值门槛的短检查通过;不是3×30分布。随后header/module × final72/final74四格各3启动×30轮实际退出0,744 typed Sema和83选定GCC插入通过,编辑/文档字段的全部multiset与重复次数在对应模式内严格一致,没有constructor差异豁免。最近一次动态selected count为83,后序审计按真实first/last/slowest集合核对,不套用历史82。 + +| p95 | final72 headers | final72 Modules | final74 headers | final74 Modules | +|---|---:|---:|---:|---:| +| warm | 36.827849ms | 72.636054ms | 40.918935ms | 72.661976ms | +| edited | 134.845953ms | 145.773551ms | 141.786559ms | 146.862755ms | + +新74模块warm/edited与72基本相同;这两补丁没有宣称改善稳定raw补全。新74两模式warm仍差31.743041ms(约77.6%)、edited差5.076196ms(约3.58%),不能称已全头文件速度对齐。主进程稳定期candidate/baseline保守CPU比例headers1.026892/modules1.006011,RSS比例0.997717/0.951807,均通过<1.20;不是descendant/硬物理缓存预算或长期资格。精确逐回复审计和独立observed-tree回放仍排队。 + +会话21052已实际进入完整12语境3×30分布,不能提前报告全部语境通过。后序raw/native/resource审计及同源kit保持串行。产品driver(会话15094)绑定已验证存活的post-raw PID2638269/start_ticks13867327,仅在其实际完成全部审计与新kit后,依次执行新最终包+固定227fda4f服务器/c45bd02d runner的inferred、真实save-plan和原UP20严格whole-log健康回放;目前waiting,未执行产品。原UP20的482源码在准备时再次核对恢复,执行前后仍必须核对;不可用private c6e022候选的通过替代final54fad6包。产品这些回放均不宣称延迟/资源/1000 saves/发布资格。PR不合入,warm成本与其余完整release门槛继续待完成。 + +### 2026-10-09 最终74串行链全部完成,补齐PR同步 + +实际serial-suite五阶段、post-raw四项独立审计及新同源kit生成、product-suite的inferred/真实save-plan/原UP20严格健康三阶段均complete/exit0。12语境各3启动×30轮全部通过,选定GCC插入262项;不套用旧72的263项。此前文中running/waiting为历史记录,本段更新当前状态。进程树资源回放通过,但不证明硬物理缓存上限或长期RSS稳定性;产品回放仅correctness,不转化为延迟/1000 saves资格。 + +引擎tests/evidence/part2-linux/final74-receipts归档最终包身份、三条实际执行链、四项审计及四组summary,并记录原文件SHA;这是执行收据,不是完整raw-response可独立重跑归档。完整原始raw/log/scripts/proofs、失败、源/构建/缓存继续保留在portable74目录;完整归档集成仍待完成。producer-closure74的65文件stored/raw SHA再次全部校验通过,补提交派生计数证据。包绑定代码59f49b2,后续evidence-only提交不改变已验证包身份。 + +同步两个既有Draft PR的本地有效提交并更新描述,PR保持未合入。warm Modules与头文件差31.743041ms仍未修复;真实缓存命中、保存新export/导航/VSCode、1000 saves、物理缓存、完整Ubuntu20产品交付、Windows/ARM macOS、7nightlies和各平台2h soak仍待验,不声明达到release标准。 + +### 2026-10-09 引擎未推送历史清理与最新CI负例 + +首次引擎上传已主动中止,远端PR head仍d2140299;检查发现未推送的旧提交历史包含后续已删除的生成模块缓存payload.pcm及压缩副本。备份本地原history后,仅移除published base之后tests/evidence/**/.cache路径;新对象压缩占用估计226.5→71.92MiB(非实际网络pack大小)。清理前后最终tree与代码59f49b2的tree均严格相等;该代码提交的新history身份为0eb0f6a1dc7e6339a7974d23ea5ace2fd05f6383。构建/包原始receipt继续保留原59f49b2身份,history-cleanup.json记录对应关系;没有重新构建或更换已验包。忽略规则排除证据目录中的cache/PCM/PCH及压缩副本,原始本地backup不推送。只正常fast-forward push,不改写远端既有提交。 + +产品2de3fd1的CI run37886194151已经报告ARM macOS release的test_save_plan四用例失败(job113676623186);失败日志已取回,原因尚未建立。PR描述已写明该merge blocker,不称最新native全绿。其余发布门槛继续保留。 diff --git a/.agents/docs/2026-10-09-0.0.12-part3-convergence-plan.md b/.agents/docs/2026-10-09-0.0.12-part3-convergence-plan.md new file mode 100644 index 00000000..fadc4973 --- /dev/null +++ b/.agents/docs/2026-10-09-0.0.12-part3-convergence-plan.md @@ -0,0 +1,175 @@ +# 0.0.12 Part 3:收敛、整理与三平台合入/发布资格 + +日期:2026-10-09。状态:**用户已批准(§7:1、2、4、5 同意;3 改为分析原因并尽量支持 linux-arm64),授权实施、squash 合入与发布。** 实施记录见 §8。 + +前置文档:[联合方案](2026-10-07-0.0.12-joint-release-plan.md)、[Part 2 方案](2026-10-08-0.0.12-part2-linux-modules-performance-plan.md)、[Part 2 实施状态](2026-10-09-0.0.12-part2-implementation-status.md)。本文件不改动其正确性与身份约束,只调整 Part 3 的目标、顺序和门槛。 + +## 0. 一句话 + +Part 2 在 Linux 上把性能做到了门槛内;Part 3 **不再做新的性能优化**,改为先冻结内容、整理仓库和补丁,再用一次最终字节完成三平台合入资格(M1),最后跑发布长期验证(M2)。 + +## 1. 现状(以远端 head 为准) + +| 对象 | 状态 | +|---|---| +| 产品 #46 | head `0592ccd`,123 提交,439 文件 +50,183 行,其中 docs/evidence 约 47,688 行(95%)。CI 34 通过 / **4 失败**:`build and unit tests` 的 macos-14 与 windows-2022(dev+release)均为 `test_save_plan` 4/5 用例失败,Linux 通过 | +| 引擎 #2 | head `61ea393`,191 提交,**3,430 文件 +1,013,177 行,其中 evidence 981,407 行(97%)**,pack 约 70MiB;846 个 evidence 文件含 `/home/speak` 绝对路径;含复制的系统头(如 3.1MiB `arm_neon.h`)。三平台 build 运行中,verify/Ubuntu20 通过 | +| 补丁台账 | 74 补丁:69 stabilizing、5 draft、**0 steady**;台账规则仍是"Only steady rides a release"。UP-25 与 UP-03 合计约 50 个补丁 | +| 引擎包 | final74 Ubuntu20/Clang12,SHA `54fad6ac…`,fork code `59f49b2` ↔ 清理后 `0eb0f6a1`(同 tree) | +| 产品 lock | **仍为 stock clangd**;产品 CI 未运行 final74 | +| Linux 性能 | 12 语境 × 3×30 通过;warm p95 53–91ms、edited p95 133–168ms;对 stock edited 改善 ≥50%。Modules 对头文件 warm 差 31.74ms(72.66 vs 40.92),edited 差 5.08ms | +| 平台 | 声明 linux-x64 / win32-x64 / darwin-arm64;**v0.0.11 已发布的 linux-arm64 VSIX/payload 在本 PR 中被移除**;macOS deployment target 11.0→12.0 | + +上轮 review 中仍未处理:linux-arm64 决策、Darwin 裸 syscall 的 `#else` 守卫、Intel 构建残留(`mcpp.toml [target.x86_64-macos]`、`.tbd`、Intel neovim 脚本)、`format.fallbackStyle` 的 `Auto` 大小写、payload v4 魔数、后台索引优先级缺 Linux/Windows 负载证据、`PATCHES.md` 表格空行。 + +## 2. Part 3 的原则 + +1. **内容冻结。** 除 Windows/ARM macOS 原生失败的根因修复、本文 §4 列出的代码项外,不再加入性能优化补丁。31.74ms warm 差距转为 0.0.13 输入(§6)。 +2. **先整理,后资格。** 补丁合并、仓库历史整理、evidence 外移都会改变或重排已测身份;必须在最终资格运行**之前**完成,最终资格只跑一次。整理后若 tree 不同,旧证据只作开发参考。 +3. **合入资格(M1)与发布资格(M2)分开**,各自门槛在本文登记,不临时迁移。 +4. **证据是摘要 + 可校验指针,不是仓库里的原始数据。** +5. 测试投入预算沿用:不超过实现时间的三分之一;超出时报告并调整批次,不降门槛。 + +## 3. 工作分解与顺序 + +### P3-A:跨平台 save-plan 失败(阻断,先做) + +现象:macOS/Windows 的 `test_save_plan.cpp:171/188/202/214` 失败,Linux 通过;第 3 例在**保存前**的草稿重规划阶段就失败(:188),说明不只是 `880cc4b` 新增的 `saved_structure_is_planned` 判定。 + +首要假设(未证实):URI 派生路径与 model/plan 路径的身份不一致——macOS 临时目录 `/var` ↔ `/private/var` 符号链接,Windows 盘符/分隔符形态;`path_key` 不解析别名。 + +1. 本地 Linux 用符号链接根目录复现;若复现,即为产品级缺陷(用户工程在符号链接路径下同样受影响),不是测试问题。 +2. 在 workspace 对 `editedAt`、`structures`、`plan.entries` 统一使用同一规范化身份;保留原拼写用于显示与引擎消息。 +3. 新增 Linux 符号链接根与大小写路径控制,使 Linux CI 能抓住此类回归。 +4. 若假设不成立,以 macOS/Windows 原生日志定位,不放宽断言或延长 tick 掩盖。 + +出口:三平台 unit 全绿,`880cc4b` 的 UP20 正确性回放保持通过。 + +### P3-B:仓库与证据整理(阻断合入) + +证据策略: +- 仓库只保留:每项证据的 `manifest.json`(命令、身份 SHA、输入 SHA、结论、样本数、p50/p95、失败计数)与人可读摘要,单项建议 ≤64KiB。 +- 原始报告、日志、trace、复制的头文件/资源目录、压缩 report 移到**专用 GitHub release(如 `evidence-0.0.12`)资产**或 Actions artifact(注意 artifact 有保留期,最终证据用 release 资产);manifest 记录 URL 与 SHA-256。 +- 路径统一改写为 `${WORKSPACE}`/`${LLVM_SRC}`/`${TMP}` 占位;`ci/check_ledger.py` 或 devtools 增加检查:拒绝 `/home/`、`/Users/`、`C:\Users\`、单文件 >1MiB、`.pcm/.pch/.o`。 +- `.gitignore` 从仅 `*.pcm` 扩展到 `*.pch`、`*.pcm.gz`、构建目录产物与 resource 复制目录。 + +合入策略(需用户决定,见 §7-2): +- 推荐:合入前从当前 tree 生成**整理分支**(代码/测试/摘要 + 主题提交),以普通 merge 或 squash 合入;原 PR 分支保留为历史档案,不进入 main。main 的克隆体积不受 PR 历史影响。 +- 产品 #46 提交整理为主题:客户端崩溃/写入所有权、engine identity + payload v4、格式化 fallback、后台索引优先级、save-plan、模型初始化期限、CI/平台范围、文档。去掉先加后撤的 Intel 提交。 +- `.agents/docs`:Part 2 状态文档(日志体)压缩为结论 + 指针;联合方案/maintained 方案/Part 2/Part 3 标明当前有效与已被取代。 + +### P3-C:补丁系列定稿(阻断发布,建议阻断合入) + +1. 按主题合并 74 补丁为约 15–20 个可审阅补丁(例:模块扫描 memo/验证、DAG 调度与 worker 监管、缓存 lease/admission、preamble 策略、completion 选择性加载、directive 恢复/诊断、Windows crash dump、格式 preset、const-correctness、backport)。每个补丁自带测试,台账一行一补丁。 +2. 定义 `stabilizing → steady`:该补丁所在最终字节通过三平台 build+unit、所属 e2e 与 canary、无未解决的已知负例、drop condition 可检验。M2 前所有随发布补丁必须是 steady;5 个 draft 要么升级、要么移出 series。 +3. 合并后 series digest 改变:从固定 tarball 干净应用、Ubuntu20 构建、consumer 测试——这一步就是最终字节的起点(P3-E)。 +4. 修复 `PATCHES.md` 表格格式与无编号文件名。 + +### P3-D:产品代码收尾(合入前) + +| 项 | 处理 | +|---|---| +| Darwin `protect_pipe_write` | 守卫改为显式 macOS;改用 libSystem `fcntl(F_SETNOSIGPIPE)`(已有 `.tbd` 链接机制)或移入 openkal UP-O1;删除 x86_64 分支 | +| Intel 残留 | 删 `[target.x86_64-macos]`、`libmcppls_darwin.tbd` 与 build.mcpp 分支、Intel neovim 脚本及 allowlist、测试中的 darwin-x64 用例;历史证据保留 | +| `format_fallback_style` | `auto` 比较改为大小写不敏感 | +| payload v4 | 提取常量,assemble/verify 共用 | +| 后台索引优先级 | 补 Linux(SCHED_IDLE)与 Windows(background mode)CPU 繁忙时索引仍推进的证据;无证据则只在 Darwin 设默认 | +| linux-arm64 / macOS 12 | 按 §7-3 决策执行,写入 release notes | + +### P3-E:最终字节与产品集成(合入资格的核心) + +1. 以 P3-C 定稿 series 生成**同源三平台引擎包**(linux-x64 Ubuntu20 下限、win32-x64、darwin-arm64),记录 source/series/binary/resource SHA。 +2. **产品 lock 切换到该引擎**(独立提交),产品 CI 首次在三平台跑 maintained 引擎;不再以 stock CI 代表最终结果。 +3. Linux 最终字节复跑:12 语境 3×30、选定 GCC 插入、stock/candidate 对照、资源审计(一次,不重复挑选)。 +4. Windows:module-faults 原生稳定性根因、UP12 crash corpus 重放、UP13 补齐真实输入;文件身份/共享模式/rename/lease/取消。 +5. ARM macOS:toolchain/SDK/VFS/生命周期、语义与延迟分布(同 Linux 语境集,可缩为 3×10,见 §7-4)。 +6. 产品闭环:VS Code 真实编辑(typing/import/autosave/保存新 export/导航)、inferred/C7、UP20,raw 与产品缓存分开报告;真实缓存命中时序。 + +### P3-F:发布长期验证(M2) + +1000 次真实保存(内存/生命周期/缓存物理增长)、全局物理缓存预算、完整 Ubuntu20 产品安装、7 次合格 nightly(日历上 ≥7 天,从 P3-E 字节冻结起算)、每平台 ≥2h RC soak。任何代码改动使已完成的 nightly 计数归零,因此 M2 期间只接受阻断级修复。 + +## 4. 门槛 + +| 检查点 | 必须证据 | 通过条件 | +|---|---|---| +| R5 本方案 review | 本文 | 用户批准范围、顺序与 §7 决策 | +| M1 合入资格 | P3-A~E 完成;两 PR 整理后 head 的三平台 CI(产品 CI 用 maintained 引擎)全绿;Linux 最终字节分布;Windows/ARM macOS 原生语义与延迟;台账与 PR 描述同步 | 普通/限定名 warm/edited p95 ≤200ms、模块成员 ≤300ms(三平台,各自本机对照);edited 对 stock 改善 ≥50%(Linux 必须,其他平台报告);CPU/RSS 无 ≥20% 稳定期退化;无已知正确性/crash 负例;仓库检查(路径/大小/二进制)通过 | +| M2 发布资格 | P3-F | 原联合方案发布要求;所有随发补丁 steady;release notes 含平台变化 | + +warm Modules 对头文件差距:**登记为非阻断跟踪项**,M1/M2 都只要求如实报告数值(若用户希望阻断,需在 R5 给出量化目标)。 + +## 5. 风险 + +- 补丁合并可能引入应用顺序/冲突错误:以"合并前后最终 tree 字节一致"为硬检查,tree 一致则语义不变,只需重做构建身份与 CI。 +- 历史整理会让 PR 讨论中的提交链接失效:原分支保留为档案并在新 PR 描述中链接。 +- Windows module-faults 与 crash corpus 是最可能拖长周期的项;如超出预算,按 §2-5 报告,不调大期限掩盖。 +- 7 nightly + soak 是日历约束,不能通过并行压缩。 + +## 6. 移交 0.0.13 的输入 + +warm 31.74ms 差距的已知方向(来自 Part 2 trace,未实施):推导指引 GetDecl 线程 CPU 约 28–33ms、operator 名称加载、documentation lookup、构造函数多重性;manifest 622 路径重复 open(约 7.5ms);PCH 辅助 canonical 扫描为性能负例,保持不导出。 + +## 7. 需要用户决定 + +1. 是否批准"内容冻结、不再做性能优化",并把 warm 差距列为非阻断? +2. 合入方式:整理分支 + 主题提交(推荐)还是保留原历史?原始证据放 release 资产(推荐)还是独立 evidence 仓库? +3. linux-arm64:恢复(stock 引擎 + 现有 kit,不承诺 maintained 引擎)还是正式停止支持并在 release notes 声明? +4. ARM macOS/Windows 延迟分布规模:与 Linux 相同 12×3×30,还是 12×3×10 加关键语境 3×30? +5. 补丁合并目标数量(约 15–20)与 steady 定义是否认可;是否把"全部 steady"提前为 M1 条件? + +## 8. 实施(用户批准后) + +### 8.1 决策落地 + +| §7 | 决定 | 落地 | +|---|---|---| +| 1 | 内容冻结;warm 31.74ms 差距不阻断 | 不新增性能补丁;差距写入 CHANGELOG "open" 并移交 0.0.13(§6) | +| 2 | 整理分支 + 主题提交;原始证据放 release 资产 | 两个 PR 沿用原分支(保留 PR #2 的 ccache 作用域),原历史先归档到 `archive/0.0.12-joint`;证据打包为 `evidence-0.0.12` release 资产 | +| 3 | linux-arm64:分析原因并尽量支持 | 原因:`1011cbf` 按 Part 2 范围决定移除,无技术失败记录;引擎 v0.0.2 已发布过 arm64。恢复为 maintained 引擎,在 arm64 Ubuntu 20.04 rootfs(`fcd7f696…`)以同一 Clang 12 配方构建,glibc 下限从 0.0.11 的 2.34 降到 2.31 | +| 4 | Windows/ARM macOS 规模 | 沿用 CI 原生矩阵(build-test、payload、conformance、VS Code、stability、performance) | +| 5 | 全部补丁 steady 提前到合入 | 台账定义 steady,`verify-series` 运行 `check_ledger.py --release`,release 工作流同样要求 | + +### 8.2 多角度拆分 + +| 角度 | 任务 | +|---|---| +| 架构 | 74→25 主题补丁,tree 字节一致(`a2e92ba0…`,两条系列分别应用验证);`patches/HISTORY.md` 映射旧编号;产品 `pack.clangd` 原样接收 maintained 引擎 part(不 strip/不重签,保持 `engine.json` 身份) | +| 稳定性 | save-plan 根因:测试夹具手工 model 用未规范化临时路径,生产在 `project/model.cpp` 规范化;Linux 用符号链接 TMPDIR 精确复现 4 处失败,修复后通过 | +| 优雅简洁 | 删除 Intel 构建脚手架(`[target.x86_64-macos]`、`__bzero` stub、Intel neovim 脚本、x86_64 SIGPIPE 分支);payload v4 常量化;`ci/check_tree.py` 拒绝大文件/生成物/个人路径 | +| 用户体验 | `format.fallbackStyle` 大小写不敏感;后台索引优先级只在有证据的 macOS 生效 | +| 兼容性 | linux-x64 glibc 下限 2.18→2.31、macOS 11→12 写入 CHANGELOG 与安装文档;外部 clangd(`mcppls.clangd`)照旧 | +| 跨平台 | linux-arm64 回到产品与引擎全部矩阵;引擎 Linux e2e 在两种架构运行 | +| 一致性 | 四个平台同一引擎 `23.1.0-mcppls.0`、同一 series digest;lock、manifest、扩展平台列表、CI 矩阵一致 | +| 无感升级 | 设置无迁移;新增设置默认 `auto`;payload v4 与扩展同包发布;不满足 glibc 的系统退化为模块级功能并说明原因 | + +### 8.3 依赖 + +``` +引擎: 重组补丁 → 台账/检查 → arm64 CI → PR #2 CI 全绿 → squash 合入 → main build-test → tag v0.0.12 → 引擎 release + ↓ (URL/size/sha256) +产品: 夹具修复 / 代码收尾 / arm64 恢复 / part 接入 ──────────────────────────────→ lock 切换 → PR #46 CI 全绿 → 自审 → squash 合入 → Release(draft) → 本地验证 +``` + +版本后缀保持 `-mcppls.0`:`LLVM_VERSION_SUFFIX` 进入 `llvm-config.h`,修改会使四平台几乎全量冷编译;引擎身份由 fork commit、series digest 与二进制 SHA 决定。下一次随产品发布的引擎变更须递增后缀,避免不同引擎以同一版本串接受彼此的 BMI。 + +### 8.4 实施中发现与处理(2026-10-10) + +用户要求 0.0.12 必须随附 mcppls-clangd,且任何方面不弱于原版 clangd。对比测量(本地 4 核 ux-xlings、2 核 PRoot typing-import)找出的差距与处理: + +| 现象 | 根因 | 处理 | +|---|---|---| +| import 行补全每键重建 prerequisites(U5/U6 p95 1.0 s、PRoot T1/T2 超 5 s) | 预编译头不含 `import` 行,原来的 preamble 区判断漏掉;空行同理 | 引擎 0025:模块/import 声明区(含其间空行)内补全跳过模块校验 | +| 每键 1.1 s 都花在扫描 memo 命中(std.cppm 每次命中重读并哈希全部 libc++ 头) | memo 回放对每个 Read 观察重新读字节 | 引擎 0014:同一句柄回放一个文件的观察;磁盘上身份/大小/mtime 不变且 mtime 早于记录 30 s 的头不再读(与 clang 校验模块输入相同的信任) | +| 补全时 import 集合变化(正在输入的未知模块名)触发整套 prerequisites 重建 | 名字集合不等即重建 | 引擎 0025:新增的名字若项目内无法构建则沿用 preamble 的模块;新导入可构建模块仍同步构建 | +| 依赖编辑后补全等完整重建(U7a p95 1.01 s,原版 0.36 s) | 同步重建 | 引擎 0025:最多等 250 ms,超时用编辑前的模块作答,重建在后台继续(每文件一个,可取消,ClangdServer 析构前停止) | +| 输入/自动保存未解析 import 时写替身、改写数据库、clangd 重读(CI T2/T3 失败) | 产品为原版死锁保留的 WA-CLANGD-002 全量生效 | 引擎新增 `unresolved-import-recovery`(`ci/unresolved_import_canary.py`:原版 60 s 无应答,维护版 77 ms);产品拆出 WA-CLANGD-013(非提供者文件的替身、UP-02 磁盘搁置),按该能力退役;模块单元自身的替身保留(module-faults F5 证明其价值) | +| 拥有缓存的稳定 payload 被删后模块永久失败(U11) | 0019 视为失败 | 引擎 0019:跳过并重建(PR #4 早先修复) | +| 维护版被报 `engine-version-untested` | `.tested` 只认 23.1.0 | 产品:随附版本同样视为已测 | +| 配置切换后模块构建排队、U8-config 重建 21 个(ux-mcpp) | 拥有缓存的准入上限固定 1 GiB,两套配置的 BMI 与读副本装不下 | 产品:Linux 上把 `cache.maxBytes` 的 3/4(至少 1 GiB)传给引擎;引擎 0019:换了上限的账本被采用而不是让每次构建失败。非 Linux 引擎无隔离 worker,不传(传了每次构建都失败) | +| 一个 BMI 丢失后 42 个导入者全部重建(U11 恢复 25–36 s,0.0.11 为 7 s) | 0021 的消费者键含生产者的文件身份和发布路径,重建到同样字节也换键 | 引擎 0021:键只含生产者的名字、大小与字节摘要(每次发布读一次);U11 恢复 6.6 s | +| 自动保存后的补全 1–3 s(ux-xlings U6 引擎占比 0.63) | 每个前置模块的查找扫描全部 4096 个槽(每槽一次租约与账本读,约 12 ms/模块);读副本只被弱引用,集合一放手就逐模块重新复制(一次输入 291 次复制) | 引擎 0019:查找先试上次的槽、扫描只校验一次身份;0021:每个文件最近一套前置模块由构建器保留(≤32 个文件,准入遇压力时放手);U5/U6 p95 0.23/0.46 s | + +首次打开的等待(U1 documentSymbol 20 s vs 14 s,因维护版等待正确模块)经用户确认可接受,见 #50。 + +流程补充(用户要求):mcppls-clangd PR 的 CI 为四个平台打包 `clangd--portable`;mcppls PR 通过 `packaging/engine-candidate.json` 用该次运行的部件联调全部 CI,两边通过后引擎才合入发布,产品再切换锁文件并删除候选文件(`docs/92-release.md` "A new engine"、引擎 README "Integrating with mcppls")。 diff --git a/.agents/docs/2026-10-09-part2-filtered-visible-lookup-design.md b/.agents/docs/2026-10-09-part2-filtered-visible-lookup-design.md new file mode 100644 index 00000000..a79fa680 --- /dev/null +++ b/.agents/docs/2026-10-09-part2-filtered-visible-lookup-design.md @@ -0,0 +1,80 @@ +# Part 2:补全时按名称加载导入声明的设计边界 + +状态:Linux 选择性加载已实现并导出为本地 0068,stabilizing;干净构建与最终生产/原生发布资格未完成,PR 不合入。延续 Part 2 的真实语义、200ms、输入失效及资源验收。 + +原 URI、同一 CDB 的 Qt 配对实验中,全头文件稳定语义执行约 53–56ms,Modules 约 132–136ms。新增私有 `SemaLookup.cpp` 插桩显示:Modules 的 `std` lookup 每次收集 17,144 个声明,枚举约 91–111ms,consumer 阶段约 11–12ms;全头文件收集 5,823 个声明,枚举约 34–42ms,consumer 约 6–7ms。该窗口包含 `Ctx->lookups()`、查找表物化及向量收集,尚不能将全部窗口归为磁盘读取或 `GetDecl`。所有选定 completion 均为真实 typed Sema;这是定位样本,尚非正式性能验收。 + +`DeclContext::lookups()` 在 namespace 具有 external visible storage 时调用 `ASTReader::completeVisibleDeclsMap()`。后者通过三类序列化表的 `findAll()` 获取 ID,再对全部 ID 执行 `GetDecl`。clangd 的模糊筛选发生在这些工作之后。仅在已有 `lookups()` 迭代器上筛名称,无法消除前面的加载成本。 + +ASTReader 子阶段计量已完成:6 次 `std` namespace lookup 各读取 17,192 个 ID、生成 2,889 个名称映射;`GetDecl` 累计约 93–108ms,整个 `completeVisibleDeclsMap` 约 97–113ms,差额约 4–5ms。6 次包含 ASTWorker 和 completion,不能解释为 6 个 completion 请求。逐 ID chrono 会增加计量开销,仍只用于归因。原始报告、两阶段插桩 diff、编译/链接参数和日志已归档于引擎 `tests/evidence/part2-linux/visible-lookup-profile/`;三个短报告均通过 typed Sema 控制。 + +准备验证的最小路线是保留原 BMI 格式和普通 lookup,在补全专用路径枚举序列化名称,先按匹配规则排除必不匹配的 identifier,再加载剩余声明。它不是答案缓存,也不以 index 代替 Sema。需要同时满足: + +- 匹配规则与当前 clangd FuzzyMatcher 一致,或采用证明包含全部合法匹配的保守筛选;不能改成 starts-with 丢失模糊结果。空词、无法解释的名称和非 identifier 保留原路径。 +- 普通解析、诊断及非补全 lookup 完全沿用完整查找。补全选择性加载不得将整个外部查找表标成已完整加载,也不得污染后续普通名称查找。 +- 收集 local、external、module-local、TU-local 表;处理 pending override、merged table 和相同 name 的所有 ID。不能只读取第一张表或选择一个重载。 +- using directive、inline namespace 和影响查找遍历的声明始终保留;对相关名称执行原有 shadow、acceptable/visibility、模块可达性与 using-shadow 处理。 +- 请求级筛选的有效期覆盖同步 Sema completion,异常、取消和嵌套调用后恢复;不得跨 ASTContext 保存 Decl 指针或跨请求复用未验证状态。 +- 优先复用现有表迭代能力;新增存储统计真实内存,不建立隐含持久名称缓存。若更改公共布局或 virtual API,执行全部受影响消费者重建,不能只替换少量对象后运行。 + +下一步用私有原型验证按名称加载的收益。最小控制涵盖限定 namespace、模糊词、空词、using/inline namespace、重载/模板、导入可见性、普通 lookup 不受影响及取消。真实 Qt 语义和 GCC 插入通过后才做短 A/B;无新增插桩的最终构建再跑完整分布。该路线若不能保全查找语义,则撤回原型,而不是关闭 external loading。 + +这是已有 UP-25 性能路径的进一步定位,已核对单一登记 #24 的 UP-25;当前不声明新的上游缺陷。具体优化及正式上游补偿状态按 contributing 规则随最终实现补齐。 + +## 私有原型首轮结果 + +原型位于 `/tmp/mcppls-part2-filtered-lookup`,从最终 67 源提取 `SemaLookup.cpp`、`ASTReader.cpp` 和私有 `MultiOnDiskHashTable.h`,增加按名称选择的 table 读取;没有更改 BMI 格式、公共布局或 virtual API。仅在带非空、长度≤63补全词的 qualified namespace lookup 中启用。名称筛选使用大小写不敏感子序列,是当前 clangd fuzzy match 的保守超集;非 identifier、非 ASCII、空词及长词回到原路径。临时 thread-local target/pattern 只覆盖该次查找表枚举;递归普通查找与 consumer 回调前恢复原状态,部分加载后保留 external visible storage 标志。 + +它当前是可执行实验,不是正式接口方案:生产实现还须用显式补全上下文/接口替代私有跨库 thread-local 传递,验证 ordinary lookup、嵌套/取消恢复、表 override/merge、模块可见性与所有相关消费者。 + +- 实际 clangd FuzzyMatcher 的 124,656 组名称/词对照中,18,934 组匹配未被子序列筛选误删,包含大小写、下划线及长词边界;此有限控制不代替全量语义证明。 +- 原 Qt URI/CDB/编译参数,1 次启动、1 轮编辑、4 次 completion:全部 typed Sema 和实际 GCC 选定插入通过。warm 118.29/113.54ms、edited 187.96ms;历史同条件短基线约 175–179/248ms。尚非完整 A/B/A 或正式 p95。 +- 每次 `std::ve` 选择性加载 4,649 个 ID、346 个名称,原完整路径约 17,192 个 ID。Qt trace 的稳定语义执行约 73.86–77.46ms,edited 模块验证约 82.71ms。 +- 小模块 fixture 通过跨 namespace using、inline namespace、重载,以及 `v_t`→`vector_template` 的非前缀 fuzzy 控制;实际 GCC 插入通过。using 场景基线/候选四次返回的全部 label/kind/实际编辑元组一致。最初 `vr`→`vector` 的 fixture 预期不符合原 FuzzyMatcher 的强匹配规则,该负记录保留,不作为候选正确性或性能结论。 + +下一步完成正式接口与正确性控制,再在无额外插桩的候选上跑短匹配 A/B/A;确认收益后才扩大至 12 语境与 3×30 验收。当前不能称 PR 达标或 release 完成。 + +## 显式接口候选与短 A/B/A + +独立 worktree `/tmp/mcppls-filtered-lookup-formal` 已实现显式接口候选:consumer 的 `getExternalNameFilter` 默认返回空谓词,clangd recorder 以实际 FuzzyMatcher 提供匹配函数;Sema 只有补全专用 qualified lookup 传递谓词,普通 lookup 保持原接口。ExternalASTSource 的同步入口将谓词绑定到精确 source/context,仅允许一次消费;内部栈作用域在返回时恢复,嵌套普通加载及复合 source 不匹配时沿用完整路径。没有跨库私有 target/pattern 全局符号,也没有新增持久 AST 缓存。内部线程局部栈指针只承载这一同步入口的动态作用域。 + +consumer 增加 virtual 方法,因此先重建全部 141 个 clangd 消费者与 7 个相关 LLVM 对象,再执行。两套二进制均成功链接;140 项 CompletionTest 通过,包括新增选择性加载后普通名称仍可查找、完整加载仍可关闭 external storage、递归普通调用不接收谓词、取消触发返回后作用域清理,以及 PCH qualified fuzzy/using/inline namespace/重载/空词控制。取消测试证明作用域清理,不是 Sema 全路径即时取消延迟证明。CIndex、interpreter 不在该局部二进制中,后续干净 kit 构建仍需覆盖它们。 + +无新增诊断插桩的短 A/B/A 已完成,三组均使用原 URI/相同 CDB 字节/参数及独立新建 CDB/cache 目录,各 1 启动×5 轮。全部 36 个选定请求为真实 Sema,全部选定 GCC 插入通过: + +| 短样本 | 基线前 | 候选 | 基线后 | +|---|---:|---:|---:| +| warm p95,6 请求/组 | 168.44ms | 112.82ms | 179.36ms | +| edited p95,5 请求/组 | 247.26ms | 187.05ms | 252.40ms | +| edited p50 | 245.48ms | 183.09ms | 240.14ms | + +候选观察到的主进程 VmHWM 约 703,780KiB,基线约 732,484/736,628KiB;采样包含冷阶段,未计子进程,不能代替稳定期物理缓存/RSS 资格。证据、完整 diff 与构建配方归档在引擎 `tests/evidence/part2-linux/filtered-lookup-formal/`。候选 diff SHA `aef3a329d3d7628d9a13e6b2cb9c9bee6e37178b4dfbb766f6be05f8bb5fb405`,引擎 SHA `6de880807d5d81c7c98341570d123fb88847928c523fc06042c92a11dba6ddb7`。尚未导出,12 语境及最终 3×30、其他平台、产品与发布长期验证仍未完成。 + +## 0068 导出与完整匹配对照 + +引擎本地 `b053791` 已导出 `0068-UP-25-selective-external-namespace-completion.patch`,台账 68/68 检查通过。源码 `c3af7d151` 的生产部分仍对应已测 `7db2e70ab`,额外改动为测试;142 CompletionTest 与 5 NamespaceLookupTest 通过。实际多模块控制覆盖独立/已合并/后续更新的名称表及重载、普通 lookup;仍需补齐最终可见性、resolve 与消费者运行资格。 + +四格每臂 3×30 的 edited p95:全头文件 baseline/candidate 为 184.52/155.90ms,Modules 为 255.22/188.61ms。每种模式内所有 186 个回复的全部返回项关键编辑元组相同,81 次抽样实际 GCC 插入通过。Modules 改善 26.10%,与候选全头文件仍差 32.71ms。详情与构建进度见 [实施状态](2026-10-09-0.0.12-part2-implementation-status.md)。 + +## 私有后续:模板推导指引名称筛选 + +`5cd03e1fd` 在现有 ASTReader predicate helper 中将 CXXDeductionGuideName 的 template identifier 纳入同一谓词,保留匹配模板的全部 guide。无接口/布局/序列化格式变化,operator/literal/using 不变。两项新增控制与原控制合计 144 CompletionTest 通过;反向替换为 0068 的测试确实检测到未选模板被加载。普通 lookup 对隐式 FunctionTemplateDecl 包装与显式 guide 均保留,alias/snippet 与文本声明一致。 + +四次 std 计量的 guide ID 从 1,425 降至 48,线程 CPU 约 28–33ms 降至 2.4–2.8ms;无新增插桩短 A/B/A edited p95 192.56/183.83/185.03ms,净收益尚未完整资格验证。36 次真实 Sema/实际选定 GCC 插入及全部返回编辑字段通过;该第一轮时延因并行编译排除。已归档引擎 `tests/evidence/part2-linux/filtered-guides-candidate/`,尚未导出 0069。 + + +## 私有后续候选:实际补全名称契约 + +正式 0068 的 identifier 谓词保持历史记录;私有 `31c43d3a2` 将谓词签名改为 `function_ref`,按 clangd 实际 TypedText 匹配 identifier、推导指引所属模板名称和 operator。OperatorKinds.def 映射及 new/delete/new[]/delete[]/call/subscript 的显式拼写需与 Sema AddTypedNameChunk 保持一致,co_await 使用 `operatorco_await`,不能使用 DeclarationName 的诊断字符串。未知 operator、literal、using 及其他名称保守保留;不额外 intern IdentifierInfo。同步 source/context 精确绑定、一次消费、嵌套恢复和普通查找行为沿用 0068。 + +完整 Linux 四格对照 edited p95:Modules 250.61→144.09ms,全头文件 180.13→134.67ms;候选 edited 差约 9.43ms,warm 仍差约 38.26ms。146 CompletionTest、5 NamespaceLookupTest 和 83 选定实际 GCC 插入通过。无效并行负载记录独立保留;完整证据及限制见实施状态和引擎 `filtered-special-names-candidate/four-arm/`。尚未导出新 series,也没有完成所有受影响消费者的最终干净构建或发布验收。 + + +后续导出:本地 series 已新增 `0069-UP-25-selective-guide-operator-completion.patch`,69 补丁/69 台账检查通过,stabilizing;合成源提交 `499609a2a1503ea7fef404e5b72fbb2e9fa2a9f2`,series SHA `c70865e0d5ca7dd2b75a5442de45e030d4149a8c7709dd8f1f611173f76376de`。完整四格证据、两个无效计时和源身份已归档。独立干净目录 `/tmp/mcppls-part2-clean-special69/` 正从固定上游 tarball 应用完整 series 并重建全部消费者;当前仅构建启动,不作为通过证据。旧 0068 构建和基线保留,新候选尚未推送,PR 不合入。 + + +## 0070:普通名字/表达式的 Scope 与 TU 选择 + +最终0069首列/普通edited p95为201.22/210.72ms,未达200ms。原限定名分支之外,Scope路径每请求仍枚举10,488个TU声明;私有批量CPU约29ms枚举+6ms消费。新增非virtual `LookupVisibleDeclsForCompletion(Scope*, ...)`,由普通名字/表达式补全传入同一borrowed StringRef谓词;LookupVisibleHelper只为NamespaceDecl或C++ TU选择外部名称。C的identifier查找路径、空谓词、普通LookupVisibleDecls、class/member遍历、本地声明/using/shadow/visibility、external-storage标记和同步RAII契约保持。类布局/已有virtual ABI与BMI格式不变,不新增答案缓存。 + +两项新控制验证PCH/文本 unqualified/global 的局部遮蔽、using/inline namespace、重载和编辑字段,以及TU部分加载后普通查找与完整加载。2项新控制+146项既有CompletionTest通过;开发构建只重建两Sema对象和测试,复用未变69消费者,不声称70全量消费者通过。默认top100跨同基线实例的index边界候选会交换;保留原负例,另用不限engine数量的实际返回字段一致性/插入控制,再验证默认返回项属于参考合法集合,计时采用默认limit及明确索引发布/正匹配。不限数量仍可能有legacy `isIncomplete=true`,不声称全索引完备。独立完整70源码已应用并核对,Ubuntu20全量构建仍在运行;正式series70/stabilizing,最终分布/产品/平台资格待证明。 diff --git a/.agents/docs/2026-10-11-build-programs-design.md b/.agents/docs/2026-10-11-build-programs-design.md new file mode 100644 index 00000000..6e87dc39 --- /dev/null +++ b/.agents/docs/2026-10-11-build-programs-design.md @@ -0,0 +1,48 @@ +# 0.0.12:mcpp 构建程序(build.mcpp)的语义支持(#51) + +日期:2026-10-11。状态:**已实现**,随 0.0.12(PR #46)发布。 + +上游:mcpp 2026.10.11.1(mcpp-community/mcpp#797,PR #798、#800)。mcpp 把 `build.mcpp`、`[build-dependencies]` 的库和引擎接口编进同一条计划,即构建程序图,并在 S1 文档中以 `build-program` 配置的集合描述它(mcpp SPEC-005 R3.13)。 + +## 1. 问题 + +用 mcppls 0.0.12 打开 mcpp 2026.10.11.1 的工程时,`build.mcpp` 没有任何语义,定义、悬停、补全全部超时。原因是 mcpp 的编译命令用 `-x c++` 声明 `.mcpp` 的语言,而 GNU/MSVC 参数翻译会删除构建自带的所有语言写法。clang 驱动无法从 `.mcpp` 推断语言,clangd 因此报 "expected exactly one compiler job"。 + +除此之外,issue #51 还列出了以下需求: + +- 按配置选择集合; +- 构建程序集合内的模块解析; +- 引擎接口只读; +- 跨配置导入的诊断(SPEC-007 P1); +- 编辑器语言关联; +- 旧版 mcpp 的版本门槛。 + +## 2. 决策 + +| # | 决策 | +|---|---| +| D1 | 计划在翻译后重新声明单元的语言。驱动可识别的扩展名维持原状;无法识别的(`.mcpp`)追加 `-x c++`;可导入单元追加 `-x c++-module`。判断依据为 `project::clang_names_language`,它对齐 clang `Types.cpp` 的扩展名表。 | +| D2 | 默认上下文先放目标集合、后放构建程序集合。两种配置都编译的源文件(同时出现在两张表中的包)按目标的参数读取。构建程序的工具链与目标不同时(交叉构建),默认上下文不读取它们,由各自的上下文读取。 | +| D3 | 默认上下文中,若目标与构建程序提供同名模块、源文件不同(例如同一个包的两个版本),保留目标的提供者。构建程序的那一份记入 `otherContextSources`,不报 `ambiguous-module`,因为两种配置互不可见,构建本身不存在歧义。 | +| D4 | 原生模块索引知道每个单元所属的配置。跨配置导入在 import 处报错:目标导入构建程序的模块报 `build-program-module`,引擎接口与 `[build-dependencies]` 的库各有一条消息;`build.mcpp` 导入目标的模块报 `target-module`。导入补全只给出本配置可见的模块;模块名跳转和悬停优先本配置的提供者。 | +| D5 | 引擎接口(集合 `mcpp:core`)只读,对它的格式化和 codeAction 返回 `[]`,prepareRename 返回 `null`,rename 返回 `RequestFailed`。从项目文件发起、但结果会改到引擎接口的 rename 被整体拒绝,不做部分修改。VS Code 通过 `configurationDefaults` 设置 `files.readonlyInclude: **/.mcpp/engine/*/modules/**`。 | +| D6 | 当前上下文不读取的构建程序,以及旧版 mcpp 未描述的 `.mcpp` 文件,都不交给 clangd:未进入计划的 `.mcpp` 文件先等待计划,再被排除。文件上给出一条 information 级诊断 `build-program-context`,说明由哪个上下文读取,或者从哪个 mcpp 版本起才有描述(`BUILD_PROGRAMS_MCPP_VERSION`)。未被读取的文件不做模块诊断。 | +| D7 | 各编辑器把 `.mcpp` 关联为 C++:VS Code、Neovim、CLion、Claude Code 和 Copilot CLI 由插件完成;Zed 的扩展无法给内置语言增加后缀,改为在 README 中给出 `file_types`。 | + +## 3. 规范 + +- S1 §7 增加一段说明性文字:构建自己运行的程序构成独立配置,`visible-sets` 只列出同一配置内的集合。§7.1 中 `configuration` 字段的说明提及 `build-program`。profile 版本不变。 +- `validate.py` 中的 mcpp 契约增加构建程序集合的检查:名称、配置内可见性、`mcpp:std:host`、`:build` 为 executable、`mcpp:core` 提供 `mcpp` 与 `mcpp.core`。 + +## 4. 测试 + +| 层 | 内容 | +|---|---| +| 单元 | `test_normalize`:`.mcpp` 单元的 `-x c++`;默认上下文的顺序;同一个包两个版本时的处理;交叉工具链下的默认上下文与 `app:build` 上下文。`test_server`:跨配置诊断、补全过滤、按配置跳转。 | +| 真实 mcpp | `mcpp-build-programs`:15 项检查,覆盖诊断、定义、悬停、补全、rename 拒绝、跨配置诊断和工作区不变,运行于 linux-x64、darwin-arm64 和 win32-x64。CI 在固定版本旁安装 `MCPP_BUILD_PROGRAMS_VERSION`(2026.10.11.1),默认版本保持不变;mcpp 输出的文档同时经过规范校验。 | +| 模拟 | `mcpp-build-programs-cross`:根据真实输出生成,并把构建程序改为第二个工具链。覆盖默认上下文的提示、`app:build` 上下文、引擎接口只读(格式化、codeAction、prepareRename、rename)。`mcpp-emit` 增加一个旧版 mcpp 未描述的 `build.mcpp`。 | +| VS Code | e2e 断言 `.mcpp` 已关联到 cpp,并断言 VS Code 实际采用了 `files.readonlyInclude` 的默认值。 | + +## 5. 兼容性 + +旧版 mcpp 和其他构建系统的文档中没有 `build-program` 集合,计划、诊断和补全的行为都不变。唯一可见的变化是:打开的 `.mcpp` 文件不再交给 clangd 猜测命令,文件上会出现一条说明。 diff --git a/.agents/docs/design.md b/.agents/docs/design.md index 248f17e5..8a758a13 100644 --- a/.agents/docs/design.md +++ b/.agents/docs/design.md @@ -269,6 +269,11 @@ before anything is published (`docs/92-release.md`). ## 7. Known limits +- [UP-O1](https://github.com/Sunrisepeak/mcpp-language-server/issues/24#issuecomment-6028338032): openkal-macos 0.12.0 leaves closed-pipe SIGPIPE unhandled. + WA-PLATFORM-001 protects owned child-input descriptors in platform/process.cpp; + retirement requires the closed-peer and blocked-writer canaries on both macOS + architectures with default signal handling. Native fix validation is pending. + - The CLion plugin builds and installs but has not been exercised in a running CLion. - linux-arm64 ships LLVM's own clangd build, which needs glibc 2.34 and a GCC 12 libstdc++ (Ubuntu 22.04+, Debian 12+, openEuler 24.03+); elsewhere the status says `engine-incompatible` and only diff --git a/.github/scripts/stability-evidence.md b/.github/scripts/stability-evidence.md new file mode 100644 index 00000000..24d7183e --- /dev/null +++ b/.github/scripts/stability-evidence.md @@ -0,0 +1,50 @@ +# Per-round stability evidence + +Stock-payload Windows run 37772700872, job 113308243293, failed round 1 +`module-faults` STRESS1 after 180.7s: maximum stall 59.0776s exceeded the +existing 45s budget; documentSymbol reached 60.009s and final state was +`preparing`. The job printed a server-log tail but deleted the scratch +workspace/cache. This evidence change does not attribute or repair that +runtime failure. + +The release stability job still runs the same fixtures, three rounds, polling +variant, assertions and 180s timeout. Each invocation gets distinct owned +workspace/cache paths, `--keep` and the existing `--measure` option. A wrapper +collects evidence after conformance returns, preserves its exit code and +removes only its newly created scratch in `finally`. No cache is shared across +rounds. Cleanup failure is diagnostic and cannot turn a runner failure into a +pass or change its verdict. Collection does not extend a conformance check's +deadline. The wallclock table explicitly includes runner **and diagnostics**; +actual check durations remain in the measurement. + +Always-upload artifacts contain only bounded text, never scratch directories, +BMI files or payload binaries: + +- At most eight direct regular cache logs, each with a 128KiB prefix/tail + allowance plus an omission marker (upper bound 128KiB + 32 bytes), using the + existing timing collector. No log-directory symlink is followed. +- At most eight `compile_commands.json` / `build_database.json` excerpts, + each at most 128KiB, from workspace/cache only. The breadth-first walk + examines at most 512 entries, 64 directories and six levels, with a five + second deadline checked between operations. Known binary/cache subtrees are + excluded; symlink/reparse components are rejected. This is an operation + time budget, not a hard bound on an individual OS filesystem call. +- Measurement and manifest are each at most 1MiB. CDB/measurement truncation is + explicitly recorded with original size, metadata, prefix/tail offsets and + retained hash; a truncated `.json` is not complete JSON. Walk stop reason, + limit reached and collection errors explicitly mark incomplete evidence. + +The maximum retained text per round is below 4MiB plus 256 bytes of log +markers. The manifest records the command, paths, runner exit and binary +identities; binary hashes are computed without copying binaries. Scratch is +not uploaded, including if a fixture creates BMI files or external links. +Missing measurements still leave a manifest and the original runner verdict. +A collector cannot survive a whole job/process termination; always-upload +preserves whatever evidence already exists without calling an interrupted +round a pass. + +Local controls exercised success, exit 7 failure, exit 9 missing measurement, +log-tail retention, oversized CDB truncation, external symlink/BMI exclusion, +owned scratch cleanup and the final-directory 512-entry exhaustion edge. +Python/YAML checks and the existing script inventory check pass. These are +collector controls, not native Windows runtime qualification. diff --git a/.github/scripts/stability_evidence.py b/.github/scripts/stability_evidence.py new file mode 100644 index 00000000..47c8e8a6 --- /dev/null +++ b/.github/scripts/stability_evidence.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +"""Retain bounded text after one stability round; preserve its runner verdict.""" +import argparse +from collections import deque +import hashlib +import json +import os +from pathlib import Path +import stat +import shutil +import subprocess +import time + +from timing_evidence import capture_logs, identity + +TEXT_BYTES = 128 * 1024 +MEASURE_BYTES = 1024 * 1024 +MAX_DATABASES = 8 +MAX_ENTRIES = 512 +MAX_DIRECTORIES = 64 +MAX_DEPTH = 6 +COLLECT_SECONDS = 5 + + +def link_or_reparse(path): + info = path.lstat() + return stat.S_ISLNK(info.st_mode) or bool(getattr(info, 'st_file_attributes', 0) & 0x400) + + +def checked_path(path): + """Reject symlink/junction components rather than resolving external inputs.""" + for component in reversed((path, *path.parents)): + if link_or_reparse(component): + raise OSError('symlink/reparse component rejected: ' + str(component)) + + +def capture_text(path, output, limit): + checked_path(path) + expected = path.stat(follow_symlinks=False) + fd = os.open(path, os.O_RDONLY | getattr(os, 'O_NOFOLLOW', 0)) + with os.fdopen(fd, 'rb') as stream: + info = os.fstat(stream.fileno()) + if not stat.S_ISREG(info.st_mode) or (info.st_dev, info.st_ino) != (expected.st_dev, expected.st_ino): + raise OSError('not the expected regular file: ' + str(path)) + half = (limit - 32) // 2 # Reserve space for the omission marker. + prefix = stream.read(half) + offset = max(len(prefix), info.st_size - half) + stream.seek(offset) + tail = stream.read(half) + checked_path(path) + marker = b'\n--- omitted middle ---\n' if offset > len(prefix) else b'' + output.write_bytes(prefix + marker + tail) + return {'source': str(path), 'artifact': output.name, 'size': info.st_size, + 'mtime_ns': info.st_mtime_ns, 'device': info.st_dev, 'inode': info.st_ino, + 'truncated': bool(marker), 'prefix_bytes': len(prefix), + 'tail_offset': offset, 'tail_bytes': len(tail), + 'retained_sha256': hashlib.sha256(output.read_bytes()).hexdigest()} + + +def capture_databases(roots, output): + queue = deque((root, 0) for root in roots) + captured, errors = [], [] + directories = entries = 0 + stop_reason = None + depth_limited = False + deadline = time.monotonic() + COLLECT_SECONDS + while queue and directories < MAX_DIRECTORIES and entries < MAX_ENTRIES and len(captured) < MAX_DATABASES: + if time.monotonic() >= deadline: + stop_reason = 'time' + break + directory, depth = queue.popleft() + try: + checked_path(directory) + directories += 1 + with os.scandir(directory) as children: + for child in children: + if entries >= MAX_ENTRIES or len(captured) >= MAX_DATABASES or time.monotonic() >= deadline: + stop_reason = ('entries' if entries >= MAX_ENTRIES else + 'databases' if len(captured) >= MAX_DATABASES else 'time') + break + entries += 1 + path = Path(child.path) + if link_or_reparse(path): + continue + if child.is_dir(follow_symlinks=False) and depth < MAX_DEPTH: + if child.name not in ('logs', '.git', 'node_modules', 'copies', 'instances', 'modules', 'bmi'): + queue.append((path, depth + 1)) + elif child.is_dir(follow_symlinks=False): + depth_limited = True + elif child.name in ('compile_commands.json', 'build_database.json') and child.is_file(follow_symlinks=False): + captured.append(capture_text(path, output / f'database-{len(captured)}.txt', TEXT_BYTES)) + except OSError as error: + if len(errors) < 8: + errors.append(str(error)) + if stop_reason is None: + stop_reason = ('entries' if entries >= MAX_ENTRIES else + 'databases' if len(captured) >= MAX_DATABASES else + 'directories' if queue and directories >= MAX_DIRECTORIES else + 'depth' if depth_limited else None) + return {'files': captured, 'errors': errors, 'directories_examined': directories, + 'entries_examined': entries, 'incomplete': bool(queue or stop_reason or errors), + 'stop_reason': stop_reason, 'limit_reached': stop_reason is not None, + 'depth_limited': depth_limited, + 'time_budget_reached': time.monotonic() >= deadline} + + +def collect(command, output): + def value(option): + return command[command.index(option) + 1] + manifest = {'command': command, 'cwd': os.getcwd(), + 'limits': {'logs': 8, 'log_bytes_each_with_marker': TEXT_BYTES + 32, + 'databases': MAX_DATABASES, 'database_bytes_each': TEXT_BYTES, + 'walk_entries': MAX_ENTRIES, 'walk_directories': MAX_DIRECTORIES, + 'walk_depth': MAX_DEPTH, 'walk_time_budget_seconds': COLLECT_SECONDS, + 'measurement_bytes': MEASURE_BYTES, 'manifest_bytes': MEASURE_BYTES}, + 'scope': 'Text-only collection after the runner; no BMI/payload upload. Truncated databases are not complete JSON.'} + try: + status = subprocess.call(command) + except OSError as error: + status = 127 + manifest['launch_error'] = str(error) + manifest['exit_code'] = status + try: + manifest['binaries'] = [identity(Path(command[0])), identity(Path(value('--server')))] + except OSError as error: + manifest['identity_error'] = str(error) + try: + cache = Path(value('--cache-dir')).absolute() + checked_path(cache / 'logs') + manifest['logs'] = capture_logs(cache, output) + except OSError as error: + manifest['log_error'] = str(error) + try: + manifest['databases'] = capture_databases( + [Path(value('--cache-dir')).absolute(), Path(value('--workspace-dir')).absolute()], output) + manifest['measurement'] = capture_text(Path(value('--measure')).absolute(), output / 'measure.json', MEASURE_BYTES) + except OSError as error: + manifest['capture_error'] = str(error) + data = (json.dumps(manifest, indent=2) + '\n').encode() + if len(data) > MEASURE_BYTES: + data = (json.dumps({'exit_code': status, 'capture_error': 'manifest exceeded byte limit'}) + '\n').encode() + (output / 'manifest.json').write_bytes(data) + return status + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('--scratch', type=Path, required=True) + parser.add_argument('command', nargs=argparse.REMAINDER) + args = parser.parse_args() + command = args.command[1:] if args.command[:1] == ['--'] else args.command + def value(option): + return command[command.index(option) + 1] + if not command or '--keep' not in command: + parser.error('a conformance command with --keep is required') + for option in ('--workspace-dir', '--cache-dir', '--measure', '--server', '--fixture', '--timeout'): + if option not in command or command.index(option) + 1 >= len(command): + parser.error('a value is required for ' + option) + scratch = args.scratch.absolute() + expected = {'--workspace-dir': scratch / 'workspace', '--cache-dir': scratch / 'cache', + '--measure': scratch / 'measure.json'} + if any(Path(value(option)).absolute() != path for option, path in expected.items()): + parser.error('workspace/cache/measure must use the owned scratch paths') + if args.output.absolute().is_relative_to(scratch): + parser.error('evidence output must be outside scratch') + args.output.mkdir(parents=True, exist_ok=False) + scratch.mkdir(parents=True, exist_ok=False) + try: + return collect(command, args.output) + finally: + try: + shutil.rmtree(scratch) + except OSError as error: + # Diagnostic cleanup cannot change the runner's verdict. + print('stability evidence scratch cleanup failed:', error) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/.github/scripts/timing_evidence.py b/.github/scripts/timing_evidence.py new file mode 100644 index 00000000..a9de36ca --- /dev/null +++ b/.github/scripts/timing_evidence.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +"""Run the tiny timing canary and retain bounded evidence outside its measured checks.""" +import argparse +import hashlib +import itertools +import json +import os +from pathlib import Path +import stat +import subprocess + +MAX_LOGS = 8 +LOG_BYTES = 128 * 1024 + + +def identity(path): + digest = hashlib.sha256() + with path.open('rb') as stream: + for block in iter(lambda: stream.read(1024 * 1024), b''): + digest.update(block) + return {'path': str(path.resolve()), 'sha256': digest.hexdigest()} + + +def capture_logs(cache, destination): + """Only direct regular log files; never traverse the cache or follow symlinks.""" + captured = [] + logs = cache / 'logs' + if not logs.is_dir() or logs.is_symlink(): + return captured + with os.scandir(logs) as entries: + for entry in itertools.islice(entries, 32): + if len(captured) == MAX_LOGS: + break + if not entry.is_file(follow_symlinks=False): + continue + expected = entry.stat(follow_symlinks=False) + fd = os.open(entry.path, os.O_RDONLY | getattr(os, 'O_NOFOLLOW', 0)) + with os.fdopen(fd, 'rb') as stream: + info = os.fstat(stream.fileno()) + if (not stat.S_ISREG(info.st_mode) or + (info.st_dev, info.st_ino) != (expected.st_dev, expected.st_ino)): + continue + prefix = stream.read(LOG_BYTES // 2) + offset = max(len(prefix), info.st_size - LOG_BYTES // 2) + stream.seek(offset) + tail = stream.read(LOG_BYTES // 2) + output = f'log-{len(captured)}.txt' + (destination / output).write_bytes(prefix + (b'\n--- omitted middle ---\n' if offset > len(prefix) else b'') + tail) + captured.append({'source': entry.path, 'device': info.st_dev, 'inode': info.st_ino, + 'size': info.st_size, 'mtime_ns': info.st_mtime_ns, 'artifact': output, + 'prefix_bytes': len(prefix), 'tail_offset': offset, 'tail_bytes': len(tail), + 'retained_sha256': hashlib.sha256((destination / output).read_bytes()).hexdigest()}) + return captured + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('command', nargs=argparse.REMAINDER) + args = parser.parse_args() + command = args.command[1:] if args.command[:1] == ['--'] else args.command + if not command: + parser.error('a conformance command is required') + def value(option): + return command[command.index(option) + 1] + fixture = Path(value('--fixture')) + if json.loads((fixture / 'scenario.json').read_text())['name'] != 'timing': + parser.error('only the generated tiny timing fixture is supported') + args.output.mkdir(parents=True, exist_ok=True) + command += ['--timing-evidence', str(args.output / 'report.json')] + manifest = {'command': command, 'cwd': os.getcwd(), 'logs': [], + 'limits': {'log_files': MAX_LOGS, 'log_bytes_each': LOG_BYTES, + 'directory_entries_examined': 32, 'report_bytes': 1024 * 1024}, + 'collection_excluded_from_navigation_budget': True} + status = subprocess.call(command) + manifest['exit_code'] = status + try: + manifest['binaries'] = [identity(Path(command[0])), identity(Path(value('--server')))] + except OSError as error: + manifest['identity_error'] = str(error) + try: + manifest['logs'] = capture_logs(Path(value('--cache-dir')), args.output) + except OSError as error: + manifest['capture_error'] = str(error) + manifest['report_present'] = (args.output / 'report.json').is_file() + (args.output / 'manifest.json').write_text(json.dumps(manifest, indent=2) + '\n') + return status + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/.github/versions.env b/.github/versions.env index 1dc073be..df90e888 100644 --- a/.github/versions.env +++ b/.github/versions.env @@ -7,6 +7,9 @@ # 2026.9.30.2: the first mcpp that reads an exact `=x.y.z` dependency pin, which the openkal set # needs (see the root mcpp.toml: 0.15.4/0.20.1 float past the vendored openkal-linux). MCPP_VERSION=2026.9.30.2 +# The mcpp the mcpp-build-programs fixture describes its project with, installed beside MCPP_VERSION, which stays the +# default: the first whose build database describes build programs (build.mcpp, mcpp-community/mcpp#797). +MCPP_BUILD_PROGRAMS_VERSION=2026.10.11.1 LLVM_VERSION=22.1.8 XLINGS_VERSION=v2026.8.17.2 # The xmake the xmake conformance fixtures run (installed from xlings; 0.0.8 part 2 X-7). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 795abcb8..4044e111 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -230,17 +230,48 @@ jobs: cp cross/mcppls-devtools host-devtools fi chmod +x host-devtools cross/* + # A candidate engine (docs/92-release.md, "A new engine"): packaging/engine-candidate.json names + # a mcppls-clangd PR's CI run, whose packaged part replaces the lock's clangd, so the two are + # tested together before the engine is released. Only a pull request (or a manual CI run) may. + - name: Candidate engine + id: candidate + run: | + set -euo pipefail + file=packaging/engine-candidate.json + [ -f "$file" ] || exit 0 + if [ '${{ github.event_name }}' != pull_request ] && { [ '${{ github.event_name }}' != workflow_dispatch ] || [ '${{ github.workflow }}' != CI ]; }; then + echo "::error::$file names an unreleased engine; it is for a pull request's CI, not ${{ github.workflow }} (${{ github.event_name }}). Release the engine, switch packaging/payload.lock.json to it and remove the file." + exit 1 + fi + echo "repository=$(jq -r .repository "$file")" >> "$GITHUB_OUTPUT" + echo "run-id=$(jq -r '.["run-id"]' "$file")" >> "$GITHUB_OUTPUT" + jq . "$file" + - uses: actions/download-artifact@v8 + if: steps.candidate.outputs.run-id != '' + with: + name: clangd-${{ matrix.platform }}-portable + repository: ${{ steps.candidate.outputs.repository }} + run-id: ${{ steps.candidate.outputs.run-id }} + github-token: ${{ github.token }} + path: candidate # Fetch, trim clangd, build the semantic kit, assemble and verify: one command, the one a # developer runs (docs/93-devtools.md), with the cross-built server named. - name: Assemble run: | set -euo pipefail + engine=() + if [ -d candidate ]; then + part=$(dirname "$(find candidate -path '*clangd/engine.json' | head -1)") + chmod +x "$part"/bin/* + jq '{version: .["engine-version"], fork: .["fork-commit"], sha256, features}' "$part/engine.json" + engine=(--clangd "$part") + fi server="cross/mcppls${{ matrix.exe }}" runner="cross/mcppls-conformance${{ matrix.exe }}" mock="cross/mcppls-mock-mcpp${{ matrix.exe }}" mockModel="cross/mcppls-mock-model${{ matrix.exe }}" packer="cross/mcppls-devtools${{ matrix.exe }}" - ./host-devtools payload --platform ${{ matrix.platform }} --server "$server" --out payload --cache "$PAYLOAD_CACHE" + ./host-devtools payload --platform ${{ matrix.platform }} --server "$server" ${engine[@]+"${engine[@]}"} --out payload --cache "$PAYLOAD_CACHE" ./host-devtools payload --verify payload --json > "$RUNNER_TEMP/verify.json" cat "$RUNNER_TEMP/verify.json" if [ -f cross/SHA256SUMS ]; then @@ -277,19 +308,19 @@ jobs: - platform: linux-x64 part: 1 of 2 os: ubuntu-24.04 - fixtures: mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mingw mcpp-split-gcc mcpp-watch multi-root mcpp-llvm mcpp-watch@polling mcpp-emit mcpp-rules-generated s1-two-sets compdb-lto-msvc failure-at-base@vscode generated-module-negotiated typing-import typing-import-spin workaround-canaries typing-autosave module-edit-autosave partial-scan-standins compdb-rejected-command compdb-mixed-standards mcpp-emit-partial mcpp-emit-partial-download compdb-midwrite xmake-basic xmake-late-config xmake-user-mode xmake-no-standard xmake-needs-download + fixtures: mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mingw mcpp-split-gcc mcpp-watch multi-root mcpp-llvm mcpp-build-programs mcpp-watch@polling mcpp-emit mcpp-rules-generated s1-two-sets compdb-lto-msvc failure-at-base@vscode generated-module-negotiated typing-import typing-import-spin workaround-canaries typing-autosave module-edit-autosave partial-scan-standins compdb-rejected-command compdb-mixed-standards mcpp-emit-partial mcpp-emit-partial-download compdb-midwrite xmake-basic xmake-late-config xmake-user-mode xmake-no-standard xmake-needs-download ux-modules-qt - platform: linux-x64 part: 2 of 2 os: ubuntu-24.04 extras: true - fixtures: inferred inferred-bom build-discovery-off engine-none module-faults untrusted mcpp-gcc mcpp-gcc@plain mcpp-emit-package-std mcpp-emit-broken mcpp-emit-unavailable mcpp-emit-hang mcpp-emit-needs-download mcpp-emit-provisioned mcpp-emit-watch mcpp-emit-watch@polling mcpp-emit-edits cmake-clang cmake-clang-bdb cmake-fetchcontent-offline watch-polling payload-corrupt clangd-cannot-load generated-module generated-module@vscode generated-module-old-mcpp generated-module-old-mcpp@neovim module-faults@zed failure-at-base failure-at-base@neovim completion-keywords diagnostic-bundle clangd-crash-context mcpp-emit-wait provisional-no-prime inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views + fixtures: inferred inferred-bom save-plan build-discovery-off engine-none module-faults untrusted mcpp-gcc mcpp-gcc@plain mcpp-emit-package-std mcpp-emit-broken mcpp-emit-unavailable mcpp-emit-hang mcpp-emit-needs-download mcpp-emit-provisioned mcpp-emit-watch mcpp-emit-watch@polling mcpp-emit-edits mcpp-build-programs-cross cmake-clang cmake-clang-bdb cmake-fetchcontent-offline watch-polling payload-corrupt clangd-cannot-load generated-module generated-module@vscode generated-module-old-mcpp generated-module-old-mcpp@neovim module-faults@zed failure-at-base failure-at-base@neovim completion-keywords diagnostic-bundle clangd-crash-context mcpp-emit-wait provisional-no-prime inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views format-explicit preparation-after-idle # generated-module{,-old-mcpp,-negotiated}'s mcpp-mock.json bakes in a POSIX driver path # (${env:HOME}/.mcpp/registry/..., no {exe}); it resolves the same way here as on Linux, so # these run on macOS but are left off win32-x64 below rather than fixed unverified. - platform: darwin-arm64 os: macos-14 extras: true - fixtures: inferred inferred-bom build-discovery-off engine-none module-faults untrusted mcpp-llvm mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mcpp-watch multi-root failure-at-base clangd-cannot-load failure-at-base@zed generated-module generated-module-old-mcpp generated-module-negotiated typing-import typing-import-spin workaround-canaries completion-keywords diagnostic-bundle typing-autosave module-edit-autosave partial-scan-standins clangd-crash-context mcpp-emit-wait provisional-no-prime inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views + fixtures: inferred inferred-bom save-plan build-discovery-off engine-none module-faults untrusted mcpp-llvm mcpp-build-programs mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mcpp-watch multi-root failure-at-base clangd-cannot-load failure-at-base@zed generated-module generated-module-old-mcpp generated-module-negotiated typing-import typing-import-spin workaround-canaries completion-keywords diagnostic-bundle typing-autosave module-edit-autosave partial-scan-standins clangd-crash-context mcpp-emit-wait provisional-no-prime inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views format-explicit # No mcpp on the arm64 runner (its tools are the cross-built ones), so the fixtures that # need no build tool and no compiler of their own: the semantic kit, clangd and the server # on aarch64, with module faults, a corrupt payload and polling included. @@ -300,12 +331,12 @@ jobs: - platform: win32-x64 part: 1 of 2 os: windows-2022 - fixtures: mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mcpp-split-msvc cmake-msvc-std compdb-clangxx-msvc-std multi-root compdb-clang-cl-std mcpp-llvm-msvc failure-at-base@vscode typing-import typing-import-spin workaround-canaries typing-autosave module-edit-autosave partial-scan-standins + fixtures: mcpp-split mcpp-partition-definition mcpp-all-cppm verify-changes mcpp-split-msvc cmake-msvc-std compdb-clangxx-msvc-std multi-root compdb-clang-cl-std mcpp-llvm-msvc mcpp-build-programs failure-at-base@vscode typing-import typing-import-spin workaround-canaries typing-autosave module-edit-autosave partial-scan-standins ux-modules-windows - platform: win32-x64 part: 2 of 2 os: windows-2022 extras: true - fixtures: inferred inferred-bom build-discovery-off engine-none module-faults mcpp-emit-hang inferred-msvc untrusted mingw cmake-msvc cmake-msvc-bdb cmake-clangxx-msvc cmake-clang-cl mcpp-msvc mcpp-watch failure-at-base clangd-cannot-load completion-keywords diagnostic-bundle mcpp-emit-wait inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views + fixtures: inferred inferred-bom save-plan build-discovery-off engine-none module-faults mcpp-emit-hang inferred-msvc untrusted mingw cmake-msvc cmake-msvc-bdb cmake-clangxx-msvc cmake-clang-cl mcpp-msvc mcpp-watch failure-at-base clangd-cannot-load completion-keywords diagnostic-bundle mcpp-emit-wait inferred-cxx26 reset-cache cache-budget include-cleaner-modules no-modules tidy-const-views format-explicit preparation-after-idle defaults: run: shell: bash @@ -318,6 +349,8 @@ jobs: set -euo pipefail case " ${{ matrix.fixtures }} " in *" mcpp-gcc "*|*" mcpp-split-gcc "*|*" mingw "*) mcpp toolchain install gcc 16.1.0 ;; esac if [ "$RUNNER_OS" = Linux ]; then sudo apt-get update -q && sudo apt-get install -y -q ninja-build; fi + # ux-modules-qt: Qt 5's headers in module units' global module fragments, from the distribution. + case " ${{ matrix.fixtures }} " in *" ux-modules-qt "*) sudo apt-get install -y -q qtbase5-dev ;; esac # 0.0.8 part 2 X-7: the xmake fixtures run xmake itself (pinned in .github/versions.env, from xlings like every other # tool here) with GCC 16 first on PATH: xmake picks the compiler it finds, and only GCC 16 has libstdc++'s std module. - name: xmake and GCC 16 for the xmake fixtures @@ -333,6 +366,40 @@ jobs: done xmake --version | head -1 g++ --version | head -1 + # mcpp-community/mcpp#797: mcpp-build-programs needs an mcpp whose build database describes build programs. It is + # installed beside the pinned one, which stays the default, and named to the fixture by MCPPLS_BUILD_PROGRAMS_MCPP. + - name: The mcpp that describes build programs + if: '!matrix.cross-tools' + run: | + set -euo pipefail + case " ${{ matrix.fixtures }} " in *" mcpp-build-programs "*) ;; *) exit 0 ;; esac + # From mcpp's own release, its checksum checked: the index snapshot the pinned xlings syncs can lag a new mcpp + # by days (2026.10.11.1 was in xim-pkgindex, not yet in the snapshot), and the pinned mcpp stays the default. + case "$RUNNER_OS-$(uname -m)" in + Linux-x86_64) platform=linux-x86_64; ext=tar.gz ;; + Linux-aarch64) platform=linux-aarch64; ext=tar.gz ;; + macOS-arm64) platform=macosx-arm64; ext=tar.gz ;; + Windows-*) platform=windows-x86_64; ext=zip ;; + *) echo "::error::no mcpp release for $RUNNER_OS-$(uname -m)"; exit 1 ;; + esac + archive="mcpp-$MCPP_BUILD_PROGRAMS_VERSION-$platform.$ext" + base="https://github.com/mcpp-community/mcpp/releases/download/v$MCPP_BUILD_PROGRAMS_VERSION" + temp="$RUNNER_TEMP"; python=python3 + if [ "$RUNNER_OS" = Windows ]; then temp=$(cygpath -u "$RUNNER_TEMP"); python=python; fi + curl -fsSL --retry 5 --retry-all-errors --retry-delay 5 -o "$temp/$archive" "$base/$archive" + curl -fsSL --retry 5 --retry-all-errors --retry-delay 5 -o "$temp/$archive.sha256" "$base/$archive.sha256" + expected=$(cut -d' ' -f1 "$temp/$archive.sha256") + actual=$("$python" -c "import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],'rb').read()).hexdigest())" "$temp/$archive") + [ "$expected" = "$actual" ] || { echo "::error::$archive: sha256 $actual, the release says $expected"; exit 1; } + rm -rf "$temp/mcpp-build-programs" && mkdir -p "$temp/mcpp-build-programs" + "$python" -c "import shutil,sys; shutil.unpack_archive(sys.argv[1], sys.argv[2])" "$temp/$archive" "$temp/mcpp-build-programs" + exe=''; [ "$RUNNER_OS" = Windows ] && exe='.exe' + mcpp="$temp/mcpp-build-programs/mcpp-$MCPP_BUILD_PROGRAMS_VERSION-$platform/bin/mcpp$exe" + chmod +x "$mcpp" 2>/dev/null || true + "$mcpp" --version + mcpp --version + if [ "$RUNNER_OS" = Windows ]; then mcpp=$(cygpath -m "$mcpp"); fi + echo "MCPPLS_BUILD_PROGRAMS_MCPP=$mcpp" >> "$GITHUB_ENV" # usable plan W3, closing the loop with mcpp itself: what `mcpp emit build-database` prints for # each of this host's mcpp fixtures, against the S1 and S2 schemas, S1's semantic rules and the # contract of mcpp-community/mcpp#636 (docs/specs/tools/validate.py). The fixtures below then have the @@ -356,7 +423,8 @@ jobs: [ -f "$source/mcpp.toml" ] && [ ! -f "$source/mcpp-mock.json" ] || continue [ -e "$temp/mcpp-emit/$fixture.json" ] && continue mkdir -p "$temp/mcpp-emit" && cp -R "$source" "$temp/mcpp-emit/$fixture" - (cd "$temp/mcpp-emit/$fixture" && mcpp emit build-database --format json > "$temp/mcpp-emit/$fixture.json") + emit=mcpp; [ "$fixture" = mcpp-build-programs ] && emit="$MCPPLS_BUILD_PROGRAMS_MCPP" + (cd "$temp/mcpp-emit/$fixture" && "$emit" emit build-database --format json > "$temp/mcpp-emit/$fixture.json") envelopes+=("$temp/mcpp-emit/$fixture.json") done "$venv" docs/specs/tools/validate.py ${envelopes[@]+"${envelopes[@]}"} | grep -v '^PASS' @@ -959,10 +1027,14 @@ jobs: - { platform: linux-arm64, os: ubuntu-24.04-arm, exe: '' } - { platform: darwin-arm64, os: macos-14, exe: '' } - { platform: win32-x64, os: windows-2022, exe: '.exe' } + env: + MCPPLS_LOG_LEVEL: debug defaults: run: shell: bash steps: + - name: Set editor evidence directory on the allocated runner + run: echo "MCPPLS_E2E_EVIDENCE_DIR=$RUNNER_TEMP/editor-e2e-evidence" >> "$GITHUB_ENV" - uses: actions/checkout@v7 # The arm64 image is not the x64 one: the display server and the libraries VS Code's # Electron loads are installed rather than assumed. @@ -1019,6 +1091,18 @@ jobs: MCPPLS_E2E_SCENARIO: stress run: | if [ "$RUNNER_OS" = Linux ]; then xvfb-run -a npm test; else npm test; fi + - name: Preserve editor request and engine failure evidence + if: always() + uses: actions/upload-artifact@v7 + with: + name: vscode-e2e-evidence-${{ matrix.platform }} + path: | + ${{ runner.temp }}/editor-e2e-evidence/*.json + ${{ runner.temp }}/editor-e2e-evidence/**/logs/** + ${{ runner.temp }}/editor-e2e-evidence/**/incidents/** + ${{ runner.temp }}/editor-e2e-evidence/**/crash-reports/** + if-no-files-found: ignore + retention-days: 7 - uses: actions/upload-artifact@v7 with: name: vsix-${{ matrix.platform }} diff --git a/.github/workflows/release-checks.yml b/.github/workflows/release-checks.yml index f69c4eeb..71301dd9 100644 --- a/.github/workflows/release-checks.yml +++ b/.github/workflows/release-checks.yml @@ -155,6 +155,9 @@ jobs: shell: bash steps: - uses: actions/checkout@v7 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' - uses: actions/download-artifact@v8 with: name: payload-${{ matrix.platform }} @@ -172,7 +175,8 @@ jobs: for round in 1 2 3 4 5; do for start in cold warm; do warm=(); [ "$start" = warm ] && warm=(--expect-warm) - "stage/mcppls-conformance${{ matrix.exe }}" run --server "payload/bin/mcppls${{ matrix.exe }}" --payload payload \ + python3 .github/scripts/timing_evidence.py --output "$results/evidence/$start-$round" -- \ + "stage/mcppls-conformance${{ matrix.exe }}" run --server "payload/bin/mcppls${{ matrix.exe }}" --payload payload \ --fixture conformance/fixtures/timing \ --workspace-dir "$RUNNER_TEMP/timing-$round/workspace" --cache-dir "$RUNNER_TEMP/timing-$round/cache" \ --timeout 120 --measure "$results/$start-$round.json" ${warm[@]+"${warm[@]}"} @@ -297,6 +301,9 @@ jobs: shell: bash steps: - uses: actions/checkout@v7 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' - uses: ./.github/actions/setup-mcpp - uses: actions/download-artifact@v8 with: @@ -307,26 +314,41 @@ jobs: run: | set -euo pipefail failed='' + evidence="$RUNNER_TEMP/stability-evidence" + mkdir -p "$evidence" for round in 1 2 3; do for fixture in ${{ matrix.fixtures }}; do extra=() case "$fixture" in *@polling) extra=(--no-dynamic-watch) ;; esac echo "::group::round $round: $fixture" started=$(date +%s) - if ! "stage/mcppls-conformance${{ matrix.exe }}" run --server "payload/bin/mcppls${{ matrix.exe }}" --payload payload \ - ${extra[@]+"${extra[@]}"} --fixture "conformance/fixtures/${fixture%@*}" --timeout 180; then + key="$round-${fixture//@/-}" + scratch="$RUNNER_TEMP/stability-scratch/$key" + if ! python3 .github/scripts/stability_evidence.py --output "$evidence/$key" --scratch "$scratch" -- \ + "stage/mcppls-conformance${{ matrix.exe }}" run --server "payload/bin/mcppls${{ matrix.exe }}" --payload payload \ + ${extra[@]+"${extra[@]}"} --fixture "conformance/fixtures/${fixture%@*}" --timeout 180 \ + --workspace-dir "$scratch/workspace" --cache-dir "$scratch/cache" --keep --measure "$scratch/measure.json"; then failed="$failed $round:$fixture" fi echo "::endgroup::" echo "round $round $fixture $(( $(date +%s) - started )) s" | tee -a "$RUNNER_TEMP/stability.txt" done done - { echo '| round | fixture | seconds |'; echo '|---|---|---|' + { echo '| round | fixture | seconds (runner + diagnostics) |'; echo '|---|---|---|' awk '{ printf "| %s | %s | %s |\n", $2, $3, $4 }' "$RUNNER_TEMP/stability.txt"; } >> "$GITHUB_STEP_SUMMARY" if [ -n "$failed" ]; then echo "::error::failed (round:fixture):$failed" exit 1 fi + - uses: actions/upload-artifact@v7 + if: always() + with: + name: stability-evidence-${{ matrix.platform }}-${{ strategy.job-index }} + path: | + ${{ runner.temp }}/stability-evidence + ${{ runner.temp }}/stability.txt + if-no-files-found: warn + # Everything a release would publish, staged and checked. Release takes this artifact as it is. candidate: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48bc5eec..87d06772 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,6 +78,13 @@ jobs: echo "::error::Run: mcpp run -p devtools -- version --set ${{ steps.pick.outputs.version }}" exit 1 } + # A release ships the engine the lock names, released and pinned; a candidate never does. + - name: No candidate engine + run: | + [ ! -f packaging/engine-candidate.json ] || { + echo "::error::packaging/engine-candidate.json names an unreleased engine. Release the engine, switch packaging/payload.lock.json to it and remove the file." + exit 1 + } # CHANGELOG.md says a release's notes are its section, so the section has to exist before an # hour of pre-release testing, not be found missing after it. - name: CHANGELOG.md has this version's section diff --git a/CHANGELOG.md b/CHANGELOG.md index 614a44df..af6ca540 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,134 @@ release's notes are that section. Versions are three-part semantic versions, `MAJOR.MINOR.PATCH`, and every editor plugin carries the product version unchanged. +## [0.0.12] — 2026-10-09 + +The bundled clangd is now **mcppls-clangd**: LLVM 23.1.0 with 25 patches for C++ modules +([mcppls-clangd 0.0.12](https://github.com/Sunrisepeak/mcppls-clangd/releases/tag/v0.0.12), +reporting `23.1.0-mcppls.0`). Each patch maps to rows of the upstream-defects register (issue #24) +and carries a drop condition. The payload pins the engine by its binary SHA-256 and its source +identity, and the server checks both before it trusts what the engine declares. + +### Completion on files that import modules + +- **Completion answers from the semantic parser, quickly.** On the Qt project fixture (12 contexts, + 3 starts × 30 rounds each, Linux x64), warm completion has p95 53–91 ms and completion right after + an edit 133–168 ms. In the same measurement, completion after an edit is at least twice as fast + as with stock clangd 23.1. Completion loads from imported modules only the names that can match + what was typed, shares the draft's verified imports, and lists each constructor overload once. Module importers still answer about 30 ms slower than the same + project written with headers once warm; that gap is open. +- **Files that include heavy headers and import modules keep their preamble.** A file that + includes Qt or `` and imports modules (whose own global module fragments include them + too) used to be parsed in full, headers and all, for every request: about 0.6 s per completion + for a Qt importer with stock clangd and before this release, and seconds per update with + ``. Its headers are now kept in a preamble that is checked against every input it + read, on Linux, Windows and macOS: 0.05 s per completion on the same Qt file. New conformance + fixtures `ux-modules-qt` (Linux) and `ux-modules-windows` (Windows) hold answers, latency while + typing, crashes and stalls on such projects. +- **Typing an import, or editing a module the file imports, no longer waits on a rebuild.** + Completion on an import line, or on a blank line among the imports, uses the modules it has. An + import nothing in the project builds keeps them too. After a dependency is edited, completion + waits up to 250 ms for its rebuild and otherwise answers from the modules as they were, while + the rebuild goes on. A cached dependency scan no longer reads every header again. +- **Unsaved edits count.** Dependency scans read the request's own buffers. A cached scan or BMI + verdict is reused only after every input it observed replays unchanged, including `__DATE__`-like + builtins and files that did not exist. + +### Building modules + +- **Prerequisite modules build as one bounded, cancellable graph.** Independent modules compile in + parallel within a shared limit. A cycle fails before any BMI is built, and closing a document + cancels its waits. A module change rebuilds only the modules that depend on it. +- **On Linux, module compilers run in supervised worker processes.** They stop when clangd dies, + are admitted against a shared memory budget, and the files they leave are collected once nothing + holds them. +- **Malformed module directives recover in place.** A missing `;` is reported on the directive + that lacks it, and a directive after a missing BMI no longer derails the rest of the file. The + product's own relocation of that diagnostic (WA-CLANGD-006) retires for an engine that declares + the fix. +- **An import of a module nothing provides is reported, and the file keeps answering.** A module + unit whose import resolves to nothing no longer stalls clangd or the files that import it. For + an engine that declares this (`unresolved-import-recovery`), the product stops giving such an + import in a file that provides no module a stand-in, and stops setting a file aside while an + autosave has such an import on disk (WA-CLANGD-013). Typing an import with autosave on no longer + rewrites the engine database at each name it passes through. A module unit's own unresolved + import still gets a stand-in, once the unit has not been edited for a few seconds, so its + importers keep their features (WA-CLANGD-002). +- **A module built again to the same bytes keeps the modules that import it.** A BMI that was + lost, evicted or damaged is built again, and when its bytes are the same its importers are + reused instead of being rebuilt one by one (ux-mcpp: 42 importers after one lost module). + Reusing a cached module no longer looks at every slot of the cache, which made each of a + request's prerequisites cost about 12 ms, and a file's last prerequisites stay with the engine + between requests, so typing an import no longer copies every module it needs again (1-2 s for a + completion right after an autosave). +- **The module cache follows the workspace's cache budget.** On Linux, mcppls-clangd's own module + cache gets three quarters of `mcppls.cache.maxBytes` (at least 1 GiB; unbounded when the budget + is) instead of a fixed 1 GiB, past which module builds waited for room: a profile change with + its modules beside the first profile's stalled the files that needed them. +- **Reusing a dependency scan no longer reads every header again.** A header that is on disk with + the identity, size and modification time the scan saw, and was last modified well before it, is + taken as unchanged, as clang does for a module's inputs. A hit on the standard library module's + scan used to read and hash each libc++ header. + +### mcpp's build programs + +- **`build.mcpp` has the features of target code (#51).** From mcpp 2026.10.11.1 the build database + describes the build programs: `build.mcpp`, the libraries of `[build-dependencies]` and mcpp's + engine interface (`import mcpp;`), in sets of the `build-program` configuration. `build.mcpp` is + read as C++ with the arguments mcpp compiles it with, so navigation, hover, completion and + diagnostics reach its libraries and the engine interface. Every editor integration treats `.mcpp` + files as C++. +- **The targets and the build programs stay apart.** The default context reads a package in both + `[dependencies]` and `[build-dependencies]` as the targets build it, and the context + `:build` reads the build programs as mcpp compiles them; build programs with a toolchain + of their own, as in a cross build, are read there and say so. A target that imports `mcpp` or a + library of `[build-dependencies]`, and a `build.mcpp` that imports a module of the targets, get an + error at the import, as mcpp refuses them. +- **The engine interface is read-only.** Formatting, code actions and renames never edit + `/engine//modules`, and VS Code opens it read-only. +- With an mcpp older than 2026.10.11.1, `build.mcpp` is not read, and a note in it names the mcpp + that describes it. + +### Editing + +- **Formatting has an mcpp fallback.** `mcppls.format.fallbackStyle` (default `auto`): a project + without `.clang-format` that is an mcpp project formats in the pinned mcpp style. A named style + overrides it, and a project `.clang-format` always wins. Other projects keep clangd's default. +- **Compiler extensions complete.** Attribute syntax, cleanup functions and, on Windows targets, + SEH constructs are offered where they are valid. +- `textDocument/semanticTokens/range` is answered, and `misc-const-correctness` no longer suggests + `const` for a range a pipeline consumes. + +### Fixes + +- **"preparation-stalled" no longer fires the moment preparation starts again (#49).** Preparation + that had finished a while earlier and was given modules again — a model reloaded, a file opened + that imports a module nobody had prepared — measured its stall clock from the previous run's + last progress. It reported "made no progress for a minute (34/39 done)" seconds after starting, + and wrote a diagnostic bundle. +- A file mcppls's own engine answers for a while (its module does not compile) is no longer taken + for one clangd will not finish once it goes back, and a syntax error in a file the editor opened + outside the workspace is no longer reported as a project issue. + +### VS Code + +- **A server that crashes while starting recovers cleanly.** Recovery waits for the failed start + to settle, then starts a fresh client through the same queue as a manual restart, under the same + crash budget. A failed protocol write closes the connection instead of leaving an unhandled + rejection (WA-VSCODE-003, WA-VSCODE-004). A crash report keeps the log path the server announced. + +### Platforms and compatibility + +- **linux-arm64 runs on far more systems.** Its clangd is the maintained engine built on an + Ubuntu 20.04 floor, so it needs glibc 2.31 (Ubuntu 20.04, Debian 11, RHEL 9 and later) instead + of 2.34 and GCC 12's libstdc++. +- **linux-x64's bundled clangd now needs glibc 2.31.** Stock clangd needed 2.18. On an older system + (Ubuntu 18.04, Debian 10, RHEL 8) the bundled clangd cannot start. mcppls then keeps its own + module-level features and says why in its status, and `mcppls.clangd` can point at another + clangd. +- **macOS needs 12 or later** (was 11): the engine is built for macOS 12. +- An external server or clangd keeps working as before. Intel macOS still has no bundled build. + ## [0.0.11] — 2026-10-04 ### Completion diff --git a/conformance/README.md b/conformance/README.md index d4d67943..22cd9f6a 100644 --- a/conformance/README.md +++ b/conformance/README.md @@ -22,6 +22,7 @@ checks fail at once with that reason instead of each waiting out its timeout. | Fixture | What it covers | |---|---| +| `save-plan` | Actual autosave of a module's new export reaches an importer without changing module names or imports; autosave of a new exported import still updates the plan and makes its exports available. Uses the semantic kit and no build system | | `xmake-basic` | 0.0.8 part 2 X-1, X-6, X-7: an xmake project with GCC 16 and `import std`, described by xmake run privately (source xmake, L3, std prepared, navigation works); the provisional model never says `untrusted-workspace`; nothing is written into the project. Linux, needs `xmake` on PATH | | `xmake-late-config` | X-1, X-5 (E1): no `set_languages`, and a stale `compile_commands.json` in the root (`prepare xmake-stale-compdb`); the engine commands are xmake's, not the file's; adding `set_languages("c++23")` to xmake.lua reaches the engine within 15 s with no `compdb-invalid`, `model-stale` or `preparation-stalled`; the project directory is unchanged once the edit is put back | | `xmake-needs-download` | Plan 0.0.9 D-1, D-2, D-3, D-6, against a stand-in `xmake` script (`fake-bin/`, first on the server's PATH by the scenario's `server-path-prepend`; POSIX only, so in the Linux fixture lists). Offline, missing packages: `producer-needs-download` naming them, that build tools are included, that the run stayed offline and that the system package manager works too, `askOnline`, the project untouched. `mcppls.describeOnline` and the install fails: `producer-install-failed` with xmake's error lines and its install log, no ask. Missing at the `xmake project` stage: needs-download, not `xmake-configure-failed`. `.xmake/*/*/xmake.conf` holds `proxy`, `dotnet` and `dotnet_sdkver` (which `xmake f` refuses) and a project option: `xmake f` runs once per load, with no `xmake-options-left-out` | @@ -35,11 +36,13 @@ checks fail at once with that reason instead of each waiting out its timeout. | `untrusted` | An mcpp package in an untrusted workspace: nothing is executed, the kit answers, the status is `degraded` with the reason | | `mcpp-gcc` | mcpp with GCC 16, described by mcpp's own `emit build-database` (mcpp 2026.9.15.1): level 3 once the S1 library has structured mcpp's level 2 document, GCC arguments translated for clangd (P1), libstdc++'s `std` from its manifest, a test that imports the package's module across sets, and the workspace unchanged | | `mcpp-llvm` | The same with LLVM 22: libc++ selected through include paths, BMI arguments removed (P3) | +| `mcpp-build-programs` | A package whose `build.mcpp` imports mcpp's engine interface and a library of `[build-dependencies]`, and which has a package in both tables, described by mcpp 2026.10.11.1 (mcpp-community/mcpp#797; `MCPPLS_BUILD_PROGRAMS_MCPP`, which CI installs beside the pinned mcpp). `build.mcpp` is read as C++ with the arguments of its own set; navigation, hover and completion reach its libraries and the engine interface; the target reads the shared package as it builds it; an import across the two configurations is diagnosed; a rename that would edit the engine interface is refused | +| `mcpp-build-programs-cross` | The same project's build programs given a toolchain of their own, as in a cross build, simulated by `mcppls-mock-mcpp` from what mcpp 2026.10.11.1 printed, with stand-ins for the engine interface inside the fixture. The default context says where `build.mcpp` is read; the context `app:build` reads it; formatting, code actions and renames do not edit the engine interface | | `mcpp-split` | The shape of a project that separates interfaces from implementations: interface units and an interface partition in `.cppm`, two implementation units (`module hello.greet;`) in `.cpp`, and an implementation partition; from mcpp's own build database. Declarations and definitions are reached from importers, definitions in implementation units before any of them is open, implementation units navigate into partitions and complete module-internal names, edits reach importers, and a file outside the build (`apps/gui/main.cpp`, importing a module nothing provides) is answered by clangd. `mcpp-split-gcc` (Linux) and `mcpp-split-msvc` (Windows) are the same project with GCC 16 and with `msvc@system` | | `mcpp-partition-definition` | Plan 2026-09-27 N-7 (WA-CLANGD-008): a module split into partitions, functions and members declared in a partition with class-type parameters and defined in other units of the module. clangd's background index builds no module a unit imports, so these definitions stayed on their declarations (0.0.5 fails N1-N5); the server builds the module's implementation units through clangd's foreground, and go-to-definition reaches them with only the callers open | | `mcpp-all-cppm` | The shape of a project whose module units are all `.cppm`, implementations written inside the interfaces: a primary interface re-exporting two partitions and a second module; navigation into partitions and through the re-exports, completion through the re-exported module, edits propagated to importers | | `mcpp-watch` | S2 5 with mcpp itself: a new module interface, a broken `mcpp.toml` and its repair are inputs mcpp names in `watch`; the broken manifest keeps the last model, `degraded` with `model-stale` and mcpp's own `MCPP_BUILD_DATABASE_PLAN_FAILED` (S2-5-9). CI also runs it as `mcpp-watch@polling` on Linux | -| `mcpp-emit` | mcpp's `emit build-database --format json` (mcpp-community/mcpp#636), simulated by `mcppls-mock-mcpp` from `mcpp-mock.json`, which records what mcpp 2026.9.15.1 prints for the project (paths as `${root}` and `${env:HOME}`): a level 2 document without `ide.options`, one set per package plus `hello:test` and `mcpp:std`, each seeing every other set. The S1 library completes it to a level 3 model; a test imports the package's module across sets, and the workspace stays unchanged. The simulated fixtures cover what a real mcpp cannot be made to do on demand | +| `mcpp-emit` | mcpp's `emit build-database --format json` (mcpp-community/mcpp#636), simulated by `mcppls-mock-mcpp` from `mcpp-mock.json`, which records what mcpp 2026.9.15.1 prints for the project (paths as `${root}` and `${env:HOME}`): a level 2 document without `ide.options`, one set per package plus `hello:test` and `mcpp:std`, each seeing every other set. The S1 library completes it to a level 3 model; a test imports the package's module across sets, and the workspace stays unchanged. The package's `build.mcpp`, which an mcpp of that age does not describe, is not read, and its diagnostic names the mcpp that describes it. The simulated fixtures cover what a real mcpp cannot be made to do on demand | | `mcpp-emit-package-std` | The same with `std` and `std.compat` provided by translation units of `mcpp:std` from a dependency package instead of by the toolchain's manifest, built in an mcpp std cache directory that does not exist yet | | `mcpp-emit-broken` | The same mcpp answering with an error: the status carries mcpp's own diagnostic, sources are scanned meanwhile, and nothing is configured in its place (the mock's `build` would leave a `compile_commands.json` that `workspace-unchanged` sees) | | `mcpp-emit-partial` | S2 0.3.0 (S2-3.4-12, S2-3.4-13; mcpp-community/mcpp#699, fix plan 2026-09-26 F10): the producer answers with every member it could plan and an `error` diagnostic whose `path` names the one it could not, exiting 1. The rest is used (the model is mcpp's, not scanned sources) and the status names the missing part (`producer-partial`) | @@ -89,15 +92,18 @@ checks fail at once with that reason instead of each waiting out its timeout. | `typing-autosave` | Fix plan 2026-09-26 F16, F13, F11, F12 (the hello project with `files.autoSave`): a new import line typed below the others, every step saved to disk, staying on `import hello.` for twelve seconds and then on a module nothing provides. clangd reads a file's imports from disk (UP-14), so 0.0.4 left every request for the file unanswered; the file is now set aside before clangd builds it and handed back once its disk text, or the database clangd read, makes it safe, with an incident recording the broken premise and no restart but for a spin. A directive missing its `;` is reported on the directive (WA-CLANGD-006) and an import only in the unsaved buffer is information (WA-CLANGD-007) | | `module-edit-autosave` | 0.0.8 plan M-1 to M-4 (the hello project with `files.autoSave afterDelay`): a module interface is written function by function for 30 s while its importer is open with a probe line `int probe_value = 1; probe_v` in `main()`, and every pause with half a statement on the screen is saved to disk a second after the last key. 0.0.7 took the module's own file from clangd with its importer (RP1.1): one position-less `module-failed` diagnostic instead of its real errors, and completions from mcppls's own engine, empty, until the next save handed it back. The unit whose compile failed keeps clangd (no `module-failed` diagnostic for the typed file); the importer is still contained while the module does not compile, and no completion in it may be empty (the file's words, M-2); no status sample may say `preparation-stalled`, and clangd may not be restarted nor a request time out. Runs the `typing` kind with `autosave-idle-ms` and `importer` | | `partial-scan-standins` | 0.0.8 plan P-1 (issue #34-2, GalTranslPP run 36676829043): three module interfaces include a header no command can reach after a generated chain of headers that takes clangd none, about two and about four seconds to preprocess, and `main.cpp` imports all three, so clangd names one more module it cannot find each time. 0.0.7 gave each its stand-in as it was named and restarted clangd for it; a restart ends the scans still running, so the next module was named by the next session (two restarts here, four rounds and 144 s on GalTranslPP). The reports are gathered and all the stand-ins enter the database once: at most one restart for a module's unit leaving the engine database (`restarts/*/reason`, `max-matches`) | +| `preparation-after-idle` | Issue #49: preparation that ended over a minute ago and is given modules again (a file opened that imports one) starts its stall clock afresh. 0.0.11 reported `preparation-stalled` at once, measured from the progress of the preparation before | | `provisional-no-prime` | 0.0.8 plan R-4 (issue #34-1), Linux and macOS: the producer (`prepare delayed-producer 8`: a shell script around `mcppls-mock-mcpp` that waits eight seconds before `emit build-database`) answers late and there is no cached model, so the scanned sources are the provisional model. Six seconds in (`not-before-since-start`), `cxxModules/report` must show at most two units wanted for preparation (std, std.compat), not the project's modules, which are prepared for commands the build tool's model will replace (0.0.7 wanted three); then the model comes (`source: mcpp`) and the importer's hover works | | `clangd-crash-context` | Fix plan 2026-09-26 F3 (issue #23), Linux and macOS: a stand-in clangd (`prepare clangd-crash-context`) prints a crash context naming a file nobody opened while `main.cpp` is typed in, then dies. Only the named file is set aside, the exit is reported with it and the status names it; 0.0.4 set aside `main.cpp` | | `compdb-rejected-command` | Fix plan 2026-09-26 F6: a `compile_commands.json` whose commands carry a value the compiler rejects (`-std=c++99999`, `prepare compdb-rejected-command`), as issue #23's did: every module scan fails, and the status says the command was rejected, as an environment issue in the compiler's words | | `mcpp-emit-wait` | Fix plan 2026-09-26 F4 (D1): the producer hangs past the ten seconds after which scanned sources are planned, to its 20 s bound; mcppls's own engine answers meanwhile and clangd is given no plan until the producer answers or is given up | | `completion-keywords` | Fix plan 2026-09-26 F9 and F15, as VS Code (`client-info`): the space is a completion trigger character; a space after `import ` or `export import ` opens the module list from mcppls's own index, and one typed anywhere else, or after `import ` or `export module `, is answered at once with nothing. The module-syntax keywords are offered where each can begin a declaration and not inside a function body, merged with clangd's answer, and on their own within 1.5 s for a file clangd cannot answer for yet (a new file waiting for clangd to read a database that has it); the report counts what the space trigger cost (S3-6.2-1 to S3-6.2-5) | -| `workaround-canaries` | Import-hang plan §9, 0.0.9 plan M-3: one check per registered workaround with a canary, run against the payload's clangd. WA-CLANGD-001 is a `clangd-check`; WA-CLANGD-009 (completion with `--experimental-modules-support` takes over 1.8 times as long on a file including 120 generated headers, `prepare heavy-headers`) and WA-CLANGD-010 (misc-const-correctness on a filter view and a view over one) are `clangd-lsp` checks, on Linux only. A failure here means a clangd update fixed that defect and the workaround it names can be removed | +| `workaround-canaries` | Import-hang plan §9, 0.0.9 plan M-3: one check per registered workaround with a canary, run against the payload's clangd. WA-CLANGD-001 is a `clangd-check`; WA-CLANGD-009 (completion with `--experimental-modules-support` takes over 1.8 times as long on a file including 120 generated headers, `prepare heavy-headers`) and WA-CLANGD-010 (misc-const-correctness on a filter view and a view over one) are `clangd-lsp` checks, on Linux only. A failure here means a clangd update fixed that defect and the workaround it names can be removed. WA-CLANGD-001 and 010 are `retired-by` capabilities mcppls-clangd declares, so with the bundled engine they report themselves retired | | `no-modules` | 0.0.9 plan M-3, WA-CLANGD-009: sources and headers with no module in the plan: clangd runs without `--experimental-modules-support`, hover and definition work, and the report splits request time into clangd's and the server's (M-1); a module interface written into the workspace restarts clangd with the flag, the event's reason naming WA-CLANGD-009 | | `tidy-const-views` | 0.0.9 plan M-3, WA-CLANGD-010: a project `.clangd` with `FastCheckFilter: None` and a `.clang-tidy` for misc-const-correctness; of a filter view, a transform view over it and an int never changed, the server shows only the int (`diagnostic-code-lines`) | | `ux-heavy-headers` | 0.0.9 plan M-2 (issue #37): ten sources including 400 generated headers (`prepare heavy-headers 400`), no modules, no checkout. `completion-baseline` holds completion through the server, each after an edit, to 1.3 times clangd alone's p95 plus 30 ms on the very compile_commands.json the server wrote, and to a share of answers by clangd. CI's `ux` job runs its one stage (`edits`); with `--disable-workaround WA-CLANGD-009` it fails (405 ms against 14 ms locally) | +| `ux-modules-qt` | 0.0.12: modules mixed with Qt headers. Two module units include Qt 5 headers in their global module fragments (`` among them), and a file includes Qt headers and imports both. CMake builds it with clang++ against the distribution's Qt 5 (`qtbase5-dev`). It checks answers (diagnostics, hover, definition), idle latency, typing in the importer, and typing with autosave in a module unit while an importer completes on it. Budgets cover every completion answered, no restart or crash, nothing set aside and diagnostics back within 6 s. Runs on Linux x64 | +| `ux-modules-windows` | 0.0.12: the same with ``. Two module units include it in their global module fragments, and a file includes it and imports both. CMake builds it with MSVC and Ninja. Diagnostics must be back within 4 s of typing (a report had them five or six seconds behind). Completion while typing has a p95 budget of 1.1 s, not 1.0 s: a completion there costs about 0.5 s even idle, and one clangd misses its 1 s budget for is answered by mcppls, a fifth of them on that runner, so its engine share budget is 0.65. Runs on Windows | | `mcpp-emit-edits` | Plan 2026-09-30 G-5, a project being written: edits inside functions, saved, never run the producer again although it names every source as an input; an edit that changes a file's imports, and a new source, do. `write-file` with `"expect-reload": false` watches for `settle` seconds that the model is not loaded again | | `reset-cache` | Plan 2026-09-30 C-1: `mcppls.resetCache` removes the workspace's cache (models, engine database, clangd's module cache and locks) and plans and starts again; navigation, hover and completion answer as before | | `diagnostic-bundle` | Issue #23 fix plan F18: the diagnostic bundle an editor exports (`mcppls.exportBundle`) holds what its manifest says, digest for digest, within its 25 MB cap, and no file of it, nor `cxxModules/report`, names the user or the home directory the server runs with, the home written into the client's log it is sent included (S3-5.5-3); asked to hide project paths, not the workspace either. On a CI runner that is `runneradmin`, its `RUNNER~1` and `C:\Users\runneradmin` on Windows, `/home/runner` and `/Users/runner` elsewhere | @@ -208,6 +214,7 @@ always has been. | `document-symbol-contains` | the outline has a top-level symbol named `expect` | | `semantic-tokens` | `textDocument/semanticTokens/full` (or `/range`, with `"range"`) for `"file"` (optionally with an unsaved `"text"`), decoded with the legend `initialize` gave, has every entry of `"expect"` (`{"line", "text", "type", "modifiers"?}`; `"modifiers"` is a list, and optional) among its tokens (design doc 2026-09-25 K/§7) | | `module-graph-contains` | `cxxModules/graph` lists module `expect`; retries within the check's own timeout, so it doubles as "a change reaches the graph within N seconds" (usable plan W9.3's `watch-polling`) | +| `request` | one request about the file: `"method"`, at `"at"` when given, with the fields of `"params"` added to the text document and position; the answer is `"expect"` exactly, or an error whose code is `"expect-error"` (mcpp-community/mcpp#797: no edit reaches mcpp's engine interface) | | `set-context` | sends `cxxModules/setContext` with `"context"` (usable plan W9.2), then a hover at `"at"` contains `expect`, retried the same way as `hover-contains` | | `write-file` | writes `"content"` (default: a fresh `export module ;`; `"content-from"` copies another workspace file) to `"file"` directly, the way a file system watcher — or, without one, the server's own polling fallback — would notice it, without the runner opening it as a document (usable plan W9.3); with `"expect-reload": true`, also waits for the status to pass through `loading` again (S2-5-1); `"replace": {"from", "with"}` rewrites part of the file as it is, and a later `"restore": true` writes back what it was (a run puts back every file it changed when it ends); `"notify": true` reports the write to the server even when it registered no watcher for it, as an editor's own watcher of build files does (an inferred model, kept while a build tool cannot answer, registers none) | | `second-instance` | a second server on the same workspace and cache reports the notice `notice-code` (default `shared-workspace`) in its status (overall design 6.3) | @@ -216,8 +223,10 @@ always has been. | `cli` | S5 section 7: `mcppls ` with the runner's payload and the fixture's server arguments, run to completion in the workspace, exits with `"exit"` (default 0) and prints one JSON document meeting `"expect"` | | `stress` | real-project stress testing (real-project plan RP0): seeded random use — see below — meets every key present in `"budget"` | | `type-text` | line `line` of `file` takes each of `steps` in turn, `interval-ms` apart (default 120), the whole buffer sent each time; after each, `request` (default `textDocument/documentSymbol`) is answered within `answer-within` seconds (default 5); with `save`, each step is also written to disk and reported as saved and changed, as autosave does; fails when the status turned to a state listed in `states-never` meanwhile (import-hang plan §8) | +| `retired-by` (any check) | the capability that retires the workaround whose defect the check watches: the check holds, saying why, when the runner uses the payload's clangd and its verified identity declares that capability (as the server retires the workaround there); against any other clangd it runs | +| `failure-log-lines` (fixture) | a regular expression: when the fixture fails, every line of the server's logs it matches is printed, however long before the end (at most 120), besides the last 200 lines | | `clangd-check` | the runner's own clangd (`--clangd`, else the payload's) run with `--check` on `file` does not finish (`expect: "hangs"`: not finished after `seconds`, default 10, or crashed) or finishes normally (`"finishes"`); a workaround's canary expects its defect, and fails with `says` once a clangd update fixed it (import-hang plan §9) | -| `clangd-lsp` | 0.0.9 plan M-3: the runner's clangd driven over LSP, the server not involved, started with `arguments` (`{workspace}` stands for the workspace; the isolated HOME applies). `"action": "diagnostics"`: `file` is opened and, once clangd's diagnostics settle (`quiet-ms`, 3000, after the first), `code` is on exactly the 0-based `lines`, or with `"includes": true` on at least those; `"completion-ratio"`: the median of `rounds` (10) completions at `at`, with `arguments`, over the same without them (`baseline-arguments`), `passes` (2) alternating sessions each, over `min-ratio`. A canary holds while the defect is there and fails with `says`, as `clangd-check` does; `only-on` keeps one off a platform it was not verified on | +| `clangd-lsp` | 0.0.9 plan M-3: the runner's clangd driven over LSP, the server not involved, started with `arguments` (`{workspace}` stands for the workspace; the isolated HOME applies). `"action": "diagnostics"`: `file` is opened and, once clangd's diagnostics settle (`quiet-ms`, 3000, after the first), `code` is on exactly the 0-based `lines`, or with `"includes": true` on at least those; `"completion-ratio"`: the median of `rounds` (10) completions at `at`, with `arguments`, over the same without them (`baseline-arguments`), `passes` (2) alternating sessions each, over `min-ratio`. A canary holds while the defect is there and fails with `says`, as `clangd-check` does; `only-on` keeps one off a platform it was not verified on. | | `completion-baseline` | 0.0.9 plan M-2: after the server settles, clangd alone (`baseline-arguments`; `{engine-database}` is the directory of the compile_commands.json the server wrote for its own clangd) is timed over `rounds` (40) completions at `at`, each right after the buffer was edited (`interval-ms` apart), then the server over the same. Budget: `ratio` (1.3) and `slackMs` (30) of clangd's p95, `engineShare` (a minimum), `maxEmpty`; the measure carries both p50 and p95 and the report's own `engineP95Ms` and `overheadP95Ms` for completion | | `report` | robustness design O3: `cxxModules/report` meets `"expect"`, retried within the check's time like an `mcp`/`cli` result (a plan or an engine may still be on its way) | | `bundle` | issue #23 fix plan F18: `workspace/executeCommand` `mcppls.exportBundle` with `"arguments"` (and a client log naming the home directory) answers with the path of a zip under 25 MB whose `manifest.json` lists every other file with its SHA-256, which has every file of `"expect-files"`, and in which no file names the server's home directory (either separator), a distinctive user name (`USER`, `USERNAME`, `LOGNAME`) or its 8.3 form, or, with `"forbid-workspace": true`, the workspace; neither may `cxxModules/report` (the workspace aside) | @@ -282,7 +291,7 @@ platform that cannot cause a fault reports it as skipped in the check's detail. | Kind | What it does and what it measures | |---|---| | `latency` | Repeats `requests` (`{"kind": "completion" \| "hover" \| "definition" \| "semanticTokens" \| "documentSymbol", "file", "at", "name"?, "expect"?, "trigger"?}`; `expect` is a path suffix for a definition, a label prefix for a completion, a text for a hover) one after another, `interval-ms` (700) apart, in a `phase`: `cold` (while the preparation runs: from the first `preparing` until it stops), `background` (from ready for `seconds`, 45: the implementation index is being built), `idle` (after the project settled: ready, and clangd under 0.3 of a core for eight seconds; `rounds`, 20) or `now` (at once, `rounds` times). Per request kind it reports p50, p95 and max seconds, timeouts, errors, empty answers and answers that missed `expect`, and, from `cxxModules/report`'s per-method `answeredBy`, the share of `completion` and `hover` answers (`engine-share-kinds`) that were not mcppls's own fallback. `first-answers` (`{"name", "kind", "file", "at", "expect", "within"}`) are asked in every round until each is answered as it should be, and the seconds since `initialize` of the first right answer are held to `within`. Budget: `p50`, `p95`, `max` (for every kind, or `.p95` for one), `timeouts`, `wrong`, `maxEmptyShare`, and `engineShare` (a minimum, 0 to 1) | -| `typing` | Types `scripts` (`{"line", "text"}`: a new line at `line` is typed one character at a time at `hz` (10), left with its broken text on screen for a moment, erased and removed; the whole buffer is sent after every key) for `seconds` (120), with a completion asked at the cursor every `completion-every-ms` (1000) without waiting for it; with `autosave-ms` the file is also written and saved that often, as autosave does, and put back when the check ends; with `autosave-idle-ms` it is written and saved once that long has passed since the last key and the buffer differs from what was last saved (`files.autoSave: afterDelay`, independent of `autosave-ms`); with `importer` (`{"file", "line", "text"}`) a second file that imports the typed one is opened with `text` inserted as a new line at `line` (0-based, in the editor's buffer only), a completion at the end of that line is asked alongside each of the typed file's, its latencies and results are kept apart, and its text is put back when the check ends. Then a real mistake (`diagnostic-probe`: `{"line", "text", "expect"}`) is typed and the time until its diagnostic arrives is measured. Reports completion p50, p95, max, the clangd restarts, files set aside and request timeouts (the report's counters, before and after), the engine share of the completions and the states the status went through. Also reports the files doomed (`file-doomed` events), the `module-failed` diagnostics published for the typed file and, apart, for the importer, the status samples naming `preparation-stalled`, and the importer's completion p95 and empty answers. Budget: `p95`, `max`, `restarts`, `filesSetAside`, `timeouts`, `engineShare` (a minimum), `diagnosticsRefresh`, `doomed` (the most `file-doomed` events), `moduleFailedDiagnostics` (the most publications for the typed file that carry a diagnostic with code `module-failed`: a file taken from clangd gets one), `stalled` (the most status samples with the issue `preparation-stalled`), `importerP95` (seconds) and `importerEmpty` (the most empty importer completions); `states-never` lists states the status must not reach | +| `typing` | Types `scripts` (`{"line", "text"}`: a new line at `line` is typed one character at a time at `hz` (10), left with its broken text on screen for a moment, erased and removed; the whole buffer is sent after every key) for `seconds` (120), with a completion asked at the cursor every `completion-every-ms` (1000) without waiting for it; with `autosave-ms` the file is also written and saved that often, as autosave does, and put back when the check ends; with `autosave-idle-ms` it is written and saved once that long has passed since the last key and the buffer differs from what was last saved (`files.autoSave: afterDelay`, independent of `autosave-ms`); with `importer` (`{"file", "line", "text"}`) a second file that imports the typed one is opened with `text` inserted as a new line at `line` (0-based, in the editor's buffer only), a completion at the end of that line is asked alongside each of the typed file's, its latencies and results are kept apart, and its text is put back when the check ends. Then a real mistake (`diagnostic-probe`: `{"line", "text", "expect"}`) is typed and the time until its diagnostic arrives is measured. Reports completion p50, p95, max, the clangd restarts, files set aside and request timeouts (the report's counters, before and after), the engine share of the completions and the states the status went through. Also reports the files doomed (`file-doomed` events), the `module-failed` diagnostics published for the typed file and, apart, for the importer, the status samples naming `preparation-stalled`, and the importer's completion p95 and empty answers. Budget: `p95`, `max`, `restarts`, `filesSetAside`, `timeouts`, `engineShare` (a minimum), `diagnosticsRefresh`, `doomed` (the most `file-doomed` events), `moduleFailedDiagnostics` (the most publications for the typed file that carry a diagnostic with code `module-failed`: a file taken from clangd gets one), `stalled` (the most status samples with the issue `preparation-stalled`), `importerP95` (seconds) and `importerEmpty` (the most empty importer completions); `states-never` lists states the status must not reach With `"firstOpenSeconds"` in the budget, the file is first asked for a completion once a second until clangd answers one (issue #50: mcppls-clangd waits for a module importer's first preamble), that wait is held to the budget and reported, and the typing and its other budgets start after it. | | `edit-save` | Opens `importers` (the first carrying `probe.append`, a use of what `insert` adds) and `file`, waits for the project to settle, inserts `insert` after `marker` in `file`, saves it (on disk, `didChange`, `didSave`, `didChangeWatchedFiles`) and times until the probe's diagnostic (`probe.expect`) clears and until every importer's diagnostics were published again, while a completion (`interactive`: `{"file", "at", "every-ms"}`) is asked every second. With `recover-probe` (a request as in `fault`) it also times until that request is answered as it should be. The interface is put back afterwards. Budget: `republishSeconds`, `probeSeconds`, `p95`, `max`, `recoverSeconds`, `errorStates`, `restarts`, `engineShare` | | `fault` | Causes a fault (`action`) and times the recovery to `recover-probe` (`{"kind": "completion" \| "definition" \| "hover", "file", "at", "expect"}`: a request whose right answer shows the project usable again; a completion of a std name only clangd can give is the honest one, a jump is often answered by mcppls's own engine before clangd is up) and to the status `ready` (a `ready` that lasts less than a second and a half does not count: 0.0.6 says `ready` for a moment before `preparing` when nothing is built). `open` lists the documents opened first, since the preparation is of what an editor has open. `kill-clangd` (`at-progress`: while the preparation is that far along, taking `progress-fallback-seconds` in `preparing` for it where the status reports no progress, or, without it, once the project settled; `count`, more than one at a further tenth each) reports how long the new clangd took (`newClangdSeconds`), how many clangds the server started for the kills (`clangdStarts`) and whether the preparation went on; `kill-server` kills the server (SIGKILL) and starts another at once (`gap-ms`) on the same workspace and cache, and reports whether it used the workspace's cache (`usesPrimaryCache`) and whether clangd was left running (`orphans`); `lock` stops the server, removes `module`'s published files and writes a stale lock for them (`variant`: `dead-pid`, `live-pid` or `foreign-host`), the shape clangd 23.1 leaves (`.locks/.lock`, a symlink to `.lock-` holding "hostname pid"), and starts another; `truncate-pcm` truncates `module`'s files to half instead; `git-checkout` checks out `rev` (`HEAD~20`) in the workspace, tells the server the files that changed and does the same back, reporting `replanSeconds` and clangd restarts of both legs and the probe's time after the second. A fault always reports whether the module files built again were more than the cache had (`newBmi`), and fails when the probe or the status is not back within `wait-seconds` (120). Budget: `answerSeconds` (the probe), `readySeconds`, `recoverSeconds` (the later of the two), `newClangdSeconds`, `clangdStarts`, `newBmi`, `orphans`, `lockWaitLines`, `usesPrimaryCache` (`true`), `replanSeconds`, `restarts` | | `graph-edit` | A build-graph change and how the server follows: `add` a module interface (`file`, `module`) or `remove` it (times until `cxxModules/graph` lists or drops `module`, and counts the clangd restarts within `quiet-seconds`, 10); `config` rewrites part of a build input (`replace`: `{"from", "with"}`) and, once settled, undoes it, timing how soon the project is described again each time and how many module files the undoing built (`revertNewBmi`). Budget: `graphSeconds`, `restarts`, `changeSeconds`, `revertSeconds`, `revertNewBmi` | @@ -343,3 +352,23 @@ of this runner's own long-standing default (the full `experimental.cxxModules` b `--client zed` and `--client plain` behave exactly as `--plain-client` always has (kept as its alias): no `cxxModules/status` arrives, so a `status` check is skipped rather than run, and the run checks that standard `$/progress` still arrived instead. + + +`format-mcpp` checks the pinned mcpp fallback and project configuration override +through actual LSP formatting edits. It requires a payload with verified +`format-style-mcpp` capability. `format-explicit` checks explicit user fallback +and project precedence and also runs with stock clangd. `format-external` is run +with `--clangd` pointing to stock clangd and checks that it receives no bundled +preset. These fixtures disable the build tool deliberately: the inferred model +is usable and reports the expected degraded state for that choice. + +`formatting-equals` applies returned TextEdits using UTF-16 positions, rejects +invalid/overlapping ranges, and compares the complete output against `expect` +or `expected-file`; an empty response cannot pass an unformatted golden. + +The focused installed-VSIX counterpart runs with +`MCPPLS_E2E_SCENARIO=formatting MCPPLS_E2E_VSIX= npm test` +in editors/vscode. It requires the maintained formatting capability and uses +three independent isolated workspaces for auto preset, explicit Google style +and project LLVM style. It compares the editor provider's full edits to the +same goldens and verifies that every workspace remains unchanged. diff --git a/conformance/fixtures/clangd-crash-context/scenario.json b/conformance/fixtures/clangd-crash-context/scenario.json index 8b48c10b..f82a0108 100644 --- a/conformance/fixtures/clangd-crash-context/scenario.json +++ b/conformance/fixtures/clangd-crash-context/scenario.json @@ -1,6 +1,6 @@ { "name": "clangd-crash-context", - "description": "Fix plan 2026-09-26 F3 (issue #23): clangd names the file it crashed on. Its `prepare` step puts a stand-in clangd in the workspace that runs the payload's clangd and, 25 seconds in, prints a crash context naming src/crasher.cpp -- a file nobody opened -- the way clangd 23.1 did on Windows, and kills it; later starts are the real clangd. Meanwhile the editor types in src/main.cpp. 0.0.4 set aside what it had been given or asked about in the last ten seconds, main.cpp, and not the file clangd named; now only src/crasher.cpp is set aside, the exit is reported with its crash context, and main.cpp keeps clangd once it is back.", + "description": "Fix plan 2026-09-26 F3 (issue #23): clangd names the file it crashed on. Its `prepare` step puts a stand-in clangd in the workspace that runs the payload's clangd and, 25 seconds in, prints a crash context naming src/crasher.cpp -- a file nobody opened -- the way clangd 23.1 did on Windows, and kills it; later starts are the real clangd. Meanwhile the editor types in src/main.cpp. 0.0.4 set aside what it had been given or asked about in the last ten seconds, main.cpp, and not the file clangd named; now only src/crasher.cpp is set aside, the exit is reported with its crash context, and main.cpp keeps clangd once it is back. A hover warms the engine first: module preparation of the first request exceeded the engine watchdog on the slowest Intel macOS runners, which had the watchdog kill the stand-in before its designed crash and turned the check into a restart-timeout race.", "prepare": [ [ "{conformance}", @@ -21,6 +21,17 @@ "state": "ready", "engine-name": "clangd" }, + { + "id": "W1-warmed-up", + "kind": "hover-contains", + "file": "src/main.cpp", + "at": [ + 4, + 31 + ], + "expect": "greet", + "timeout": 90 + }, { "id": "T1-editing-when-it-crashes", "kind": "type-text", diff --git a/conformance/fixtures/format-explicit/expected-google.txt b/conformance/fixtures/format-explicit/expected-google.txt new file mode 100644 index 00000000..f3395899 --- /dev/null +++ b/conformance/fixtures/format-explicit/expected-google.txt @@ -0,0 +1,24 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template + requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { + public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_ + capacity_ * limit_; + } + + private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/conformance/fixtures/format-explicit/expected-llvm.txt b/conformance/fixtures/format-explicit/expected-llvm.txt new file mode 100644 index 00000000..33d2fb25 --- /dev/null +++ b/conformance/fixtures/format-explicit/expected-llvm.txt @@ -0,0 +1,24 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template + requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { +public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_ + capacity_ * limit_; + } + +private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/conformance/fixtures/format-explicit/mcpp.toml b/conformance/fixtures/format-explicit/mcpp.toml new file mode 100644 index 00000000..0108775a --- /dev/null +++ b/conformance/fixtures/format-explicit/mcpp.toml @@ -0,0 +1,5 @@ +[package] +name = "format-mcpp-fixture" +version = "0.1.0" +[build] +sources = ["src/**/*.cppm"] diff --git a/conformance/fixtures/format-explicit/scenario.json b/conformance/fixtures/format-explicit/scenario.json new file mode 100644 index 00000000..fec3bf1d --- /dev/null +++ b/conformance/fixtures/format-explicit/scenario.json @@ -0,0 +1,54 @@ +{ + "name": "format-explicit", + "description": "An explicit user fallback overrides mcpp auto selection; a later project .clang-format overrides that fallback. Checks actual formatting edits against clang 23 goldens.", + "server-arguments": [ + "--no-discover", + "--build-tool", + "off", + "--format-fallback-style", + "Google" + ], + "checks": [ + { + "id": "U1", + "kind": "status", + "source": "inferred", + "state": "degraded", + "engine-name": "clangd" + }, + { + "id": "U2-user-selected", + "kind": "report", + "expect": [ + { + "path": "/roots/0/engines/*/details/arguments/*", + "equals": "--fallback-style=Google", + "min-matches": 1 + }, + { + "path": "/roots/0/engines/*/details/arguments/*", + "equals": "--fallback-style=mcpp", + "max-matches": 0 + } + ] + }, + { + "id": "U3-user-golden", + "kind": "formatting-equals", + "file": "src/format.cppm", + "expected-file": "expected-google.txt" + }, + { + "id": "U4-project-config", + "kind": "write-file", + "file": ".clang-format", + "content": "BasedOnStyle: LLVM\n" + }, + { + "id": "U5-project-wins", + "kind": "formatting-equals", + "file": "src/format.cppm", + "expected-file": "expected-llvm.txt" + } + ] +} diff --git a/conformance/fixtures/format-explicit/src/format.cppm b/conformance/fixtures/format-explicit/src/format.cppm new file mode 100644 index 00000000..45eb6e55 --- /dev/null +++ b/conformance/fixtures/format-explicit/src/format.cppm @@ -0,0 +1,6 @@ +module; +#include +export module format.demo; +import std; +export namespace demo {template requires requires(T x){x+x;} T sum(T first,T second){auto combine=[&](T left,T right){return left+right;};return combine(first,second);} +class Buffer {public:Buffer(int capacity,int limit):capacity_(capacity),limit_(limit){} int scaled() const{return capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_;}private:int capacity_;int limit_;};} diff --git a/conformance/fixtures/format-external/expected-llvm.txt b/conformance/fixtures/format-external/expected-llvm.txt new file mode 100644 index 00000000..33d2fb25 --- /dev/null +++ b/conformance/fixtures/format-external/expected-llvm.txt @@ -0,0 +1,24 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template + requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { +public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_ + capacity_ * limit_; + } + +private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/conformance/fixtures/format-external/mcpp.toml b/conformance/fixtures/format-external/mcpp.toml new file mode 100644 index 00000000..0108775a --- /dev/null +++ b/conformance/fixtures/format-external/mcpp.toml @@ -0,0 +1,5 @@ +[package] +name = "format-mcpp-fixture" +version = "0.1.0" +[build] +sources = ["src/**/*.cppm"] diff --git a/conformance/fixtures/format-external/scenario.json b/conformance/fixtures/format-external/scenario.json new file mode 100644 index 00000000..d6cc31ef --- /dev/null +++ b/conformance/fixtures/format-external/scenario.json @@ -0,0 +1,37 @@ +{ + "name": "format-external", + "description": "An explicit external clangd must not inherit the bundled mcpp formatting capability. The requested maintained style falls back to the external engine default and is visible as an issue. Run with --clangd set to vanilla clangd.", + "server-arguments": [ + "--no-discover", + "--format-fallback-style", + "mcpp", + "--build-tool", + "off" + ], + "checks": [ + { + "id": "E1", + "kind": "status", + "source": "inferred", + "state": "degraded", + "engine-name": "clangd" + }, + { + "id": "E2-no-inherited-preset", + "kind": "report", + "expect": [ + { + "path": "/roots/0/engines/*/details/arguments/*", + "equals": "--fallback-style=mcpp", + "max-matches": 0 + } + ] + }, + { + "id": "E3-native-default", + "kind": "formatting-equals", + "file": "src/format.cppm", + "expected-file": "expected-llvm.txt" + } + ] +} diff --git a/conformance/fixtures/format-external/src/format.cppm b/conformance/fixtures/format-external/src/format.cppm new file mode 100644 index 00000000..45eb6e55 --- /dev/null +++ b/conformance/fixtures/format-external/src/format.cppm @@ -0,0 +1,6 @@ +module; +#include +export module format.demo; +import std; +export namespace demo {template requires requires(T x){x+x;} T sum(T first,T second){auto combine=[&](T left,T right){return left+right;};return combine(first,second);} +class Buffer {public:Buffer(int capacity,int limit):capacity_(capacity),limit_(limit){} int scaled() const{return capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_;}private:int capacity_;int limit_;};} diff --git a/conformance/fixtures/format-mcpp/expected-google.txt b/conformance/fixtures/format-mcpp/expected-google.txt new file mode 100644 index 00000000..f3395899 --- /dev/null +++ b/conformance/fixtures/format-mcpp/expected-google.txt @@ -0,0 +1,24 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template + requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { + public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_ + capacity_ * limit_; + } + + private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/conformance/fixtures/format-mcpp/expected-mcpp.txt b/conformance/fixtures/format-mcpp/expected-mcpp.txt new file mode 100644 index 00000000..c10ac313 --- /dev/null +++ b/conformance/fixtures/format-mcpp/expected-mcpp.txt @@ -0,0 +1,23 @@ +module; +#include +export module format.demo; +import std; +export namespace demo { +template +requires requires(T x) { x + x; } +T sum(T first, T second) { + auto combine = [&](T left, T right) { return left + right; }; + return combine(first, second); +} +class Buffer { +public: + Buffer(int capacity, int limit) : capacity_(capacity), limit_(limit) {} + int scaled() const { + return capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + capacity_ * limit_ + + capacity_ * limit_; + } +private: + int capacity_; + int limit_; +}; +} // namespace demo diff --git a/conformance/fixtures/format-mcpp/mcpp.toml b/conformance/fixtures/format-mcpp/mcpp.toml new file mode 100644 index 00000000..0108775a --- /dev/null +++ b/conformance/fixtures/format-mcpp/mcpp.toml @@ -0,0 +1,5 @@ +[package] +name = "format-mcpp-fixture" +version = "0.1.0" +[build] +sources = ["src/**/*.cppm"] diff --git a/conformance/fixtures/format-mcpp/scenario.json b/conformance/fixtures/format-mcpp/scenario.json new file mode 100644 index 00000000..eeaaa0ff --- /dev/null +++ b/conformance/fixtures/format-mcpp/scenario.json @@ -0,0 +1,47 @@ +{ + "name": "format-mcpp", + "description": "Maintained engine capability selects pinned mcpp fallback; actual LSP edits reproduce the review golden and project override wins without product writes. Requires a candidate payload declaring format-style-mcpp.", + "server-arguments": [ + "--no-discover", + "--build-tool", + "off" + ], + "checks": [ + { + "id": "F1", + "kind": "status", + "source": "inferred", + "state": "degraded", + "engine-name": "clangd" + }, + { + "id": "F2-capability-selected", + "kind": "report", + "expect": [ + { + "path": "/roots/0/engines/*/details/arguments/*", + "equals": "--fallback-style=mcpp", + "min-matches": 1 + } + ] + }, + { + "id": "F3-golden", + "kind": "formatting-equals", + "file": "src/format.cppm", + "expected-file": "expected-mcpp.txt" + }, + { + "id": "F4-project-config", + "kind": "write-file", + "file": ".clang-format", + "content": "BasedOnStyle: Google\n" + }, + { + "id": "F5-project-wins", + "kind": "formatting-equals", + "file": "src/format.cppm", + "expected-file": "expected-google.txt" + } + ] +} diff --git a/conformance/fixtures/format-mcpp/src/format.cppm b/conformance/fixtures/format-mcpp/src/format.cppm new file mode 100644 index 00000000..45eb6e55 --- /dev/null +++ b/conformance/fixtures/format-mcpp/src/format.cppm @@ -0,0 +1,6 @@ +module; +#include +export module format.demo; +import std; +export namespace demo {template requires requires(T x){x+x;} T sum(T first,T second){auto combine=[&](T left,T right){return left+right;};return combine(first,second);} +class Buffer {public:Buffer(int capacity,int limit):capacity_(capacity),limit_(limit){} int scaled() const{return capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_+capacity_*limit_;}private:int capacity_;int limit_;};} diff --git a/conformance/fixtures/mcpp-build-programs-cross/build.mcpp b/conformance/fixtures/mcpp-build-programs-cross/build.mcpp new file mode 100644 index 00000000..3d8993e2 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/build.mcpp @@ -0,0 +1,9 @@ +import std; +import mcpp; +import gen; +import both; + +int main() { + mcpp::cxxflag(generated_flag().c_str()); + mcpp::cxxflag(std::format("-DBOTH={}", both_value()).c_str()); +} diff --git a/conformance/fixtures/mcpp-build-programs-cross/deps/both/mcpp.toml b/conformance/fixtures/mcpp-build-programs-cross/deps/both/mcpp.toml new file mode 100644 index 00000000..f0d858b2 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/deps/both/mcpp.toml @@ -0,0 +1,7 @@ +[package] +name = "both" +version = "0.1.0" +license = "Apache-2.0" + +[targets.both] +kind = "lib" diff --git a/conformance/fixtures/mcpp-build-programs-cross/deps/both/src/both.cppm b/conformance/fixtures/mcpp-build-programs-cross/deps/both/src/both.cppm new file mode 100644 index 00000000..f7272206 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/deps/both/src/both.cppm @@ -0,0 +1,3 @@ +export module both; + +export int both_value() { return 42; } diff --git a/conformance/fixtures/mcpp-build-programs-cross/deps/gen/mcpp.toml b/conformance/fixtures/mcpp-build-programs-cross/deps/gen/mcpp.toml new file mode 100644 index 00000000..0bf0ba7f --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/deps/gen/mcpp.toml @@ -0,0 +1,7 @@ +[package] +name = "gen" +version = "0.1.0" +license = "Apache-2.0" + +[targets.gen] +kind = "lib" diff --git a/conformance/fixtures/mcpp-build-programs-cross/deps/gen/src/gen.cppm b/conformance/fixtures/mcpp-build-programs-cross/deps/gen/src/gen.cppm new file mode 100644 index 00000000..b55c4070 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/deps/gen/src/gen.cppm @@ -0,0 +1,4 @@ +export module gen; +import std; + +export std::string generated_flag() { return "-DGEN=7"; } diff --git a/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp.cppm b/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp.cppm new file mode 100644 index 00000000..b381721a --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp.cppm @@ -0,0 +1,4 @@ +// Stands in for mcpp's engine interface, /engine//modules/mcpp.cppm, which mcpp +// writes once for each of its versions (mcpp-community/mcpp#797). +export module mcpp; +export import mcpp.core; diff --git a/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp_core.cppm b/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp_core.cppm new file mode 100644 index 00000000..49561100 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/engine/modules/mcpp_core.cppm @@ -0,0 +1,7 @@ +// Stands in for /engine//modules/mcpp_core.cppm. Written the way no formatter +// leaves it: a formatting request that edited it would show. +export module mcpp.core; + +export namespace mcpp { +void cxxflag(const char* flag){(void)flag;} +} diff --git a/conformance/fixtures/mcpp-build-programs-cross/mcpp-mock.json b/conformance/fixtures/mcpp-build-programs-cross/mcpp-mock.json new file mode 100644 index 00000000..883e3f61 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/mcpp-mock.json @@ -0,0 +1,717 @@ +{ + "database": { + "ide": { + "generator": { + "name": "mcpp", + "version": "2026.10.11.1" + }, + "profile-version": "0.3.0", + "toolchains": { + "llvm-22.1.8-x86_64-unknown-linux-gnu": { + "build-id": "ea8def082a061212", + "config-files": [], + "driver": "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "family": "clang", + "stdlib": { + "name": "libc++", + "version": "22.1.8" + }, + "target": "x86_64-unknown-linux-gnu", + "version": "22.1.8" + }, + "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine": { + "build-id": "ea8def082a061212", + "config-files": [], + "driver": "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "family": "clang", + "stdlib": { + "name": "libc++", + "version": "22.1.8" + }, + "target": "x86_64-unknown-linux-gnu", + "version": "22.1.8" + } + } + }, + "revision": 0, + "sets": [ + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache", + "-O0", + "-g", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module" + ], + "family-name": "mcpplibs.both", + "ide": { + "configuration": "dev", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu" + }, + "name": "mcpplibs.both", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache", + "-O0", + "-g", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module", + "-c", + "${root}/deps/both/src/both.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/mcpplibs_both/src/both.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/mcpplibs_both/src/both.m.o", + "private": false, + "provides": { + "both": "" + }, + "requires": [], + "source": "${root}/deps/both/src/both.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a" + } + ], + "visible-sets": [ + "app", + "mcpp:std" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache", + "-O0", + "-g", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-DGEN=7", + "-DBOTH=42" + ], + "family-name": "app", + "ide": { + "configuration": "dev", + "kind": "executable", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu" + }, + "name": "app", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache", + "-O0", + "-g", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-DGEN=7", + "-DBOTH=42", + "-x", + "c++-module", + "-c", + "${root}/src/greet.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/greet.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [ + "-x", + "c++-module" + ], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/greet.m.o", + "private": false, + "provides": { + "app.greet": "" + }, + "requires": [], + "source": "${root}/src/greet.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a" + }, + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/pcm.cache", + "-O0", + "-g", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-DGEN=7", + "-DBOTH=42", + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/modmap/app-33d32db8.modmap", + "-c", + "${root}/src/main.cpp", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/main.o" + ], + "ide": { + "role": "non-module" + }, + "local-arguments": [ + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/modmap/app-33d32db8.modmap" + ], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a/obj/main.o", + "private": false, + "provides": {}, + "requires": [ + "std", + "both", + "app.greet" + ], + "source": "${root}/src/main.cpp", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/x86_64-linux-gnu/b6e3a56e57139d1a" + } + ], + "visible-sets": [ + "mcpplibs.both", + "mcpp:std" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-Wno-reserved-module-identifier", + "--no-default-config", + "-nostdinc++", + "-stdlib=libc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "--precompile", + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "-o", + "pcm.cache/std.pcm" + ], + "family-name": "mcpp:std", + "ide": { + "configuration": "dev", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu" + }, + "name": "mcpp:std", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-Wno-reserved-module-identifier", + "--no-default-config", + "-nostdinc++", + "-stdlib=libc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "--precompile", + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "-o", + "pcm.cache/std.pcm" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1/std.o", + "private": false, + "provides": { + "std": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1/pcm.cache/std.pcm" + }, + "requires": [], + "source": "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "work-directory": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1" + } + ], + "visible-sets": [ + "mcpplibs.both", + "app" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module" + ], + "family-name": "mcpplibs.gen", + "ide": { + "configuration": "build-program", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine" + }, + "name": "mcpplibs.gen:host", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module", + "-c", + "${root}/deps/gen/src/gen.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpplibs_gen/src/gen.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpplibs_gen/src/gen.m.o", + "private": false, + "provides": { + "gen": "" + }, + "requires": [ + "std" + ], + "source": "${root}/deps/gen/src/gen.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4" + } + ], + "visible-sets": [ + "mcpplibs.both:host", + "mcpp:core", + "app:build", + "mcpp:std:host" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module" + ], + "family-name": "mcpplibs.both", + "ide": { + "configuration": "build-program", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine" + }, + "name": "mcpplibs.both:host", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module", + "-c", + "${root}/deps/both/src/both.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpplibs_both/src/both.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpplibs_both/src/both.m.o", + "private": false, + "provides": { + "both": "" + }, + "requires": [], + "source": "${root}/deps/both/src/both.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4" + } + ], + "visible-sets": [ + "mcpplibs.gen:host", + "mcpp:core", + "app:build", + "mcpp:std:host" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1" + ], + "family-name": "mcpp.core", + "ide": { + "configuration": "build-program", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine" + }, + "name": "mcpp:core", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "-x", + "c++-module", + "-c", + "${root}/engine/modules/mcpp.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpp_core/mcpp.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [ + "-x", + "c++-module" + ], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpp_core/mcpp.m.o", + "private": false, + "provides": { + "mcpp": "" + }, + "requires": [], + "source": "${root}/engine/modules/mcpp.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4" + }, + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/modmap/mcpp.core-541b33a3.modmap", + "-x", + "c++-module", + "-c", + "${root}/engine/modules/mcpp_core.cppm", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpp_core/mcpp_core.m.o" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [ + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/modmap/mcpp.core-541b33a3.modmap", + "-x", + "c++-module" + ], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/mcpp_core/mcpp_core.m.o", + "private": false, + "provides": { + "mcpp.core": "" + }, + "requires": [ + "mcpp" + ], + "source": "${root}/engine/modules/mcpp_core.cppm", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4" + } + ], + "visible-sets": [ + "mcpplibs.gen:host", + "mcpplibs.both:host", + "app:build", + "mcpp:std:host" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/modmap/app-eec2fa-163e2975.modmap", + "-x", + "c++" + ], + "family-name": "app", + "ide": { + "configuration": "build-program", + "kind": "executable", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine" + }, + "name": "app:build", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-fmodule-file=std=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache/std.pcm", + "-fprebuilt-module-path=${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/pcm.cache", + "-O0", + "-fPIC", + "--no-default-config", + "-nostdinc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "-D__MCPP_TARGET_LINUX__=1", + "@${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/modmap/app-eec2fa-163e2975.modmap", + "-x", + "c++", + "-c", + "${root}/build.mcpp", + "-o", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/app-eec2fa/__ext/eec2fa71/build.mcpp.o" + ], + "ide": { + "role": "non-module" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4/obj/app-eec2fa/__ext/eec2fa71/build.mcpp.o", + "private": false, + "provides": {}, + "requires": [ + "std", + "mcpp", + "gen", + "both" + ], + "source": "${root}/build.mcpp", + "work-directory": "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/target/x86_64-linux-gnu/20372b3b7dad2cf4" + } + ], + "visible-sets": [ + "mcpplibs.gen:host", + "mcpplibs.both:host", + "mcpp:core", + "mcpp:std:host" + ] + }, + { + "baseline-arguments": [ + "-std=c++23", + "-Wno-reserved-module-identifier", + "--no-default-config", + "-nostdinc++", + "-stdlib=libc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "--precompile", + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "-o", + "pcm.cache/std.pcm" + ], + "family-name": "mcpp:std", + "ide": { + "configuration": "build-program", + "kind": "library", + "toolchain": "llvm-22.1.8-x86_64-unknown-linux-gnu-build-machine" + }, + "name": "mcpp:std:host", + "translation-units": [ + { + "arguments": [ + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/bin/clang++", + "-std=c++23", + "-Wno-reserved-module-identifier", + "--no-default-config", + "-nostdinc++", + "-stdlib=libc++", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/c++/v1", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/include/x86_64-unknown-linux-gnu/c++/v1", + "-nostdlibinc", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.3/include", + "-isystem${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-linux-headers/5.11.1/include", + "--precompile", + "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "-o", + "pcm.cache/std.pcm" + ], + "ide": { + "role": "module-interface" + }, + "local-arguments": [], + "object": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1/std.o", + "private": false, + "provides": { + "std": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1/pcm.cache/std.pcm" + }, + "requires": [], + "source": "${env:HOME}/.mcpp/registry/data/xpkgs/xim-x-llvm/22.1.8/share/libc++/v1/std.cppm", + "work-directory": "${env:HOME}/.mcpp/build-cache/v1/std/a443bc8c43c26ef1" + } + ], + "visible-sets": [ + "mcpplibs.gen:host", + "mcpplibs.both:host", + "mcpp:core", + "app:build" + ] + } + ], + "version": 1 + }, + "watch": [ + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/mcpp.lock", + "${env:HOME}/.mcpp/cache/build-database/ae4d259c7716e5e2/target/.build-mcpp/host/8e2543cba42b/mcpp.toml", + "${env:HOME}/.mcpp/config.toml", + "build.mcpp", + "deps/both/mcpp.toml", + "deps/both/src/**/*.S", + "deps/both/src/**/*.asm", + "deps/both/src/**/*.c", + "deps/both/src/**/*.cc", + "deps/both/src/**/*.cpp", + "deps/both/src/**/*.cppm", + "deps/both/src/**/*.s", + "deps/gen/mcpp.toml", + "deps/gen/src/**/*.S", + "deps/gen/src/**/*.asm", + "deps/gen/src/**/*.c", + "deps/gen/src/**/*.cc", + "deps/gen/src/**/*.cpp", + "deps/gen/src/**/*.cppm", + "deps/gen/src/**/*.s", + "mcpp.lock", + "mcpp.toml", + "src/**/*.S", + "src/**/*.asm", + "src/**/*.c", + "src/**/*.cc", + "src/**/*.cpp", + "src/**/*.cppm", + "src/**/*.s", + "tests/**/*.cpp" + ] +} diff --git a/conformance/fixtures/mcpp-build-programs-cross/mcpp.toml b/conformance/fixtures/mcpp-build-programs-cross/mcpp.toml new file mode 100644 index 00000000..3ac9d413 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/mcpp.toml @@ -0,0 +1,19 @@ +[package] +name = "app" +version = "0.1.0" +description = "Conformance fixture: build programs compiled with a toolchain of their own (mcpp-community/mcpp#797)" +license = "Apache-2.0" + +[toolchain] +default = "llvm@22.1.8" + +[dependencies] +both = { path = "deps/both" } + +[build-dependencies] +gen = { path = "deps/gen" } +both = { path = "deps/both" } + +[targets.app] +kind = "bin" +main = "src/main.cpp" diff --git a/conformance/fixtures/mcpp-build-programs-cross/scenario.json b/conformance/fixtures/mcpp-build-programs-cross/scenario.json new file mode 100644 index 00000000..a03c41ce --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/scenario.json @@ -0,0 +1,141 @@ +{ + "name": "mcpp-build-programs-cross", + "description": "Build programs compiled with a toolchain of their own, as in a cross build, simulated by mcppls-mock-mcpp from what mcpp 2026.10.11.1 printed for mcpp-build-programs (mcpp-community/mcpp#797), with the build programs' sets given a second toolchain and mcpp's engine interface given stand-ins inside the fixture. The default context reads the targets and says where build.mcpp is read; the context app:build reads it with its own libraries; no formatting, code action or rename edits the engine interface.", + "server-arguments": [ + "--mcpp", + "{runner-dir}/mcppls-mock-mcpp{exe}" + ], + "checks": [ + { + "id": "S1", + "kind": "status", + "source": "mcpp", + "level": 3, + "state": "ready" + }, + { + "id": "T1", + "kind": "diagnostics-empty", + "file": "src/main.cpp" + }, + { + "id": "K1", + "kind": "diagnostic-code", + "file": "build.mcpp", + "expect": "build-program-context", + "severity": 3, + "line": 0, + "$comment": "the default context reads the targets; build programs compiled with another toolchain are read in their own context" + }, + { + "id": "K2", + "kind": "set-context", + "file": "build.mcpp", + "context": "app:build", + "at": [ + 7, + 44 + ], + "expect": "both_value" + }, + { + "id": "K3", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 6, + 19 + ], + "expect": "deps/gen/src/gen.cppm" + }, + { + "id": "K4", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 6, + 11 + ], + "expect": "engine/modules/mcpp_core.cppm" + }, + { + "id": "E1", + "kind": "request", + "file": "engine/modules/mcpp_core.cppm", + "method": "textDocument/formatting", + "params": { + "options": { + "tabSize": 4, + "insertSpaces": true + } + }, + "expect": [], + "$comment": "mcpp's engine interface is read-only: no edit is offered there" + }, + { + "id": "E2", + "kind": "request", + "file": "engine/modules/mcpp_core.cppm", + "method": "textDocument/codeAction", + "params": { + "range": { + "start": { + "line": 5, + "character": 0 + }, + "end": { + "line": 5, + "character": 10 + } + }, + "context": { + "diagnostics": [] + } + }, + "expect": [] + }, + { + "id": "E3", + "kind": "request", + "file": "engine/modules/mcpp_core.cppm", + "method": "textDocument/prepareRename", + "at": [ + 5, + 6 + ], + "expect": null + }, + { + "id": "E4", + "kind": "request", + "file": "engine/modules/mcpp_core.cppm", + "method": "textDocument/rename", + "at": [ + 5, + 6 + ], + "params": { + "newName": "flag" + }, + "expect-error": -32803 + }, + { + "id": "E5", + "kind": "request", + "file": "build.mcpp", + "method": "textDocument/rename", + "at": [ + 6, + 11 + ], + "params": { + "newName": "flag" + }, + "expect-error": -32803 + }, + { + "id": "W1", + "kind": "workspace-unchanged" + } + ] +} diff --git a/conformance/fixtures/mcpp-build-programs-cross/src/greet.cppm b/conformance/fixtures/mcpp-build-programs-cross/src/greet.cppm new file mode 100644 index 00000000..6f6c68d4 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/src/greet.cppm @@ -0,0 +1,3 @@ +export module app.greet; + +export const char* greeting() { return "hello"; } diff --git a/conformance/fixtures/mcpp-build-programs-cross/src/main.cpp b/conformance/fixtures/mcpp-build-programs-cross/src/main.cpp new file mode 100644 index 00000000..6eda41d5 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs-cross/src/main.cpp @@ -0,0 +1,5 @@ +import std; +import both; +import app.greet; + +int main() { std::println("{} {} {} {}", greeting(), both_value(), GEN, BOTH); } diff --git a/conformance/fixtures/mcpp-build-programs/build.mcpp b/conformance/fixtures/mcpp-build-programs/build.mcpp new file mode 100644 index 00000000..3d8993e2 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/build.mcpp @@ -0,0 +1,9 @@ +import std; +import mcpp; +import gen; +import both; + +int main() { + mcpp::cxxflag(generated_flag().c_str()); + mcpp::cxxflag(std::format("-DBOTH={}", both_value()).c_str()); +} diff --git a/conformance/fixtures/mcpp-build-programs/deps/both/mcpp.toml b/conformance/fixtures/mcpp-build-programs/deps/both/mcpp.toml new file mode 100644 index 00000000..f0d858b2 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/deps/both/mcpp.toml @@ -0,0 +1,7 @@ +[package] +name = "both" +version = "0.1.0" +license = "Apache-2.0" + +[targets.both] +kind = "lib" diff --git a/conformance/fixtures/mcpp-build-programs/deps/both/src/both.cppm b/conformance/fixtures/mcpp-build-programs/deps/both/src/both.cppm new file mode 100644 index 00000000..f7272206 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/deps/both/src/both.cppm @@ -0,0 +1,3 @@ +export module both; + +export int both_value() { return 42; } diff --git a/conformance/fixtures/mcpp-build-programs/deps/gen/mcpp.toml b/conformance/fixtures/mcpp-build-programs/deps/gen/mcpp.toml new file mode 100644 index 00000000..0bf0ba7f --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/deps/gen/mcpp.toml @@ -0,0 +1,7 @@ +[package] +name = "gen" +version = "0.1.0" +license = "Apache-2.0" + +[targets.gen] +kind = "lib" diff --git a/conformance/fixtures/mcpp-build-programs/deps/gen/src/gen.cppm b/conformance/fixtures/mcpp-build-programs/deps/gen/src/gen.cppm new file mode 100644 index 00000000..b55c4070 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/deps/gen/src/gen.cppm @@ -0,0 +1,4 @@ +export module gen; +import std; + +export std::string generated_flag() { return "-DGEN=7"; } diff --git a/conformance/fixtures/mcpp-build-programs/mcpp.toml b/conformance/fixtures/mcpp-build-programs/mcpp.toml new file mode 100644 index 00000000..3b55dfef --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/mcpp.toml @@ -0,0 +1,19 @@ +[package] +name = "app" +version = "0.1.0" +description = "Conformance fixture: a build program with libraries of its own (mcpp-community/mcpp#797)" +license = "Apache-2.0" + +[toolchain] +default = "llvm@22.1.8" + +[dependencies] +both = { path = "deps/both" } + +[build-dependencies] +gen = { path = "deps/gen" } +both = { path = "deps/both" } + +[targets.app] +kind = "bin" +main = "src/main.cpp" diff --git a/conformance/fixtures/mcpp-build-programs/scenario.json b/conformance/fixtures/mcpp-build-programs/scenario.json new file mode 100644 index 00000000..abce8f67 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/scenario.json @@ -0,0 +1,150 @@ +{ + "name": "mcpp-build-programs", + "description": "A package whose build.mcpp imports mcpp's engine interface and a library of [build-dependencies], gen, and which has a package, both, in both tables, described by mcpp's own `emit build-database` (mcpp 2026.10.11.1, mcpp-community/mcpp#797): build.mcpp is read as C++ with the arguments of its own set, its imports resolve in the build programs' graph, navigation reaches the engine interface, the target reads both as it builds it, and an import across the two configurations is diagnosed. MCPPLS_BUILD_PROGRAMS_MCPP names an mcpp of that version or later, which CI installs beside the pinned one; unset, the mcpp on PATH is asked.", + "server-arguments": [ + "--mcpp", + "{env:MCPPLS_BUILD_PROGRAMS_MCPP|}" + ], + "checks": [ + { + "id": "S1", + "kind": "status", + "source": "mcpp", + "profile-kind": "build-toolchain", + "profile-compiler": "clang", + "level": 3, + "state": "ready" + }, + { + "id": "T1", + "kind": "diagnostics-empty", + "file": "src/main.cpp", + "$comment": "GEN and BOTH are the flags build.mcpp gives the target: mcpp ran the build program to describe the target" + }, + { + "id": "T2", + "kind": "definition", + "file": "src/main.cpp", + "at": [ + 4, + 54 + ], + "expect": "deps/both/src/both.cppm" + }, + { + "id": "B1", + "kind": "diagnostics-empty", + "file": "build.mcpp", + "$comment": "build.mcpp is C++ by mcpp's -x c++ and its imports resolve in the build programs' graph" + }, + { + "id": "B2", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 6, + 19 + ], + "expect": "deps/gen/src/gen.cppm" + }, + { + "id": "B3", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 7, + 44 + ], + "expect": "deps/both/src/both.cppm" + }, + { + "id": "B4", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 6, + 11 + ], + "expect": "modules/mcpp.cppm", + "$comment": "mcpp's engine interface, under /engine//modules" + }, + { + "id": "B5", + "kind": "hover-contains", + "file": "build.mcpp", + "at": [ + 6, + 11 + ], + "expect": "cxxflag" + }, + { + "id": "B6", + "kind": "definition", + "file": "build.mcpp", + "at": [ + 2, + 8 + ], + "expect": "deps/gen/src/gen.cppm" + }, + { + "id": "R1", + "kind": "request", + "file": "build.mcpp", + "method": "textDocument/rename", + "at": [ + 6, + 11 + ], + "params": { + "newName": "flag" + }, + "expect-error": -32803, + "$comment": "a rename that would edit mcpp's engine interface is refused as a whole" + }, + { + "id": "B7", + "kind": "completion-contains", + "file": "build.mcpp", + "insert": [ + 8, + " mcpp::" + ], + "at": [ + 8, + 10 + ], + "expect": "cxxflag" + }, + { + "id": "X1", + "kind": "diagnostic-code", + "file": "src/main.cpp", + "text": "import mcpp;\nint main() {}\n", + "expect": "build-program-module", + "line": 0, + "$comment": "SPEC-007 P1: a target does not import the engine interface" + }, + { + "id": "X2", + "kind": "diagnostic-code", + "file": "src/main.cpp", + "text": "import std;\nimport gen;\nint main() {}\n", + "expect": "build-program-module", + "line": 1 + }, + { + "id": "X3", + "kind": "diagnostic-code", + "file": "build.mcpp", + "text": "import app.greet;\nint main() {}\n", + "expect": "target-module", + "line": 0 + }, + { + "id": "W1", + "kind": "workspace-unchanged" + } + ] +} diff --git a/conformance/fixtures/mcpp-build-programs/src/greet.cppm b/conformance/fixtures/mcpp-build-programs/src/greet.cppm new file mode 100644 index 00000000..6f6c68d4 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/src/greet.cppm @@ -0,0 +1,3 @@ +export module app.greet; + +export const char* greeting() { return "hello"; } diff --git a/conformance/fixtures/mcpp-build-programs/src/main.cpp b/conformance/fixtures/mcpp-build-programs/src/main.cpp new file mode 100644 index 00000000..6eda41d5 --- /dev/null +++ b/conformance/fixtures/mcpp-build-programs/src/main.cpp @@ -0,0 +1,5 @@ +import std; +import both; +import app.greet; + +int main() { std::println("{} {} {} {}", greeting(), both_value(), GEN, BOTH); } diff --git a/conformance/fixtures/mcpp-emit/build.mcpp b/conformance/fixtures/mcpp-emit/build.mcpp new file mode 100644 index 00000000..caf6b311 --- /dev/null +++ b/conformance/fixtures/mcpp-emit/build.mcpp @@ -0,0 +1,3 @@ +import mcpp; + +int main() { mcpp::cxxflag("-DGREETING_FROM_BUILD=1"); } diff --git a/conformance/fixtures/mcpp-emit/scenario.json b/conformance/fixtures/mcpp-emit/scenario.json index eadef86a..5215d483 100644 --- a/conformance/fixtures/mcpp-emit/scenario.json +++ b/conformance/fixtures/mcpp-emit/scenario.json @@ -1,6 +1,6 @@ { "name": "mcpp-emit", - "description": "mcpp answering `emit build-database --format json` (mcpp-community/mcpp#636), simulated by mcppls-mock-mcpp from recorded data in the shape mcpp decided: a level 2 database with one set for the package, one for its tests (hello:test) and one for the standard library modules mcpp builds (mcpp:std), each seeing every other. The S1 library completes the model to level 3; nothing is configured or written in the project.", + "description": "mcpp answering `emit build-database --format json` (mcpp-community/mcpp#636), simulated by mcppls-mock-mcpp from recorded data in the shape mcpp decided: a level 2 database with one set for the package, one for its tests (hello:test) and one for the standard library modules mcpp builds (mcpp:std), each seeing every other. The S1 library completes the model to level 3; nothing is configured or written in the project. The package's build.mcpp, which an mcpp of that age does not describe, is not read, and says which mcpp describes it.", "server-arguments": [ "--mcpp", "{runner-dir}/mcppls-mock-mcpp{exe}" @@ -127,6 +127,18 @@ ], "expect": "src/greet/greet.cppm" }, + { + "id": "B1-undescribed", + "kind": "diagnostic-code", + "file": "build.mcpp", + "expect": "build-program-context", + "severity": 3, + "line": 0, + "absent": [ + "unresolved-module" + ], + "$comment": "mcpp-community/mcpp#797: the database of an mcpp older than 2026.10.11.1 does not describe build.mcpp; it is not read, and the status of the file says which mcpp describes it" + }, { "id": "W1", "kind": "workspace-unchanged" diff --git a/conformance/fixtures/mcpp-split/scenario.json b/conformance/fixtures/mcpp-split/scenario.json index 8c236b16..0921299d 100644 --- a/conformance/fixtures/mcpp-split/scenario.json +++ b/conformance/fixtures/mcpp-split/scenario.json @@ -576,7 +576,7 @@ "timeout": 60 }, { - "id": "O1-planned-with-a-stand-in", + "id": "O1-planned-open-file", "kind": "report", "timeout": 10, "expect": [ @@ -584,16 +584,24 @@ "path": "/roots/0/plan/openSources", "min-items": 1 }, - { - "path": "/roots/0/plan/standIns", - "contains": "hello.gui" - }, { "path": "/roots/0/engines/*/details/filesSetAside", "max-items": 0 } ] }, + { + "id": "O1b-its-import-gets-a-stand-in", + "retired-by": "unresolved-import-recovery", + "kind": "report", + "timeout": 10, + "expect": [ + { + "path": "/roots/0/plan/standIns", + "contains": "hello.gui" + } + ] + }, { "id": "W1", "kind": "workspace-unchanged" diff --git a/conformance/fixtures/preparation-after-idle/scenario.json b/conformance/fixtures/preparation-after-idle/scenario.json new file mode 100644 index 00000000..b7e98aa7 --- /dev/null +++ b/conformance/fixtures/preparation-after-idle/scenario.json @@ -0,0 +1,13 @@ +{ + "name": "preparation-after-idle", + "description": "Issue #49: preparation that ended a long while ago, given modules again (a file opened that imports one nothing prepared yet, a model loaded again), starts its stall clock afresh. 0.0.11 measured it from the last progress of the preparation before, so it was 'preparation-stalled ... made no progress for a minute (34/39 done)' five seconds after it began, and wrote a bundle.", + "server-arguments": ["--no-discover"], + "checks": [ + {"id": "S1", "kind": "status", "source": "inferred", "state": "ready", "engine-name": "clangd"}, + {"id": "P0-first-preparation", "kind": "hover-contains", "file": "src/main.cpp", "at": [2, 21], "expect": "fa", "timeout": 90}, + {"id": "P1-idle-past-the-stall-timeout", "kind": "report", "not-before-since-start": 80, "timeout": 30, + "expect": [{"path": "/roots/0/engines/*/details/preparation/running", "equals": 0}]}, + {"id": "P2-more-to-prepare", "kind": "hover-contains", "file": "src/second.cpp", "at": [2, 21], "expect": "fb", "timeout": 60}, + {"id": "P3-never-stalled", "kind": "status-never", "issue-codes": ["preparation-stalled"]} + ] +} diff --git a/conformance/fixtures/preparation-after-idle/src/a.cppm b/conformance/fixtures/preparation-after-idle/src/a.cppm new file mode 100644 index 00000000..f69f91d7 --- /dev/null +++ b/conformance/fixtures/preparation-after-idle/src/a.cppm @@ -0,0 +1,2 @@ +export module a; +export int fa() { return 1; } diff --git a/conformance/fixtures/preparation-after-idle/src/b.cppm b/conformance/fixtures/preparation-after-idle/src/b.cppm new file mode 100644 index 00000000..5bfc1bc3 --- /dev/null +++ b/conformance/fixtures/preparation-after-idle/src/b.cppm @@ -0,0 +1,2 @@ +export module b; +export int fb() { return 2; } diff --git a/conformance/fixtures/preparation-after-idle/src/main.cpp b/conformance/fixtures/preparation-after-idle/src/main.cpp new file mode 100644 index 00000000..c30cec9b --- /dev/null +++ b/conformance/fixtures/preparation-after-idle/src/main.cpp @@ -0,0 +1,3 @@ +import a; + +int main() { return fa(); } diff --git a/conformance/fixtures/preparation-after-idle/src/second.cpp b/conformance/fixtures/preparation-after-idle/src/second.cpp new file mode 100644 index 00000000..4510bc88 --- /dev/null +++ b/conformance/fixtures/preparation-after-idle/src/second.cpp @@ -0,0 +1,3 @@ +import b; + +int g() { return fb(); } diff --git a/conformance/fixtures/save-plan/scenario.json b/conformance/fixtures/save-plan/scenario.json new file mode 100644 index 00000000..0bff8906 --- /dev/null +++ b/conformance/fixtures/save-plan/scenario.json @@ -0,0 +1,83 @@ +{ + "name": "save-plan", + "description": "Actual autosave keeps new exports visible when the module graph is unchanged, and replans a new exported import. No compiler or build system.", + "server-arguments": [ + "--no-discover" + ], + "checks": [ + { + "id": "SAVE-ready", + "kind": "status", + "source": "inferred", + "profile-kind": "semantic-kit", + "state": "ready", + "engine-name": "clangd" + }, + { + "id": "SAVE-initial", + "kind": "diagnostics-empty", + "file": "src/main.cpp" + }, + { + "id": "SAVE-export", + "kind": "type-text", + "file": "src/value.cppm", + "line": 4, + "steps": [ + " int added() { return 2; }" + ], + "save": true, + "interval-ms": 1000, + "answer-within": 5, + "states-never": [ + "error" + ] + }, + { + "id": "SAVE-export-visible", + "kind": "completion-contains", + "file": "src/main.cpp", + "insert": [ + 3, + " sample::" + ], + "at": [ + 3, + 10 + ], + "expect": [ + "original", + "added" + ] + }, + { + "id": "SAVE-import", + "kind": "type-text", + "file": "src/value.cppm", + "line": 1, + "steps": [ + "export import save.extra;" + ], + "save": true, + "interval-ms": 1000, + "answer-within": 5, + "states-never": [ + "error" + ] + }, + { + "id": "SAVE-import-visible", + "kind": "completion-contains", + "file": "src/main.cpp", + "at": [ + 3, + 10 + ], + "expect": [ + "original", + "added", + "extra" + ] + } + ] +} diff --git a/conformance/fixtures/save-plan/src/extra.cppm b/conformance/fixtures/save-plan/src/extra.cppm new file mode 100644 index 00000000..61d324ec --- /dev/null +++ b/conformance/fixtures/save-plan/src/extra.cppm @@ -0,0 +1,2 @@ +export module save.extra; +export namespace sample { int extra() { return 3; } } diff --git a/conformance/fixtures/save-plan/src/main.cpp b/conformance/fixtures/save-plan/src/main.cpp new file mode 100644 index 00000000..c213d1ad --- /dev/null +++ b/conformance/fixtures/save-plan/src/main.cpp @@ -0,0 +1,4 @@ +import save.value; +int main() { + sample::original(); +} diff --git a/conformance/fixtures/save-plan/src/value.cppm b/conformance/fixtures/save-plan/src/value.cppm new file mode 100644 index 00000000..2eb9c1b7 --- /dev/null +++ b/conformance/fixtures/save-plan/src/value.cppm @@ -0,0 +1,6 @@ +export module save.value; +// imports +export namespace sample { + int original() { return 1; } + // exports +} diff --git a/conformance/fixtures/typing-autosave/scenario.json b/conformance/fixtures/typing-autosave/scenario.json index 9b11a832..dd45747b 100644 --- a/conformance/fixtures/typing-autosave/scenario.json +++ b/conformance/fixtures/typing-autosave/scenario.json @@ -68,6 +68,7 @@ }, { "id": "T3-disk-seen", + "retired-by": "module-directive-recovery", "kind": "report", "timeout": 20, "expect": [ @@ -195,7 +196,15 @@ { "path": "/roots/0/engines/*/details/filesSetAside", "max-items": 0 - }, + } + ] + }, + { + "id": "T10b-handed-back", + "retired-by": "unresolved-import-recovery", + "kind": "report", + "timeout": 30, + "expect": [ { "path": "/roots/0/events/*/kind", "equals": "file-handed-back" diff --git a/conformance/fixtures/typing-import-spin/scenario.json b/conformance/fixtures/typing-import-spin/scenario.json index 991dcbb4..2bf3e0c3 100644 --- a/conformance/fixtures/typing-import-spin/scenario.json +++ b/conformance/fixtures/typing-import-spin/scenario.json @@ -1,6 +1,6 @@ { "name": "typing-import-spin", - "description": "Import-hang plan \u00a74 against the real defect: WA-CLANGD-001 turned off, so clangd 23.1 spins on `import hello.` (Linux, macOS) or crashes on it (Windows). A spin is found within its 20 s budget, the file set aside with that text remembered and clangd restarted; a crash is restarted as before; either way features come back while typing goes on. If a clangd update removes the defect, T2 fails too: WA-CLANGD-001 can then go.", + "description": "Import-hang plan \u00a74 against the real defect: WA-CLANGD-001 turned off, so clangd 23.1 spins on `import hello.` (Linux, macOS) or crashes on it (Windows). A spin is found within its 20 s budget, the file set aside with that text remembered and clangd restarted; a crash is restarted as before; either way features come back while typing goes on. If a clangd update removes the defect, T2 fails too: WA-CLANGD-001 can then go. An engine whose verified identity declares module-directive-recovery has no such spin by proof, and T2 reports itself retired there.", "server-arguments": [ "--no-discover", "--disable-workaround", @@ -59,6 +59,7 @@ }, { "id": "T2-spin-found", + "retired-by": "module-directive-recovery", "kind": "report", "timeout": 60, "expect": [ @@ -78,6 +79,7 @@ }, { "id": "T2-crash-restarted", + "retired-by": "module-directive-recovery", "kind": "report", "timeout": 60, "only-on": [ diff --git a/conformance/fixtures/typing-import/scenario.json b/conformance/fixtures/typing-import/scenario.json index d2133da2..f12c8f0e 100644 --- a/conformance/fixtures/typing-import/scenario.json +++ b/conformance/fixtures/typing-import/scenario.json @@ -125,6 +125,7 @@ }, { "id": "T6-workaround-on", + "retired-by": "module-directive-recovery", "kind": "report", "expect": [ { diff --git a/conformance/fixtures/ux-mcpp/scenario.json b/conformance/fixtures/ux-mcpp/scenario.json index a6020e55..9fd0c3d1 100644 --- a/conformance/fixtures/ux-mcpp/scenario.json +++ b/conformance/fixtures/ux-mcpp/scenario.json @@ -355,6 +355,7 @@ "expect": "ux_undeclared_name" }, "budget": { + "firstOpenSeconds": 90, "p95": 1.0, "max": 3.0, "timeouts": 0, @@ -413,6 +414,7 @@ }, "autosave-ms": 1000, "budget": { + "firstOpenSeconds": 90, "p95": 1.0, "max": 3.0, "timeouts": 0, @@ -455,6 +457,7 @@ "text": " int ux_probe_value = 1; ux_probe_" }, "budget": { + "firstOpenSeconds": 90, "p95": 1.1, "importerP95": 1.5, "importerEmpty": 0, diff --git a/conformance/fixtures/ux-modules-qt/CMakeLists.txt b/conformance/fixtures/ux-modules-qt/CMakeLists.txt new file mode 100644 index 00000000..b8a14bc2 --- /dev/null +++ b/conformance/fixtures/ux-modules-qt/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.28) +project(inventory LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Qt 5 (qtbase5-dev): its headers in the global module fragments, as a Qt project written with modules has them. +# The distribution's prefix is named: a CMake installed elsewhere (xlings') does not search it on its own. +list(APPEND CMAKE_PREFIX_PATH /usr /usr/lib/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu/cmake) +find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets) + +add_library(views) +target_sources(views PUBLIC FILE_SET CXX_MODULES FILES src/model.cppm src/view.cppm) +target_link_libraries(views PUBLIC Qt5::Widgets) + +add_executable(app src/main.cpp) +target_link_libraries(app PRIVATE views) diff --git a/conformance/fixtures/ux-modules-qt/scenario.json b/conformance/fixtures/ux-modules-qt/scenario.json new file mode 100644 index 00000000..8e609fcc --- /dev/null +++ b/conformance/fixtures/ux-modules-qt/scenario.json @@ -0,0 +1,238 @@ +{ + "name": "ux-modules-qt", + "description": "C++ modules mixed with Qt headers (0.0.12, issue #50): a module unit whose global module fragment includes , another that includes Qt Core headers, and a file that includes Qt headers and imports both, built by CMake with clang++ against the system's Qt 5 (qtbase5-dev). Answers are right, and they stay fast while a person types in the importer and in a module unit that autosaves: every completion answered, no restart (a crash counts as one), nothing set aside, diagnostics back within seconds.", + "server-arguments": [ + "--no-discover" + ], + "prepare": [ + [ + "cmake", + "-S", + ".", + "-B", + "build", + "-G", + "Ninja", + "-DCMAKE_CXX_COMPILER={env:CONFORMANCE_CLANGXX|clang++}", + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + ], + [ + "cmake", + "--build", + "build" + ] + ], + "checks": [ + { + "id": "S1", + "kind": "status", + "source": "cmake", + "state": "ready", + "engine-name": "clangd" + }, + { + "id": "C1", + "kind": "diagnostics-empty", + "file": "src/main.cpp", + "timeout": 240 + }, + { + "id": "C1-module-with-qt-widgets", + "kind": "diagnostics-empty", + "file": "src/view.cppm", + "timeout": 240 + }, + { + "id": "C2-hover-module-member", + "kind": "hover-contains", + "file": "src/main.cpp", + "at": [ + 8, + 16 + ], + "expect": "addItem", + "timeout": 120 + }, + { + "id": "C3-definition-into-module", + "kind": "definition", + "file": "src/main.cpp", + "at": [ + 8, + 16 + ], + "expect": "src/model.cppm", + "timeout": 60 + }, + { + "id": "C4-qt-member-through-module", + "kind": "hover-contains", + "file": "src/main.cpp", + "at": [ + 10, + 32 + ], + "expect": "rowCount", + "timeout": 60 + }, + { + "id": "U3-idle", + "kind": "latency", + "phase": "idle", + "rounds": 20, + "requests": [ + { + "kind": "completion", + "name": "module-member", + "file": "src/main.cpp", + "at": [ + 10, + 31 + ] + }, + { + "kind": "completion", + "name": "qt-member", + "file": "src/main.cpp", + "at": [ + 10, + 11 + ] + }, + { + "kind": "hover", + "file": "src/main.cpp", + "at": [ + 8, + 16 + ] + }, + { + "kind": "definition", + "file": "src/main.cpp", + "at": [ + 8, + 16 + ], + "expect": "src/model.cppm" + } + ], + "budget": { + "completion.p95": 0.5, + "hover.p95": 0.3, + "definition.p95": 0.5, + "engineShare": 0.9 + } + }, + { + "id": "U5-typing-in-the-importer", + "kind": "typing", + "file": "src/main.cpp", + "seconds": 60, + "hz": 10, + "completion-every-ms": 1000, + "scripts": [ + { + "line": 12, + "text": "inventory.addItem(QStringLiteral(\"nut\")); window.showCount(inventory.rowC" + }, + { + "line": 12, + "text": "auto names = inventory.itemNames(); names.sort(); window.setWindowTitle(names.join(QStringLiteral(\", \")));" + }, + { + "line": 12, + "text": "QTimer timer; timer.setInterval(100); QObject::connect(&timer, &QTimer::timeout, &app, [&] { window.showCount(inventory.rowCount()); });" + }, + { + "line": 12, + "text": "for (const auto& name : inventory.itemNames()) { window.statusBar()->showMessage(name); }" + } + ], + "diagnostic-probe": { + "line": 12, + "text": "int ux_probe_typo = ux_undeclared_name;", + "expect": "ux_undeclared_name" + }, + "budget": { + "firstOpenSeconds": 120, + "p95": 1.0, + "max": 3.0, + "timeouts": 0, + "restarts": 0, + "filesSetAside": 0, + "engineShare": 0.75, + "diagnosticsRefresh": 6.0 + } + }, + { + "id": "U16-module-autosave", + "kind": "typing", + "file": "src/model.cppm", + "seconds": 60, + "hz": 10, + "completion-every-ms": 1000, + "autosave-idle-ms": 1000, + "scripts": [ + { + "line": 22, + "text": "int countMatching(const QString& prefix) const { int total = 0; for (const auto& item : items_) { if (item.startsWith(prefix)) ++tot" + }, + { + "line": 22, + "text": "QString firstItem() const { return items_.isEmpty() ? QString() : items_.fir" + } + ], + "importer": { + "file": "src/main.cpp", + "line": 12, + "text": " inventory." + }, + "budget": { + "p95": 1.0, + "max": 3.0, + "timeouts": 0, + "restarts": 0, + "filesSetAside": 0, + "importerP95": 1.5, + "moduleFailedDiagnostics": 0, + "stalled": 0, + "firstOpenSeconds": 120 + }, + "description": "While the module unit does not compile (half a statement autosaved), its importer's completions on that module's names come from mcppls's own engine, empty, as with stock clangd: the budget holds how fast they come, not what they hold (keeping the last BMI that built is for a later version)." + }, + { + "id": "STRESS1", + "kind": "stress", + "seed": 11, + "actions": 60, + "requestTimeout": 65, + "files": [ + "src/*.cppm", + "src/*.cpp" + ], + "budget": { + "timeouts": 0, + "p90": 5, + "maxStallSeconds": 45, + "rssMB": 3000 + } + }, + { + "id": "R1-no-crash-no-restart", + "kind": "report", + "timeout": 10, + "expect": [ + { + "path": "/roots/0/engines/*/details/restarts", + "max-items": 0 + }, + { + "path": "/roots/0/engines/*/details/filesSetAside", + "max-items": 0 + } + ] + } + ], + "failure-log-lines": "Textual module preamble|replay differs|scan memo declined|scan manifest probe boundary|Built preamble of size" +} diff --git a/conformance/fixtures/ux-modules-qt/src/main.cpp b/conformance/fixtures/ux-modules-qt/src/main.cpp new file mode 100644 index 00000000..8a144df1 --- /dev/null +++ b/conformance/fixtures/ux-modules-qt/src/main.cpp @@ -0,0 +1,14 @@ +#include +#include +import views.model; +import views.view; + +int main(int argc, char* argv[]) { + QApplication app(argc, argv); + views::Inventory inventory; + inventory.addItem(QStringLiteral("bolt")); + views::InventoryWindow window(&inventory); + window.showCount(inventory.rowCount()); + QTimer::singleShot(0, &app, &QApplication::quit); + return app.exec(); +} diff --git a/conformance/fixtures/ux-modules-qt/src/model.cppm b/conformance/fixtures/ux-modules-qt/src/model.cppm new file mode 100644 index 00000000..a3839774 --- /dev/null +++ b/conformance/fixtures/ux-modules-qt/src/model.cppm @@ -0,0 +1,27 @@ +module; +#include +#include +export module views.model; + +export namespace views { + +class Inventory : public QAbstractListModel { +public: + explicit Inventory(QObject* parent = nullptr) : QAbstractListModel(parent) {} + int rowCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : items_.size(); } + QVariant data(const QModelIndex& index, int role) const override { + if (!index.isValid() || role != Qt::DisplayRole) return {}; + return items_.at(index.row()); + } + void addItem(const QString& item) { + beginInsertRows({}, items_.size(), items_.size()); + items_.append(item); + endInsertRows(); + } + QStringList itemNames() const { return items_; } + +private: + QStringList items_; +}; + +} // namespace views diff --git a/conformance/fixtures/ux-modules-qt/src/view.cppm b/conformance/fixtures/ux-modules-qt/src/view.cppm new file mode 100644 index 00000000..608afbdd --- /dev/null +++ b/conformance/fixtures/ux-modules-qt/src/view.cppm @@ -0,0 +1,19 @@ +module; +#include +export module views.view; +import views.model; + +export namespace views { + +class InventoryWindow : public QMainWindow { +public: + explicit InventoryWindow(Inventory* inventory) { + auto* list = new QListView(this); + list->setModel(inventory); + setCentralWidget(list); + setWindowTitle(QStringLiteral("Inventory")); + } + void showCount(int count) { statusBar()->showMessage(QString::number(count)); } +}; + +} // namespace views diff --git a/conformance/fixtures/ux-modules-windows/CMakeLists.txt b/conformance/fixtures/ux-modules-windows/CMakeLists.txt new file mode 100644 index 00000000..369a1ebf --- /dev/null +++ b/conformance/fixtures/ux-modules-windows/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.28) +project(winapp LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# in the global module fragments, as a Windows program written with modules has it. +add_library(platform) +target_sources(platform PUBLIC FILE_SET CXX_MODULES FILES src/process.cppm src/files.cppm) +target_compile_definitions(platform PUBLIC UNICODE _UNICODE NOMINMAX) + +add_executable(app src/main.cpp) +target_link_libraries(app PRIVATE platform) diff --git a/conformance/fixtures/ux-modules-windows/scenario.json b/conformance/fixtures/ux-modules-windows/scenario.json new file mode 100644 index 00000000..e9e10388 --- /dev/null +++ b/conformance/fixtures/ux-modules-windows/scenario.json @@ -0,0 +1,235 @@ +{ + "name": "ux-modules-windows", + "description": "C++ modules mixed with (0.0.12, issue #50): two module units whose global module fragments include , and a file that includes it and imports both, built by CMake with MSVC (cl.exe) and Ninja. Answers are right, and they stay fast while a person types in the importer and in a module unit that autosaves: every completion answered, diagnostics back within seconds (a report had them five or six seconds behind each keystroke), no restart (a crash counts as one), nothing set aside. The typing budgets are what the 4-vCPU Windows runner measured over its first rounds, with a margin: a completion there costs about 0.5 s even idle (clang parses the body against the 28 MB preamble and the module files; stock clangd has no preamble for such a file and parses every header for each request), and one clangd has not answered within mcppls's 1 s budget is answered by mcppls, so U5's p95 sits at 1.0 s whenever a twentieth of them land past it (0.79-1.00 s measured); its p95 budget is 1.1 s, and its engine share is 0.65, not ux-mcpp's 0.75: the runner measured 0.72-0.90 over its rounds, a fifth of the completions landing past the 1 s budget.", + "prepare-environment": "msvc", + "prepare": [ + [ + "cmake", + "-S", + ".", + "-B", + "build", + "-G", + "Ninja", + "-DCMAKE_CXX_COMPILER=cl", + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + ], + [ + "cmake", + "--build", + "build" + ] + ], + "checks": [ + { + "id": "S1", + "kind": "status", + "source": "cmake", + "profile-kind": "build-toolchain", + "state": "ready" + }, + { + "id": "C1", + "kind": "diagnostics-empty", + "file": "src/main.cpp", + "timeout": 240 + }, + { + "id": "C1-module-with-windows-h", + "kind": "diagnostics-empty", + "file": "src/files.cppm", + "timeout": 240 + }, + { + "id": "C2-hover-module-member", + "kind": "hover-contains", + "file": "src/main.cpp", + "at": [ + 8, + 28 + ], + "expect": "entryNames", + "timeout": 120 + }, + { + "id": "C3-definition-into-module", + "kind": "definition", + "file": "src/main.cpp", + "at": [ + 8, + 28 + ], + "expect": "src/files.cppm", + "timeout": 60 + }, + { + "id": "C4-windows-api", + "kind": "hover-contains", + "file": "src/main.cpp", + "at": [ + 10, + 6 + ], + "expect": "SetLastError", + "timeout": 60 + }, + { + "id": "U3-idle", + "kind": "latency", + "phase": "idle", + "rounds": 20, + "requests": [ + { + "kind": "completion", + "name": "module-member", + "file": "src/main.cpp", + "at": [ + 9, + 35 + ] + }, + { + "kind": "completion", + "name": "windows-api", + "file": "src/main.cpp", + "at": [ + 10, + 7 + ] + }, + { + "kind": "hover", + "file": "src/main.cpp", + "at": [ + 8, + 28 + ] + }, + { + "kind": "definition", + "file": "src/main.cpp", + "at": [ + 8, + 28 + ], + "expect": "src/files.cppm" + } + ], + "budget": { + "completion.p95": 0.8, + "hover.p95": 0.3, + "definition.p95": 0.5, + "engineShare": 0.9 + } + }, + { + "id": "U5-typing-in-the-importer", + "kind": "typing", + "file": "src/main.cpp", + "seconds": 60, + "hz": 10, + "completion-every-ms": 1000, + "scripts": [ + { + "line": 11, + "text": "DWORD written = 0; HANDLE out = ::GetStdHandle(STD_OUTPUT_HANDLE); ::WriteConsoleW(out, L\"x\", 1, &writ" + }, + { + "line": 11, + "text": "auto uptime = process.uptimeMilliseconds(); if (uptime > 0 && process.isCurr" + }, + { + "line": 11, + "text": "for (const auto& name : directory.entryNames()) { ::OutputDebugStringW(name.c_s" + }, + { + "line": 11, + "text": "SYSTEMTIME now {}; ::GetLocalTime(&now); std::wstring stamp = std::to_wstring(now.wHo" + } + ], + "diagnostic-probe": { + "line": 11, + "text": "int ux_probe_typo = ux_undeclared_name;", + "expect": "ux_undeclared_name" + }, + "budget": { + "firstOpenSeconds": 120, + "p95": 1.1, + "max": 3.0, + "timeouts": 0, + "restarts": 0, + "filesSetAside": 0, + "engineShare": 0.65, + "diagnosticsRefresh": 4.0 + } + }, + { + "id": "U16-module-autosave", + "kind": "typing", + "file": "src/process.cppm", + "seconds": 60, + "hz": 10, + "completion-every-ms": 1000, + "autosave-idle-ms": 1000, + "scripts": [ + { + "line": 13, + "text": "inline DWORD sessionId() { DWORD session = 0; ::ProcessIdToSessionId(::GetCurrentProcessId(), &sess" + }, + { + "line": 13, + "text": "inline bool isElevated() { HANDLE token = nullptr; if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &tok" + } + ], + "importer": { + "file": "src/main.cpp", + "line": 11, + "text": " directory." + }, + "budget": { + "firstOpenSeconds": 120, + "p95": 1.0, + "max": 3.0, + "timeouts": 0, + "restarts": 0, + "filesSetAside": 0, + "stalled": 0, + "importerP95": 1.5 + }, + "description": "While the module unit does not compile (half a statement autosaved), its importer's completions on that module's names come from mcppls's own engine, empty, as with stock clangd: the budget holds how fast they come, not what they hold (keeping the last BMI that built is for a later version)." + }, + { + "id": "STRESS1", + "kind": "stress", + "seed": 13, + "actions": 60, + "requestTimeout": 65, + "files": [ + "src/*.cppm", + "src/*.cpp" + ], + "budget": { + "timeouts": 0, + "p90": 5, + "maxStallSeconds": 45, + "rssMB": 3000 + } + }, + { + "id": "R1-no-crash-no-restart", + "kind": "report", + "timeout": 10, + "expect": [ + { + "path": "/roots/0/engines/*/details/restarts", + "max-items": 0 + }, + { + "path": "/roots/0/engines/*/details/filesSetAside", + "max-items": 0 + } + ] + } + ], + "failure-log-lines": "Textual module preamble|replay differs|scan memo declined|scan manifest probe boundary|Built preamble of size" +} diff --git a/conformance/fixtures/ux-modules-windows/src/files.cppm b/conformance/fixtures/ux-modules-windows/src/files.cppm new file mode 100644 index 00000000..9f795a84 --- /dev/null +++ b/conformance/fixtures/ux-modules-windows/src/files.cppm @@ -0,0 +1,27 @@ +module; +#include +#include +#include +export module platform.files; + +export namespace platform { + +class Directory { +public: + explicit Directory(std::wstring path) : path_(std::move(path)) {} + std::vector entryNames() const { + std::vector names; + WIN32_FIND_DATAW found {}; + HANDLE handle = ::FindFirstFileW((path_ + L"\\*").c_str(), &found); + if (handle == INVALID_HANDLE_VALUE) return names; + do names.emplace_back(found.cFileName); while (::FindNextFileW(handle, &found)); + ::FindClose(handle); + return names; + } + const std::wstring& path() const { return path_; } + +private: + std::wstring path_; +}; + +} // namespace platform diff --git a/conformance/fixtures/ux-modules-windows/src/main.cpp b/conformance/fixtures/ux-modules-windows/src/main.cpp new file mode 100644 index 00000000..44bec849 --- /dev/null +++ b/conformance/fixtures/ux-modules-windows/src/main.cpp @@ -0,0 +1,13 @@ +#include +#include +import platform.process; +import platform.files; + +int main() { + platform::Process process; + platform::Directory directory(L"."); + auto names = directory.entryNames(); + ::OutputDebugStringW(directory.path().c_str()); + SetLastError(0); + return process.isCurrent() && !names.empty() ? 0 : 1; +} diff --git a/conformance/fixtures/ux-modules-windows/src/process.cppm b/conformance/fixtures/ux-modules-windows/src/process.cppm new file mode 100644 index 00000000..6a14064e --- /dev/null +++ b/conformance/fixtures/ux-modules-windows/src/process.cppm @@ -0,0 +1,15 @@ +module; +#include +export module platform.process; + +export namespace platform { + +struct Process { + DWORD id = ::GetCurrentProcessId(); + ULONGLONG uptimeMilliseconds() const { return ::GetTickCount64(); } + bool isCurrent() const { return id == ::GetCurrentProcessId(); } +}; + +inline unsigned long currentThreadId() { return ::GetCurrentThreadId(); } + +} // namespace platform diff --git a/conformance/fixtures/ux-xlings/scenario.json b/conformance/fixtures/ux-xlings/scenario.json index 4b9b2ec9..4bc280ba 100644 --- a/conformance/fixtures/ux-xlings/scenario.json +++ b/conformance/fixtures/ux-xlings/scenario.json @@ -356,6 +356,7 @@ "expect": "ux_undeclared_name" }, "budget": { + "firstOpenSeconds": 90, "p95": 1.0, "max": 3.0, "timeouts": 0, @@ -414,6 +415,7 @@ }, "autosave-ms": 1000, "budget": { + "firstOpenSeconds": 90, "p95": 1.0, "max": 3.0, "timeouts": 0, @@ -456,6 +458,7 @@ "text": " int ux_probe_value = 1; ux_probe_" }, "budget": { + "firstOpenSeconds": 90, "p95": 1.1, "importerP95": 1.5, "importerEmpty": 0, diff --git a/conformance/fixtures/workaround-canaries/scenario.json b/conformance/fixtures/workaround-canaries/scenario.json index 42c0ed6a..e4397357 100644 --- a/conformance/fixtures/workaround-canaries/scenario.json +++ b/conformance/fixtures/workaround-canaries/scenario.json @@ -1,6 +1,6 @@ { "name": "workaround-canaries", - "description": "Import-hang plan §9: each registered clangd workaround's defect, run against the payload's clangd. A check here failing means an update of clangd fixed the defect, and the workaround it names can be removed (src/engine/clangd/workarounds.cpp). WA-CLANGD-001 runs clangd --check; WA-CLANGD-009 and 010 drive the clangd over LSP (kind clangd-lsp, 0.0.9 plan M-3), since clangd --check prints no clang-tidy diagnostics and times no completion.", + "description": "Import-hang plan §9: each registered clangd workaround's defect, run against the payload's clangd. A check here failing means an update of clangd fixed the defect, and the workaround it names can be removed (src/engine/clangd/workarounds.cpp). A canary with retired-by holds by proof for an engine whose verified identity declares that capability, as the server retires its workaround there; it still runs against any other clangd. WA-CLANGD-001 runs clangd --check; WA-CLANGD-009 and 010 drive the clangd over LSP (kind clangd-lsp, 0.0.9 plan M-3), since clangd --check prints no clang-tidy diagnostics and times no completion.", "prepare": [ ["{conformance}", "prepare", "heavy-headers", "120"] ], @@ -10,6 +10,7 @@ "checks": [ { "id": "WA-CLANGD-001", + "retired-by": "module-directive-recovery", "kind": "clangd-check", "file": "src/hang.cpp", "expect": "hangs", @@ -32,6 +33,7 @@ }, { "id": "WA-CLANGD-010", + "retired-by": "const-correctness-views", "kind": "clangd-lsp", "only-on": ["linux"], "action": "diagnostics", diff --git a/conformance/traceability.json b/conformance/traceability.json index eb76935c..6fe36ca1 100644 --- a/conformance/traceability.json +++ b/conformance/traceability.json @@ -508,7 +508,7 @@ "S1-11.2-7": [ { "script": "editors/vscode/src/status.ts", - "contains": "status.project.source} · L${tier}" + "contains": "status.project.source} \u00b7 L${tier}" }, { "check": "mcpp-emit/S1" @@ -1416,6 +1416,12 @@ { "script": "modules/pack/src/payload.cpp", "contains": "S4-4-5: libc++" + }, + { + "test": "tests/test_instance.cpp: a payload's kit is taken only when its libc++ is the core engine's version" + }, + { + "test": "tests/test_text.cpp: only a valid maintained-engine suffix selects its LLVM base" } ], "S4-4-6": [ @@ -2162,5 +2168,50 @@ "script": "src/orchestrator/workspace.cpp", "contains": "no numbers are remembered" } + ], + "S4-4-10": [ + { + "test": "tests/test_engineidentity.cpp: an engine identity binds its platform version base source and bytes" + }, + { + "test": "tests/test_engineidentity.cpp: missing or mistyped immutable fields cannot become an engine identity" + }, + { + "script": "modules/pack/tests/test_payload.cpp", + "contains": "maintained engine assembly requires matching immutable identity before replacing output" + }, + { + "script": "src/engine/payload.cpp", + "contains": "decode_engine_identity" + }, + { + "validate": "S4 engine identity example validates" + }, + { + "test": "tests/test_instance.cpp: identified payloads validate their engine while explicit external engines inherit no capabilities" + } + ], + "S4-4-11": [ + { + "test": "tests/test_server.cpp: format fallback requires declared capability and preserves explicit styles" + }, + { + "check": "format-mcpp/F3-golden" + }, + { + "check": "format-mcpp/F5-project-wins" + }, + { + "check": "format-explicit/U3-user-golden" + }, + { + "check": "format-explicit/U5-project-wins" + }, + { + "check": "format-external/E2-no-inherited-preset" + }, + { + "check": "format-external/E3-native-default" + } ] } diff --git a/docs/00-install.md b/docs/00-install.md index b8bb3180..2d8a5518 100644 --- a/docs/00-install.md +++ b/docs/00-install.md @@ -9,7 +9,8 @@ Search the Extensions view for **mcppls** or **C++ Modules Language Server**, or run `code --install-extension sunrisepeak.mcpp-language-server` ([Marketplace page](https://marketplace.visualstudio.com/items?itemName=sunrisepeak.mcpp-language-server)). VS Code picks the build for your platform — `linux-x64`, `linux-arm64`, `darwin-arm64` or `win32-x64`; there is none -for other platforms yet. On Linux, see [which systems each architecture runs on](#supported-linux-systems). +for other platforms yet. `darwin-arm64` needs macOS 12 or later; on Linux, see [which systems each +architecture runs on](#supported-linux-systems). ## Cursor, VSCodium, Windsurf and other VS Code-compatible editors, from Open VSX @@ -52,13 +53,13 @@ clangd the payload carries: | Platform | clangd | Needs | Runs on | |---|---|---|---| -| `linux-x64` | clangd/clangd's 23.1.0 build, with libstdc++ linked in | glibc 2.18 | every current glibc distribution | -| `linux-arm64` | LLVM's own 23.1.0 Linux arm64 build (clangd/clangd publishes none) | glibc 2.34, GCC 12's libstdc++ (`GLIBCXX_3.4.30`), zlib | Ubuntu 22.04 and later, Debian 12 and later, openEuler 24.03 LTS and later (tested); Fedora 36 and later (by its package versions) | +| `linux-x64` | mcppls-clangd 23.1.0, built on Ubuntu 20.04 with libstdc++ and zlib linked in | glibc 2.31 | Ubuntu 20.04, Debian 11, RHEL and Rocky Linux 9, openEuler 22.03 LTS and later | +| `linux-arm64` | the same engine, built the same way for arm64 | glibc 2.31 | the same systems, on arm64 | -On an arm64 system older than that — Ubuntu 20.04, Debian 11, RHEL and Rocky Linux 8 and 9, Amazon -Linux 2023, openEuler 22.03 — the bundled clangd cannot start. mcppls then keeps its own -module-level features (module navigation, import completion, module diagnostics), and its status -says why. Alpine and other musl distributions run neither architecture's clangd. +On an older system — Ubuntu 18.04, Debian 10, RHEL and Rocky Linux 8, Amazon Linux 2 — the bundled +clangd cannot start. mcppls then keeps its own module-level features (module navigation, import +completion, module diagnostics), and its status says why; `mcppls.clangd` can name a clangd that +does run there. Alpine and other musl distributions run neither architecture's clangd. ### Android, under Termux diff --git a/docs/20-projects.md b/docs/20-projects.md index df54be8d..fedcb9d9 100644 --- a/docs/20-projects.md +++ b/docs/20-projects.md @@ -56,6 +56,19 @@ A few things are worth knowing: `target/` when a build has written them, and otherwise says which are missing, with **Build in Terminal**; once a build writes them, the files that include them get their semantics without a restart. +- **`build.mcpp` and the libraries it imports.** From mcpp 2026.10.11.1 the build database also + describes the build programs: `build.mcpp`, the libraries of `[build-dependencies]` and mcpp's + engine interface (`import mcpp;`), in sets of their own configuration (`:build`, + `:host`, `mcpp:core`). `build.mcpp` is read as C++ with the arguments mcpp compiles it + with, so navigation, hover, completion and diagnostics reach its libraries and the engine + interface. A package in both `[dependencies]` and `[build-dependencies]` is read as the targets + build it; the context `:build` (**mcppls: Select Context**) reads the build programs as + mcpp compiles them, and is where they are read when they use a toolchain of their own, as in a + cross build. An import across the two — a target importing `mcpp` or a library of + `[build-dependencies]`, `build.mcpp` importing a module of the targets — is an error, as it is for + mcpp. The engine interface under `/engine//modules` belongs to mcpp and is + read-only: no formatting, code action or rename edits it, and VS Code opens it read-only. With an + older mcpp, `build.mcpp` is not read, and a note in the file names the mcpp that describes it. - **An older mcpp** without `emit build-database` is not the end of it: if a newer mcpp is installed elsewhere on the machine (the xlings package store, mcpp's own registry store), mcppls asks *that* one instead, read-only and offline the same way, only to describe the project — the project still diff --git a/docs/30-settings.md b/docs/30-settings.md index d1944bb6..567b786c 100644 --- a/docs/30-settings.md +++ b/docs/30-settings.md @@ -56,7 +56,7 @@ either wrapped in a top-level `mcppls` object or not. | `mcppls.compiler` | a string | *(empty)* | `--compiler` | reload | Use this compiler for module semantics instead of what was detected: an absolute path, a name on `PATH`, or `kit` to force the bundled semantic kit. Empty means discovered automatically. | | `mcppls.semanticKit` | `auto`, `off` | `auto` | `--semantic-kit` | reload | Whether the bundled standard library kit may be used at all: `auto`, when no compiler is found; `off`, never (without a compiler, only module-level features remain). | | `mcppls.requestTimeout` | a non-negative number of seconds | `60` | `--request-timeout` | restart | How long an engine request may take before it is answered without the engine. A request a person waits for (hover, definition, completion and the like) waits at most 30s in all, including while clangd starts or prepares its modules, and is then answered by mcppls's own engine. | -| `MCPPLS_ENGINE_ARGUMENTS` | a string | *(empty)* | — | restart | Extra arguments appended to clangd's own command line, for troubleshooting (e.g. `-j=8 --background-index-priority=background`). | +| `MCPPLS_ENGINE_ARGUMENTS` | a string | *(empty)* | — | restart | Extra arguments appended to clangd's own command line, for troubleshooting (e.g. `-j=8 --background-index-priority=normal`). An explicit background-index priority overrides mcppls's default `background` on macOS. | ### Editor experience @@ -65,6 +65,7 @@ either wrapped in a top-level `mcppls` object or not. | `mcppls.semanticTokens.modules` | `true`, `false` | `true` | — | restart | Color `import`, `module`, `export` and module names from the server's semantic tokens. Off: only the grammar's colors. | | `mcppls.semanticTokens.moduleType` | `true`, `false` | `false` | — | restart | A client declares it knows the custom `module` semantic token type and the `partition` modifier; off for every client but this one, since none else advertises it. Not a package.json setting: VS Code's own extension always declares it, fixed, because it contributes that token type itself. | | `mcppls.completion.triggerOnSpace` | `true`, `false` | `true` | — | restart | Show the module list as soon as a space is typed after `import` or `export import`. A space anywhere else never reaches the server. A client that says nothing gets this only when it identifies itself as VS Code or a fork of it; every other client opts in with `initializationOptions.completion.triggerOnSpace: true`. | +| `mcppls.format.fallbackStyle` | a string | `auto` | `--format-fallback-style` | restart | Formatting fallback when no project .clang-format exists. auto selects the pinned mcpp style for an mcpp project when the bundled engine supports it; otherwise clangd's default. A named style overrides auto; mcpp opts other projects in and requires engine support. Project .clang-format always wins. | | `mcppls.index.primeImplementationUnits` | `auto`, `off` | `auto` | `--prime-implementation-units` | restart | Build a module's implementation units in clangd in the background, a few at a time, so go-to-definition reaches a definition that only an implementation unit has, before that file was ever opened. clangd's own background index cannot see a module unit's imports (WA-CLANGD-008). `off`: only the units a definition request searches, and the files you open, are indexed for this. | | `mcppls.enable` | `true`, `false` | `true` | — | immediately | Start mcppls for this workspace. `false` in a workspace's settings keeps the extension installed but inactive there -- for a project it cannot serve yet -- without uninstalling it; the status bar item turns it back on. | | `mcppls.detectConflicts` | `true`, `false` | `true` | — | immediately | Offer once to turn off another C++ extension's language features in this workspace, and say so when one becomes active later. VS Code only: no other client arbitrates between language servers. | diff --git a/docs/50-troubleshooting.md b/docs/50-troubleshooting.md index a7f697cd..871dfd3f 100644 --- a/docs/50-troubleshooting.md +++ b/docs/50-troubleshooting.md @@ -126,6 +126,10 @@ project does not have (yet) — the file is answered by mcppls's own engine unti the status lists it as `file-unsafe-on-disk`, category `code`, with the reason, and stays *ready*. A module nothing provides gets a stand-in within a second of the save, and the file goes back to clangd once clangd has read the database with it, about six seconds later. +With the bundled mcppls-clangd (0.0.12) neither happens: it finishes `import hello.` at once and +reports an import of a module the project does not have, so the file stays with clangd, and only a +module unit's own such import gets a stand-in, once the unit has not been edited for a few seconds +(`WA-CLANGD-001` and `WA-CLANGD-013` retire for an engine that declares the fix). **"Import directive must end with a ';'" on the wrong line, or "module X not found" for an import you just typed.** clangd reports a directive missing its `;` on the code after it; mcppls moves the diff --git a/docs/90-architecture.md b/docs/90-architecture.md index 2c04f8cf..ac30568a 100644 --- a/docs/90-architecture.md +++ b/docs/90-architecture.md @@ -33,7 +33,12 @@ editor / coding agent / CI a time, and only after 10 s without typing, opening a file or a request; a restart clangd needs for a changed build description waits until typing has paused for 3 s (at most 60 s). A crash or a clangd that stopped answering restarts at once. Module preparation takes every worker but one when - an opened file waits on it, half of them otherwise. + an opened file waits on it, half of them otherwise. On macOS, clangd's background index uses its + `background` priority (Background QoS instead of the engine's default Utility QoS) unless + `MCPPLS_ENGINE_ARGUMENTS` explicitly selects another; on Linux both priorities are `SCHED_IDLE`, + and on Windows clangd's own default stays, since background mode also lowers I/O priority there. + The full index remains enabled. This gives interactive cold module builds precedence; + it does not guarantee a particular response time. - **What cannot be recovered is written down at once.** When the server cannot recover by itself it writes a redacted diagnostic bundle (`/bundles/auto--