Architecture Decision Rulings — R44
Architecture Decision Rulings — R44
Date: 2026-08-13 · Produces: ADR-178 · Findings:
F-R44-01…F-R44-08The brief called this round “R42 Phase 1c” and that label is taken twice over.
Architecture_Decision_Rulings_R42.mddefines R42 Phase 1 as the Actions-budget work, and R43 was filed one day earlier for the same collision. Filed as R44; theRsequence is a filing convention rather than a contiguous range, whichdocs/README.mdrecords about the absentR10and R42’s header aboutR41. The earlier records are untouched (F-R44-06).The brief’s ADR number is not the one used. It proposed numbers allocated before R42 Phase 2 and R43 landed.
adr_link_lint.pyreports 175 rows numbered to 177, so this round takes ADR-178.The brief opens by saying the docs platform is in better shape than the rest of the ecosystem, and that is true. Nothing built by ADR-112, ADR-113, ADR-114 or ADR-115 is re-litigated here. What this round does is give the platform’s comparative advantage an enforcement point — it is the one component that reads every published file — and then pay the first instalment of what that enforcement finds.
0. Findings
| Finding | Evidence | |
|---|---|---|
F-R44-01 | A closed spike is still named as a blocker in two places, and the corpus contains its own refutation. docs/README.md’s outstanding list reads “6 spikes (S1, S2, S4, S5, S6, S7)” and Quantity_Registry.md marks Q-026 as ⊙ Estimated (awaiting S6). S6 was closed by ADR-146 in R36, and docs/README.md says so 117 lines above the list that contradicts it | The R36 row in that same file (“Spike S6 is closed”), whitepaper §11’s ADR-146 row (“Spike S6 is CLOSED”, “closes Spike S6”), and whitepaper L919 |
F-R44-02 | The release checklist does not exist. ADR-045 clause 2 names “a named release-checklist item” as one of four legitimate enforcement points, and thirty sentences across this corpus name it. There is no such file, no such heading, and no such artefact anywhere in the repository | grep -ric "release checklist" docs/ .claude-rules/ = 30; find . -iname "*checklist*" = nothing; grep -rn "^#.*[Cc]hecklist" = nothing |
F-R44-03 | A version pin’s re-verification procedure is a broken link. Directory.Packages.props says “Re-run the probe before bumping either. tools/build/probe-photino-aot.md records how”. That file has never existed; tools/build/ contains only Production.props | find . -iname "*photino*" matches nothing outside the props file itself |
F-R44-04 | F-R43-05 was fixed in two of its three copies. R43 corrected the .github/supply-chain/BASELINE.md pointer in osv-ledger.json and in osv-ledger-gate.mjs, one day before this round. SECURITY.md line 137 still sent a reader to the same non-existent file | The three files, read together — which is the only way this is visible |
F-R44-05 | The Full.slnx test suite cannot be run to completion on a Windows workstation, and nothing reports the shortfall. Descent.Sandbox.Tests passes 115 tests and its host process then exits 0xC0000409 (STATUS_STACK_BUFFER_OVERRUN). The suite carries 327 [Fact]/[Theory] attributes and was last counted at 562, so roughly four hundred tests never ran — and the run reports “115 passed, 0 failed” for that assembly | dotnet test DescentVTT.Full.slnx -c Debug: 1 093 total, of which the Sandbox contributes 115; the same suite alone gives 結束代碼: -1073740791 with 失敗: 0 |
F-R44-06 | The round label collides for the second consecutive round. The brief’s “R42 Phase 1c” follows R43’s “R42 Phase 1” | Architecture_Decision_Rulings_R42.md’s header, and R43’s F-R43-01 |
F-R44-08 | The gate this round built was machine-dependent, in two places, and both were found by running it somewhere else. cited-paths derived its anchor set with readdirSync and resolved a cited path with existsSync, so a workstation’s untracked files changed the verdict: .claude/ exists at home and not on a runner, and the primary checkout carries a git-ignored core/Descent.RngKit/ that ADR-162’s deletion left behind. One ledger line was correct in CI and STALE at home; two others were the reverse | The gate’s first CI run (docs-lint red on two STALE LEDGER LINE reports), then node tools/docs-corpus-invariants.mjs in C:\Repos\DescentVTT after the merge sync. Fixed in a follow-up branch — §5a carries the argument |
F-R44-07 | boa-metering.test.ts’s skip guard does not guard, and frontend-ci.yml asserts in a comment that it does. That workflow’s Refuse a silent skip of the S7 corpus step explains itself with “written to SKIP when their fixtures are absent, so a developer without a Rust toolchain still gets a green pnpm test”. It does not skip: describeIfBuilt resolves to describe.skip, and Vitest still evaluates the callback body to collect the suite, where load(METERED) calls readFileSync and throws ENOENT. A developer without the fixtures gets a hard file-level failure, not a skip | pnpm exec vitest run src/plugins/boa-metering.test.ts in a tree with no src/plugins/generated/gas/: Error: ENOENT … descent_wasm_core.gas.wasm at boa-metering.test.ts:80. FIXED 2026-08-13, after R44 merged — see §5b. gas-instrumentation.test.ts was checked for the same shape and did not have it: it loads inside it bodies, so its guard always worked |
F-R44-05is the one that should worry a reader most, and it is the reason this round did not update the test count. A test host that dies mid-assembly and still reports its partial run as a clean pass is theteedefect with a different mechanism: the number looks measured and is not. Writing 1 093 intodocs/README.mdwould have been a simulated measurement (P7), so that paragraph carries the date, the attempt and the reason instead. What closes this is a CI run, where the suite is measured on Linux and where a non-zero exit is not swallowed; nobody has read that number off a greenci.ymlrun either, and this round did not do so.
1. What was asked, and what was actually possible
The brief has six items. One of them cannot be done from here at all, and saying so first is the honest ordering.
| Item | Outcome |
|---|---|
| 1 — provision the deployment and watch the smoke assertion run | NOT DONE. Blocked, and blocked on credentials rather than on effort. See §2 |
| 2 — bring the deployment into the infrastructure discipline | Done, as RC-D-02 — an argued §10.1.1 exception with an expiry |
| 3 — make the platform enforce cross-document drift | Done, and it is the round’s substance. ADR-178 |
| 4 — confirm the search index does not leak past the boundary | Done as far as it can be without a deployment: the assertion is written and covers the index; it has never run |
| 5 — currency and hygiene | Done, including one dependency removed on a measurement |
| 6 — document the shifts | Done — this file, ADR-178, and the four documents §6 lists |
2. Item 1 is blocked, and the block is not one this round may work around
Creating the Cloudflare Pages project and the Access application is an outward-facing act requiring credentials this repository does not hold and this agent has no way to obtain. The brief’s own stop-rule covers exactly this case: “a check needs a secret, a permission or an outward-facing act you do not have → report it; do not work around it.” The brief also requires owner confirmation before the first deploy, which is a second, independent gate.
Nothing was faked and nothing was half-done. DOCS_DEPLOY_ENABLED is untouched, so the
deploy job remains inert and main cannot go red for want of provisioning — which is the
failure mode ADR-114 clause 5 chose the variable to prevent.
What this round did instead is make the act repeatable and the assertion stronger, so the
owner’s four steps are a checklist rather than a reconstruction: RC-D-01 in
docs/Release_Checklist.md. It also carries the brief’s own instruction to prove the gate can
fail: tools/docs-access-smoke.mjs --expect-open, pointed once at an unprotected preview.
The audience is untouched. ADR-113 clause 6 stays armed for every audience wider than
repository collaborators, R21 clause 3 remains the gate chain, and site being set in
astro.config.mjs is a declaration of target rather than a decision that the corpus is public.
This round widened nothing.
3. ADR-178 — The docs platform as a cross-document invariant gate
Context
The five lints under tools/docs-lint/ read the whitepaper. doc_reference_lint.py is the
exception and resolves references inside docs/. Between them they cover a great deal and
they share one blind spot: they each read one file at a time.
The corpus’s most-recorded defect class is two documents that agreed when written and silently
diverged. W6 claimed the whitepaper was unmodified for three months after it had been fully
revised. The record-location table stopped at 108, then at 124, then failed to index R38 for a
day. The ADR row count has been wrong ten times in five days across three copies. 133 is cited
by seven merged source files and has no §11 row — found by hand arithmetic, because no checker
looks at code. Each of those is invisible to a single-file lint, because neither document is
wrong on its own.
The platform is the one component that reads them all. tools/adr-index.mjs already proves the
pattern: a framework-agnostic parser that a build step consumes.
Decision
1. A sixth lint, tools/docs-corpus-invariants.mjs, checks six cross-document invariants.
Each is a drift this corpus has recorded catching by hand, and each is listed in the tool’s own
header with the incident that motivates it:
| Check | The invariant | The incident |
|---|---|---|
record-table | The record-location table and docs/decisions/Architecture_Decision_Rulings_R*.md are the same set, both directions, and every row names a file that exists | Stopped at 108, then at 124; R38 unindexed for a day |
adr-count | Every current-tense statement of the ADR row count equals §11’s | Wrong ten times in five days; four sites in one file |
adr-citations | Every ADR-NNN cited anywhere in the repository has a §11 row | 133, cited by seven source files |
dated-claim | docs/README.md’s “On code” paragraph carries a date no older than the newest decision record | That paragraph has reported its own drift four times |
closed-spikes | A spike the corpus records as closed appears in no outstanding list, and no Q-ID names it as a blocker | F-R44-01 |
cited-paths | A backticked repository path cited from a .props, .csproj, .targets or a .md outside docs/ resolves | F-R44-03, F-R44-04 |
Enforcement point: .github/workflows/docs-lint.yml, step Cross-document invariant gate
(#6), which fails the job on any unreconciled finding.
2. It is a ratchet with a two-sided ledger, not a wall. docs-corpus-invariants.ledger.txt
declares the live backlog with a reason per row, refused at parse time if absent. An
undeclared finding fails the build; a declared line that no longer fires also fails it,
which forces the ledger to be pruned in the change that earns it. That is the shape
enforcement_baseline.txt and uncited_ceiling.txt already use, for the reason both records
give: a checker that only catches growth records a debt nobody can watch being paid off. A hard
gate against an unknown backlog produces a permanently red build, and a CI that is always red is
no CI at all.
Baseline on first run: 44 findings. Seventeen were fixed in the same change; thirteen ledger
lines carry the rest, of which two are live defects another brief owns (F-R44-01) and the
remainder are deliberate absences in the doc_reference_allowlist.txt sense — a deleted engine
named in its own deletion record, a directory the desktop app creates at runtime, a fuzzing
corpus .gitignore deliberately excludes.
Enforcement point: the parse-time refusal in parseLedger, and reconcile’s stale half,
both pinned by cases in the suite.
3. It runs in docs-lint.yml, and this OVERRIDES the brief’s placement. The brief and
ADR-112 both point at docs-platform-ci.yml. That workflow is path-filtered for Actions-budget
reasons and does not fire on a change to a .cs file — which is exactly the change that
produced 133. A gate placed where the triggering change cannot reach it is the tee defect in
a different costume, and this repository has already paid for that once. docs-lint.yml has no
path filter.
ADR-112’s rule is not weakened by this, and the distinction is the whole argument: ADR-112
governs where the logic lives — a framework-agnostic module under tools/, which this is —
not which workflow invokes it. Retiring Astro would change nothing about this checker, which is
the property ADR-112’s exit-cost clause was written to preserve.
Enforcement point: the workflow step, and the tool’s main() being reachable as a CLI with
no Astro import anywhere in its module graph.
4. Every check refuses an empty input, and --self-check asserts that in CI. A scan over an
empty set approves everything. Eight guards refuse: no rulings files, no matched count claim, no
citations, a missing “On code” anchor, no dated decision record, no recorded spike closure, no
path claims, and a ledger line without a reason.
Enforcement point: the vacuity self-check step in docs-lint.yml, which runs before the
gate on the same argument the Python self-tests are ordered first.
5. Stated rather than implied: the mutation suite runs in a different workflow from the gate.
tools/docs-corpus-invariants.test.mjs runs under the frontend Vitest with every other tools/
check, so frontend-ci.yml owns it while docs-lint.yml owns the gate. That is weaker than
the Python arrangement, where the self-tests are the first step of the same job. Clause 4
closes the dangerous half; it does not close all of it, and pulling a pnpm install into
docs-lint.yml to collect one file costs more than the coupling is worth. Recorded as a known
weakness rather than left for a reader to notice.
Enforcement point: none beyond clause 4 — this clause is description, not a requirement, which is ADR-045’s own instruction for a rule that cannot name one.
6. The access-boundary smoke assertion probes every class of thing the site serves. ADR-114
clause 5 shipped a curl against one corpus page. Pagefind builds a static index at build
time over what the build rendered, so the index carries the prose of every published page.
An index is content. A boundary proved on /vtt/…/ and not on /pagefind/… is proved on a
neighbour — the argument the route check’s own header already makes about dist/.
tools/docs-access-smoke.mjs requires an authentication challenge from seven URLs: a corpus
page, the Pagefind entry and its loader, a scrubbed wire-schema page, a scrubbed C# SDK page, an
asset published beside its page, and the sitemap. A 404 and a network error are failures, not
passes — an assertion that treats an unexpected answer as probably-fine is one that passes
when the site is broken. redirect: 'manual' is load-bearing and is pinned by a case: fetch
follows a 302 by default and would report the identity provider’s own 200 as an open door.
Verified against the built dist/ rather than assumed: dist/pagefind/pagefind-entry.json
exists, and the twelve mockup images sit beside their page as files.
Enforcement point: the smoke step in docs-platform-ci.yml’s deploy job — which has never
run, so tools/docs-access-smoke.test.mjs is the only present evidence that it can fail, and
--expect-open against an unprotected preview (RC-D-01) is what converts that into evidence.
7. What is deliberately NOT enforced, and why. The brief empowered this round to conclude a check is not worth its false-positive rate provided it says which.
- A release-checklist coverage check is refused. Thirty sentences name the checklist in
varied prose across a dozen files; matching them is a phrasing-recognition problem with a high
false-positive rate, and the useful check — is each named obligation represented? — cannot be
written until the obligations are transcribed, which is a round’s work (
F-R44-02). cited-pathsdoes not resolve a path relative to something the citing text does not name. A baresrc/network/in.claude-rules/frontend-guidelines.mdmeans “inside the app under discussion”. Measured: guessing produced a 47% false-positive rate; anchoring at a real top-level entry and resolving against the root or any enclosing directory produced 14%, and every one of those was a genuine finding or a deliberate absence.closed-spikesrecognises one phrasing. A spike answered by a decision that never says so is invisible. S7 is the live example — ADR-165 answers the question S7 asked, and no sentence in the corpus records it as closed, so this round does not assert that it is (P9). Whoever owns S7 closes it or does not; inventing the closure to make a list tidy is the fabrication the house style forbids.- Nothing here reads a rendered page. The checker reads sources, so it is as blind to a rendering defect as the Python lints are.
Alternatives considered
- A sixth Python lint under
tools/docs-lint/. Rejected:tools/adr-index.mjsalready parses §11 and is the consumer the docs platform uses. A second §11 parser in another language is two definitions that agree today and diverge later — the_registry.pyargument, which this corpus already made once and acted on. - A build step inside
astro build. Rejected on clause 3’s reach argument, and on ADR-112’s own exit-cost rule: a check that only exists as an Astro hook is a check that leaves with Astro. - A hard gate with no ledger. Rejected: 44 findings on the first run, of which some are permanent by construction. A permanently red build is a build nobody reads.
- Fixing
F-R44-01here. Rejected: the plugin-tier performance brief ownsQ-026’s disposition, and re-columning a quantity is that brief’s call. Declared in the ledger instead, where the two-sided rule guarantees the lines must be deleted when the fix lands.
Consequences (including negative)
docs/README.md’s ADR count is now load-bearing in a way it was not. One live copy remains, in the authority table; two restatements were deleted rather than corrected, because a figure the lint prints on every run does not need three homes (P6). A round that adds an ADR and does not update that one cell now goes red.- The ledger is a new file that must be pruned. A ledger nobody prunes becomes a suppression file. The stale half is what forces it, and the reason-per-row rule is what makes pruning possible for someone who was not here.
- The
adr-citationscheck has repository-wide reach and therefore repository-wide cost. It reads 6 700+ citations across every text file on every pull request. Measured at well under a second; it is a full-tree read and that is worth knowing before adding to it. - A deliberate-absence ledger line covers a whole class.
cited-paths | core/Descent.RngKitis one line for eight citations, matchingdoc_reference_allowlist.txt’s per-name shape. It stops firing only when the last citation goes, so it hides the ninth disappearing. Taken because the alternative is eight identical reasons.
Links: Depends-on 112 (the portability rule this obeys and the exit-cost argument for
being a CLI first); Depends-on 045 (the enforcement-point criterion every clause above is
written against, and whose fourth option F-R44-02 shows has never existed); Amends 114
(clause 5’s smoke assertion is widened from one URL to seven, and the Pagefind index is brought
inside it); interacts with 113, 115, 106; introduces no Q-ID.
4. The seventeen fixes, and what they say about the gate
The check found 44 things on its first run. Seventeen were fixed in the same change, and they are worth listing by class rather than by file, because the classes are the argument for the gate existing.
| Class | Instances | Example |
|---|---|---|
| A deleted artefact still described in the present tense | 8 | csharp-guidelines.md §10: “core/Descent.RngKit and core/Descent.Sandbox are proprietary engines”, two days after ADR-162 deleted the first |
| An argument reachable only through a deleted path | 1 | The Sandbox package hub pointed at RngKit’s hub “and that file carries the full argument”. Restated in place |
| A procedure behind a link that never existed | 1 | F-R44-03 |
| A fix applied to some copies and not all | 1 | F-R44-04 |
| A path that never followed a directory move | 2 | The root README still sent readers to docs/Quantity_Registry.md, seven days after the restructure put it under docs/vtt/ |
| A citation relative to an unnamed base | 2 | tests/parity/geometry_parity.json, which is under core/Descent.Geometry/ |
| A stale count | 1 fixed, 2 deleted | “§11 indexes all 123 ADRs” against 175 |
| A dated claim gone stale | 1 | The “On code” paragraph, discharged with a date and F-R44-05 rather than with a number |
Every one of these was invisible to all five existing lints, and eleven of them are outside
docs/ entirely, where doc_reference_lint.py structurally cannot look.
5. The mutation sweep, and the guard it found unreachable
Twenty-five mutations against the checker, run after the suite went green. Twenty-four were killed on the first pass. The survivor is a defect in the code rather than in the suite, which is the opposite of the usual verdict and is why it is recorded here.
isRepositoryPathClaim carried an explicit ^\w+:// test to refuse a URL. Removing it changed
nothing, because a URL is refused twice over by later guards: its scheme carries a colon,
which the character class does not admit, and its scheme is not a top-level directory of the
repository, which the anchor check requires. Three guards, one property, and no single-guard
mutation can kill the assertion — so a case named “refuses a URL” was proving less than it
looked like it proved.
R39’s sweep recorded the mirror image: five mutations became unreachable code and were rejected by the compiler, proving nothing about the suite. The trap is the same in both directions — a guard nothing can reach makes a green suite mean less than it appears to.
The redundant guard is deleted rather than kept as defence in depth, and one case is added for the guard that had none of its own: a path under docs/vtt/ carrying a colon is anchored at a real directory, so only the character class can refuse it. With that in place the sweep is 25 of 25.
tools/docs-access-smoke.test.mjs was not swept, and that is stated rather than glossed: it is
fourteen cases against a checker that has never run, written failure-path-first for that reason.
5a. The gate was machine-dependent, twice, and both were found by running it
(Added 2026-08-13, after ADR-178 merged. F-R44-08.)
The checker asked the filesystem two questions it should have asked git, and the answers differ per machine. Both defects have the same shape and the same consequence: the gate returned a different verdict on a workstation than on a runner, which makes a green local run no evidence about CI — the one property a gate cannot have.
The first was the anchor set, and CI found it. cited-paths decided what counted as a
repository path with readdirSync(root). A developer’s tree carries .claude/ because the
desktop app creates worktrees there; a checkout does not. So .claude/rules/ and
.claude/worktrees/ were path claims at home and not path claims on the runner, and the first
CI run of the gate reported both ledger lines STALE. Fixed by declaring
TOP_LEVEL_ENTRIES — the allowlist-never-a-glob shape the publication manifest already uses —
with two cases holding it against git ls-tree.
The second was resolution, and syncing the primary checkout found it. With the anchors
fixed, the gate still resolved a cited path with existsSync. C:\Repos\DescentVTT carries a
git-ignored core/Descent.RngKit/, left behind when ADR-162 deleted that engine — so eight
citations resolved there, dangled in CI, and the ledger line was correct on the runner and
STALE at home. This is the mirror image of the first defect and it was invisible until the
tool ran somewhere other than the worktree that wrote it.
The fix is a principle rather than a patch: the corpus is what is committed. The file list
and the resolution set both come from git ls-files, so a build artefact, a TestResults/
tree and a sibling worktree are not part of the repository as far as any check is concerned.
readableFiles was split out of trackedFiles for a reason the sweep supplied — its
empty-list refusal survived a mutation while it was welded to a git call nothing could make
return nothing, which is R39’s unreachable-guard trap in a third costume.
Verified rather than argued: the gate now reports the same 25 findings and 13 declared lines in three places — this worktree, the primary checkout with its ignored leftovers, and a tracked-files-only export standing in for CI. The follow-up sweep is 6 of 6.
What this says about the round’s own claim. ADR-178 is a check against documents that
disagree between contexts, and its first two defects were the checker disagreeing between
machines. That is not irony worth enjoying; it is the same failure class, and it is recorded
here because the next person to write a repository-wide checker will reach for existsSync
too.
5b. F-R44-07 closed, and a second false claim found beside it
(Added 2026-08-13, after ADR-178 merged.)
The skip guard did not guard. describe.skip marks a collected suite — Vitest still
evaluates the callback body in order to collect it — and boa-metering.test.ts opened each block
with const metered = load(METERED). On a machine without the fixtures that threw ENOENT
during collection and the file failed. BUILT computed the right answer and nothing consumed it
in time. The reads are now memoised behind fixture() and happen inside the it bodies, where a
skipped test never reaches them.
gas-instrumentation.test.ts was checked for the same shape and does not have it. It loads
inside its it bodies and always skipped correctly. It is changed only to share the fixture-root
indirection, and its own correctness is now pinned rather than assumed — “the one that was
correct stays correct” is half of what a regression test is for.
A second claim in the same CI comment was also false, and this one was silent rather than
loud. The step’s rationale read “a skip prints a warning and leaves the job green”. It did
not print anything: Vitest attributes a console call to the test that made it, so a
module-scope console.warn in a file whose every test is skipped goes nowhere. Probed
2026-08-13 — a direct process.stderr.write appears, the console.warn does not — and both
suites now use stderr. Two documents agreeing with each other and both wrong about the code is
the class ADR-178 exists for; neither copy was checkable, which is why writing the check came
first this time.
The enforcement point, and why it needs a child process
The reason nobody caught either claim is structural: CI builds the fixtures before running the
suites, so the runner never exercises the case the sentences are about. A gate that cannot
reach the failing condition is the tee defect in another costume, which this round has now met
three times.
src/plugins/fixture-skip-guard.test.ts makes the case reachable. fixture-root.ts adds one
seam — an environment override for the fixture directory, read by test files only and by no
shipped module — and the guard spawns a child vitest with it pointed at an empty temporary
directory. It asserts the child exits 0, that both suites report as skipped rather than
passing on zero assertions, and that each suite’s notice reached a terminal.
Spawning a process to assert an exit code is tools/supply-chain/nuget-vulnerability-gate.test.mjs’s
precedent, adopted for its reason: the exit code is the entire product, and a checker that is
right about a gate that never turns red proves nothing.
Sweep: 6 of 6, including the original defect reintroduced verbatim and the same defect injected into the suite that never had it. Two of the six are worth recording because they were mistakes in the test, found by the sweep rather than by review:
- The notices assertion first matched only
build-gas-fixtures.mjs, which both notices contain — so reverting one suite to the swallowedconsole.warnleft it green. It is the “satisfied by an unrelated neighbour” trap thecited-pathssweep hit in §5, twice in one round. Each notice is now pinned by a string only it carries. - The child was first run with
execFileSync, which returns stdout only, while both notices and Vitest’s summary go to stderr. Capturing one stream and asserting about the other is the same shape as the defect being fixed.spawnSynccaptures both.
Verified in both states rather than one: fixtures absent → 2 files skipped, 18 tests skipped, exit 0; fixtures built locally → 2 files passed, 18 tests passed. Full frontend suite 968 green, lint and typecheck clean.
6. What this round did not do
- Item 1 in full. No Cloudflare Pages project, no Access application, no repository
variables, no deploy, and therefore the smoke assertion has still never executed. §2 is the
argument;
RC-D-01is the handover. F-R44-01is not fixed, deliberately. The plugin-tier performance brief ownsQ-026.- Twenty-nine of the thirty release-checklist obligations are not transcribed, so those rules
remain unenforced.
docs/Release_Checklist.mdsays so in its own header rather than letting its existence imply otherwise. - The test count was not re-measured, because it cannot be here (
F-R44-05). Nobody has read it off a green CI run either. - S7’s status is not asserted. No sentence in this corpus records it as closed and this round did not write one.
Directory.Packages.props’s “plugins/ the game cartridges” line is untouched although ADR-162 made it false — the check did not find it (it is not a backticked path) and fixing it in passing is whatP1forbids. It is a real stale claim and is recorded here rather than swept.— fixed 2026-08-13 in a follow-up, and §5b carries it. The entry stood for a few hours and read that changing the skip guard was ADR-165’s tier’s call. That was the wrong division: the defect is not in what the suite asserts — which is ADR-165’s evidence and is untouched — but in when it reads its fixtures, which is nobody’s decision and simply a bug. Fixing it also turned up a second false claim in the same CI comment, and gave both an enforcement point they had never had.F-R44-07is not fixed.- Nothing was done about the two
Descent.IntegrationTestsfailures seen locally (LiveTypeScriptClientTestsassertingnode_modulesexists under the frontend client). They are the environment, not the tree, and are named here so a later reader does not rediscover them as new.