Skip to content

Commit 76a15fc

Browse files
committed
docs: hand off after closing CCF-014 and CCF-016
Records the batch that closed two cross-cutting causes -- CCF-014 via #1871 (docs/TryOutputFailureContractPlan.md) and #1872, CCF-016 via #1873 (docs/DerivedExceptionHResultPlan.md) and #1874 -- in NEXT.md and plan.md. Baselines verified this batch: - full component gate 14,476 tests across 37 executables, no failures (+32 over the 14,444 floor); - audit 56 remediated, 307 confirmed, of 364 (seven findings moved confirmed -> remediated); CCF-014 and CCF-016 both CLOSED; - module graph 41 modules / 91 edges, negative fixtures 9 / 66, version seams 2 / 18, canonical Doxygen 1,941 of the 1,942 ceiling -- all unchanged; - validate_module_boundaries.py and its unit test, generate_component_catalog.py --check, db_consistency_check.py, both seam checks, both negative-fixture checks, git diff --check, check_selective_components.sh and local_ci_check.sh build all pass. Also corrects #1872's test-count figure. Its commit message says +13 (SequenceReader 7, Utf8Parser 6); the measured delta is +14 -- Utf8ParserTests gained 7, not 6. The commit is not amended, per this repository's practice of never rewriting history; the corrected figure stands in the ticket notes, the audit records and NEXT.md, and the arithmetic reconciles: 14,444 + 14 + 18 = 14,476. Nine premise corrections are recorded across the two families with the historical audit text preserved, including two that changed what was implemented: the Utf8Parser FormatException path was left writing neither output because .NET does the same deliberately, and SR-AUD-100's default-message claim was confirmed a false positive, so no message change was made and a test now pins the reference text verbatim. New ticket #1875 is open and inactive for the measured 45-type HResult population outside modules/core/include/System. It carries its evidence, issues no SR-AUD identifier, and says explicitly that none of the 45 is a confirmed defect until checked against its own reference. No ticket is left doing. #1773 stays blocked and #1854/#1858/#1862/#1863/#1865 stay needs_user with their docs/FloatingValueFidelityPlan.md section 19 decision records unchanged. Nothing was pushed, merged, rebased or tagged; CNA and mobile-eggbert were not inspected or modified; no compilation exceeded three aggregate jobs.
1 parent c5fe1c1 commit 76a15fc

4 files changed

Lines changed: 285 additions & 12 deletions

File tree

‎NEXT.md‎

Lines changed: 211 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,19 @@
33

44
# NEXT.md
55

6-
*Last verified: 2026-07-30. Branch: `feature/remediation-batch-empty-callable`
7-
(previously `feature/remediation-batch-floating-fidelity`). The test floor is
8-
now **14,444** (was 14,396): the **CCF-011 empty-callable batch closed the whole
9-
family** — design ticket #1866 (`docs/EmptyCallableBoundaryPlan.md`) plus four
6+
*Last verified: 2026-07-30. Branch: `feature/remediation-batch-ccf014-ccf016`
7+
(previously `feature/remediation-batch-empty-callable`). The test floor is now
8+
**14,476** (was 14,444): this batch **closed two whole families** — CCF-014 via
9+
design ticket #1871 (`docs/TryOutputFailureContractPlan.md`) and implementation
10+
#1872 (SR-AUD-075 `SequenceReader` + SR-AUD-085 `Utf8Parser`, +14), and CCF-016
11+
via design ticket #1873 (`docs/DerivedExceptionHResultPlan.md`) and
12+
implementation #1874 (SR-AUD-093/094/095/096/100, eleven exception types, 40
13+
constructors, +18) — total +32. Post-audit tally: **56 remediated, 307
14+
confirmed, of 364**. **CCF-014 and CCF-016 are both CLOSED.** New this batch:
15+
**#1875**, opened **inactive** for the measured 45-type HResult population
16+
outside `modules/core/include/System/` (no `SR-AUD-*` identifier). The previous
17+
batch left the floor at 14,444 / 49-remediated: the **CCF-011 empty-callable
18+
batch closed that whole family** — design ticket #1866 (`docs/EmptyCallableBoundaryPlan.md`) plus four
1019
implementations, #1867 (SR-AUD-065 `Lazy<T>` + SR-AUD-099
1120
`AggregateException::Handle`, +14), #1868 (SR-AUD-058 `Progress<T>` +
1221
SR-AUD-121 `EventHandler`, +13), #1869 (SR-AUD-052 `Array`, +13) and #1870
@@ -23,10 +32,10 @@ IsPow2, +2). **New ticket this batch:** #1865 (SR-AUD-033 parse thousands +
2332
overflow-to-Infinity tail, `needs_user`, split from #1864 like #1857→#1858).
2433
Still `needs_user`: #1858 (Decimal comma + overflow taxonomy), #1862 (SR-AUD-029
2534
Round `noexcept`), #1863 (SR-AUD-033 format output), #1854 (SR-AUD-043b noexcept);
26-
#1773 stays blocked, and **no ticket is `todo`** — every open row is
27-
`blocked`/`needs_user`. See "Autonomous batch handoff, 2026-07-30 (CCF-011
28-
empty-callable family, CLOSED)" immediately below for this batch's queue,
29-
baselines and next recommended family; the CCF-007 section follows it. The prior
35+
#1773 stays blocked, and the only `todo` row is the **inactive** #1875. See
36+
"Autonomous batch handoff, 2026-07-30 (CCF-014 + CCF-016, both CLOSED)"
37+
immediately below for this batch's queue, baselines and next recommended family;
38+
the CCF-011 and CCF-007 sections follow it. The prior
3039
batch reached 14,344 via #1851/#1852/#1853/#1849; the one before that left the
3140
floor at 14,233 via the CCF-003 close
3241
(#1846/#1844/#1845/#1847, +31), tooling #1848, and CCF-005's first fix #1850 (+3);
@@ -191,6 +200,200 @@ This is the cold-start handoff for the next working session. Keep it focused
191200
on verified facts, remaining bounded work, and commands needed to resume.
192201
Historical session detail belongs in git history and `plan.sqlite3`.
193202

203+
## Autonomous batch handoff, 2026-07-30 (CCF-014 + CCF-016, both CLOSED)
204+
205+
Branch `feature/remediation-batch-ccf014-ccf016` (off
206+
`feature/remediation-batch-empty-callable`). Five commits: two family plans, two
207+
implementations, plus this handoff. **Nothing pushed, merged, rebased, or
208+
tagged.** CNA and mobile-eggbert were not inspected or modified; #1773 remains
209+
blocked. Maximum aggregate compilation parallelism was **3 jobs** throughout;
210+
`check_selective_components.sh` and `check_doxygen_warnings.sh` were run with
211+
`TMPDIR="$PWD/build-tmp"` (absolute) to honour the no-`/tmp`-builds rule.
212+
**Signing preflight** (`gpg --batch --pinentry-mode error --clearsign`) exited 0
213+
without a prompt before any repository work, and every commit is signed.
214+
215+
### Completed (committed)
216+
217+
| Ticket | Findings | Fix | Sanitizer | Tests |
218+
|---|---|---|---|---|
219+
| **#1871** | — (design) | `docs/TryOutputFailureContractPlan.md`, 18 sections. Current behaviour of both CCF-014 findings measured by `build-probe/1871_try_output_probe.cpp` (26 cases) with caller sentinels; reference read from `SequenceReader.cs`, `SequenceReader.Search.cs`, `Utf8Parser.*.cs`, `ParserHelpers.cs`. | n/a | 0 |
220+
| **#1872** | SR-AUD-075, SR-AUD-085 → **remediated**, **closes CCF-014** | `SequenceReader<T>::TryRead`/`TryPeek` assign `T{}` on the end-of-sequence branch (position untouched); `Utf8Parser` gained one shared private `fail(value, bytesConsumed)` used by all **ten** failure exits of its **nine** overloads. `FormatException` path deliberately unchanged. | ASan+UBSan+LSan clean, probe instrumented | **+14** |
221+
| **#1873** | — (design) | `docs/DerivedExceptionHResultPlan.md`, 13 sections. All values measured by `build-probe/1873_hresult_probe.cpp` (44 checks + controls); required values from `HResults.cs` and each type's own `.cs`. | n/a | 0 |
222+
| **#1874** | SR-AUD-093/094/095/096/100 → **remediated**, **closes CCF-016** | All **40** public constructors of **11** types assign their documented HResult (38 previously-wrong results → `wrong=0`). | not applicable, recorded with reasons | **+18** |
223+
224+
**Batch total +32** over the 14,444 floor → **14,476 across 37 executables**,
225+
verified through the full component gate.
226+
227+
**Count correction:** #1872's commit message says "+13 add-only tests
228+
(SequenceReader 7, Utf8Parser 6)". The measured delta is **14** — `Utf8ParserTests`
229+
gained 7, not 6. The commit is not amended (historical commits are never
230+
rewritten here); the corrected figure stands in the ticket notes, the audit
231+
records and this file. Arithmetic: 14,444 + 14 + 18 = 14,476. ✔
232+
233+
### New ticket created this batch and left INACTIVE
234+
235+
- **#1875** (P3, `todo`, **inactive — do not start without confirming it is still
236+
wanted**) — audit the **45 of 59** exception types *outside*
237+
`modules/core/include/System/` that carry no explicit HResult (`Threading`,
238+
`Net`, `IO`, `Text.Json`, `Xml`, `Security.Cryptography`, …). Measured
239+
population, **not** confirmed defects: `System::AggregateException` sat in the
240+
identical shape and is **correct**, because .NET's `AggregateException.cs`
241+
assigns no HResult either. Each type must be checked against its own reference
242+
first. **No `SR-AUD-*` identifier issued** — numbering stays frozen at 364.
243+
244+
### Premises corrected (measured 2026-07-30, historical text preserved)
245+
246+
**CCF-014**
247+
248+
1. **The family is 11 public entries, not the two the record names** — 2 in
249+
`SequenceReader` and all 9 `Utf8Parser` overloads.
250+
2. **The defect is grammar-independent** — the `X` and `N` grammars leak the same
251+
stale value as the default decimal path.
252+
3. **Failure *after* a successful core parse is equally stale** (a width-range
253+
rejection such as `"256"` into `uint8_t`). A repair that reset the output only
254+
when the core parse failed would have missed every width.
255+
4. **`bytesConsumed` was always correct and no partial value was ever published**,
256+
so of the ten recurring Try-output failure classes only "output left unchanged"
257+
applies here.
258+
5. **The `FormatException` path leaves both outputs unwritten — and .NET does the
259+
same deliberately** (`ParserHelpers.cs` `Unsafe.SkipInit`). Parity, not a
260+
defect; a permanent test pins that a caller sentinel survives the throw.
261+
6. **The wrapper already compensated for the core**: `SequenceReaderExtensions`
262+
assigns `value = 0` on false and reaches `SequenceReader::TryRead` through a
263+
helper that also assigns `T{}`. Six same-module surfaces already had the
264+
contract; all six are now pinned by tests.
265+
266+
**CCF-016**
267+
268+
7. **Five findings cover ELEVEN types, not five** (SR-AUD-094 alone spans five),
269+
and the port has more constructors than the reference in two places.
270+
8. **SR-AUD-100's message claim is a FALSE POSITIVE.** The port's
271+
`Duplicate objects in argument.` is byte-identical to
272+
`SR.Arg_DuplicateWaitObjectException` (`Strings.resx:319-321`). No message
273+
change was made; a test pins the text verbatim. The finding is `remediated` on
274+
its real (HResult) half with the Correction appended, per the
275+
SR-AUD-081/SR-AUD-362 convention.
276+
9. **`AggregateException` is not a twelfth member** — .NET assigns no HResult
277+
there either; pinned as a control in both the probe and the suite.
278+
279+
### Recorded requirement (not an approval trigger)
280+
281+
`SequenceReader<T>::TryRead`/`TryPeek` now require `T` to be value-initialisable.
282+
That is strictly *weaker* than the reference's own `where T : unmanaged`
283+
constraint, and a permanent test instantiates `SequenceReader<std::string>` to
284+
show it. Member functions of a class template instantiate only when used, so any
285+
instantiation that does not call these two is unaffected.
286+
287+
### Baselines (verified this batch)
288+
289+
- Full component gate: **14,476 tests across 37 executables**, no failures.
290+
- Audit: **56 remediated, 307 confirmed, of 364** (seven findings moved
291+
`confirmed → remediated`; one row is the split `043a remediated; 043b open`).
292+
- **CCF-014 and CCF-016 are both CLOSED** — closure paragraphs in
293+
`audit/AUDIT_CROSS_CUTTING_FINDINGS.md`.
294+
- Module graph: **41 physical modules, 91 dependency edges** (unchanged).
295+
- Negative fixtures: **9 fixtures, 66 sites**, every site rejected (unchanged).
296+
- Version seams: **2 seams, 18 specialisations** (unchanged).
297+
- Canonical Doxygen: **1,941 warnings** (ceiling 1,942) — unchanged.
298+
- `validate_module_boundaries.py` (+ unit test), `generate_component_catalog.py
299+
--check`, `db_consistency_check.py`, both seam checks, both negative-fixture
300+
checks, `git diff --check`, `check_selective_components.sh` and
301+
`local_ci_check.sh build` all pass.
302+
303+
### Sanitizer freshness
304+
305+
- **CCF-014 (#1872):** both files are header-only, so
306+
`build-probe/1871_try_output_probe.cpp` was compiled **with**
307+
`-fsanitize=address,undefined` — that recompiles the changed inline code with
308+
instrumentation, so no stale archive is involved and `build-asan` needed no
309+
rebuild (untouched this batch). Exit 0, zero ASan/UBSan/LeakSanitizer reports,
310+
including the 20- and 23-digit overflow inputs that drive the parser
311+
accumulator and the raw `const uint8_t*` walk to their limits. TSan recorded as
312+
**not applicable**.
313+
- **CCF-016 (#1874):** sanitizers recorded as **not applicable** with reasons —
314+
one integer store per constructor body; no allocation, ownership transfer,
315+
pointer arithmetic, lifetime change, shared state or new member. No sanitizer
316+
target needed refreshing.
317+
318+
**Mutation checks (both implementations).** Reverting `Utf8Parser::fail`'s value
319+
write fails 5 permanent tests; reverting `SequenceReader::TryRead`'s fails 3;
320+
deleting one of `DllNotFoundException`'s three HResult assignments fails 2. An
321+
assertion set that is never mutation-checked is how
322+
`ParseInvalidNotDigit_BytesConsumedIsZero` came to initialise its value to 99 and
323+
then assert only the cursor.
324+
325+
### Build-directory sizes (start → end of batch)
326+
327+
| Dir | Start | End |
328+
|---|---|---|
329+
| `build` | 723M | 724M (incremental, ccache) |
330+
| `build-asan` | 3.5G | 3.5G (untouched this batch) |
331+
| `build-probe` | 31M | ~32M (2 probe sources + 5 logs retained; binaries removed) |
332+
| `build-consumer` | 12K | 12K |
333+
| `build-tmp` | 8.1M | 8.1M (selective-check mktemp matrix cleaned by the script) |
334+
| `build-modular` | 777M | 777M (untouched) |
335+
336+
`build-probe/build.sh` (shared, gitignored) gained three additive entries this
337+
batch — `modules/buffers/include` on the include path and
338+
`FormatException.cpp`/`OverflowException.cpp`/`InvalidCastException.cpp` as
339+
support sources — so buffers and exception probes link. Additive only; no
340+
existing probe is affected.
341+
342+
### Approval-gated, unchanged (do NOT start without explicit per-action approval)
343+
344+
- **#1862** SR-AUD-029 — `Round(x,digits)` `noexcept` decision. `FloatingValueFidelityPlan.md` §19.1.
345+
- **#1863** SR-AUD-033 format — observable `ToString` text change. §19.2.
346+
- **#1865** SR-AUD-033 parse tail — thousands + overflow→Infinity. §19.4.
347+
- **#1858** SR-AUD-035 tail — Decimal comma + overflow taxonomy. §19.4.
348+
- **#1854** SR-AUD-043b — `ReadOnlyMemory`/`HashCode::AddBytes` drop-`noexcept`. §19.3.
349+
- **#1773** — CNA/mobile-eggbert migration; blocked until they upgrade.
350+
351+
All five decision records in `docs/FloatingValueFidelityPlan.md` §19 are
352+
unchanged by this batch.
353+
354+
### Remaining compatible queue
355+
356+
Only **#1875**, which is deliberately inactive. Every other open ticket is
357+
`blocked` or `needs_user`.
358+
359+
### Recommended next work
360+
361+
1. **#1875**, if wanted — the 45-type HResult audit. Bounded, mechanical, and
362+
already carries its measured evidence; the honest framing is "check each
363+
against the reference", not "fix 45 wrong values".
364+
2. Otherwise start another compatible family from the audit index, plan first.
365+
Strongest remaining candidates, by coherence and safety impact:
366+
- **CCF-002** (SR-AUD-006/007/009) — `DateTime`/`DateTimeOffset`/`TimeOnly`
367+
component and parse validation. Check first whether the parse-grammar half
368+
is approval-gated (accepted textual grammar) and split it if so, exactly as
369+
#1857→#1858 and #1864→#1865 were split.
370+
- **CCF-012** (SR-AUD-015) — `String::Format` / `FormattableString` brace
371+
grammar. Two surfaces, one shared parsed-token model; note that changing
372+
accepted grammar is an approval trigger, so this is likely design-first.
373+
- **CCF-017** (SR-AUD-114) — the `Attribute` base's identity fallback. Small
374+
membership, but it changes value semantics for every unoverridden attribute.
375+
- **CCF-019 remainder** (SR-AUD-327 JsonNode, SR-AUD-333 XML LINQ `XObject`) —
376+
genuine ASan-confirmed use-after-free, the highest-severity remaining
377+
family, but each needs its own compatibility review and is likely
378+
design-first with an approval-gated implementation, exactly as
379+
`LinkedListNode` was.
380+
381+
### Known limitations / notes
382+
383+
- `CLAUDE.md`'s non-negotiable rule 2 still cites the historical **14,113**
384+
figure from #1832. No recent batch has refreshed it; NEXT.md is the live
385+
baseline and each ticket's section states the count it measured. Left unchanged
386+
deliberately rather than churning a rules document.
387+
- Test-side audit reports were **not** given remediation notes, per the
388+
established convention — the notes live on the owning header report.
389+
- The 45-type population behind #1875 is measured but unverified against the
390+
reference. Nothing in this batch asserts any of them is wrong.
391+
- `SequenceReader` still lacks .NET's `TryPeek(long offset, out T)` overload;
392+
adding it is new API surface, not a failure-contract repair, and is recorded as
393+
a deliberate exclusion in `TryOutputFailureContractPlan.md` §16.
394+
395+
---
396+
194397
## Autonomous batch handoff, 2026-07-30 (CCF-011 empty-callable family, CLOSED)
195398

196399
Branch `feature/remediation-batch-empty-callable` (off

‎audit/AUDIT_CROSS_CUTTING_FINDINGS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ previously require. That is strictly *weaker* than the reference's own
611611
specification, virtual function, vtable slot or data member changed; `Utf8Parser`
612612
has no data members at all.
613613

614-
Evidence: 13 permanent add-only regressions (`SequenceReader` 7, `Utf8Parser` 6);
614+
Evidence: 14 permanent add-only regressions (`SequenceReader` 7, `Utf8Parser` 7);
615615
`SharpRuntimeTests_Buffers` 536/536; whole-repository build clean with zero
616616
errors and zero warnings. **Mutation-checked**, which is what the record's
617617
"checking only false and zero consumed is insufficient" warning demands: reverting

‎audit/modules/buffers/include/System/Buffers/Text/Utf8Parser.hpp.audit.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ The class doc-comment previously stated only the `bytesConsumed = 0` half of the
144144
contract and was silent about `value`; it now states both halves and the throwing
145145
exception.
146146

147-
Closure evidence: 6 new permanent regressions in `Utf8ParserTests.cpp` (failed
147+
Closure evidence: 7 new permanent regressions in `Utf8ParserTests.cpp` (failed
148148
`bool` parse including a valid-token prefix; not-a-digit across all eight integer
149149
widths; empty source; overflow-after-successful-core across every width in both
150150
directions plus a negative literal into an unsigned type; all four format

0 commit comments

Comments
 (0)