Nullable remediation: UtilitiesCS/ReusableTypeClasses (#366)#380
Merged
Conversation
Per-file `#nullable enable` opt-in remediation for 32 reusable base/value types under UtilitiesCS/ReusableTypeClasses/ (Batches 1-5: trivial leaves, value/utility types, matrices, timed actions, locking core). Each file carries a `#nullable enable` pragma and reaches zero CS86xx under the per-file pragma gate. Annotation and null-safety only: nullable `?` annotations, guard clauses, justified `!`, and unconstrained-generic `T?`/`default!` fields. No behavior changes, no refactors, no file splits, no post-condition attributes (net481 lacks the polyfills), no record/init conversion. No `<Nullable>` element added to UtilitiesCS.csproj (AC2). Verification (cluster, isolated-compile methodology): 0 CS86xx, 0 CS8714 across the 32 files under their pragmas; csharpier clean; analyzers build succeeds (75 warnings = baseline, 0 errors); 5702 MSTest tests pass with no regression; line coverage 83.8% / branch 76.4% (unchanged within rounding, annotations are IL-invariant). Batch 6-8 and the CS8714 `where TKey : notnull` public-contract change on the four generic dictionary bases are HALTED pending maintainer ratification (see evidence/other/cs8714-notnull-ratification.md, BLOCKED). Phases 6-9 are out of scope for this commit. Epic child of utilitiescs-nullable-remediation (Wave 0). Refs #366. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
Atomic-executor memory: on net481 the ConcurrentDictionary reference assemblies are not nullable-annotated, so `where TKey : notnull` is not required to clear CS8714 under the per-file pragma gate; and the pragma gate must be measured with the isolated-compile methodology because the whole-project TWAE build carries pre-existing unrelated errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
Orchestrator memory: (1) TaskMaster lacks the Python orchestrator-state validator, so the SubagentStop completion hook uses the portable PowerShell path (no require-complete) — a blocked child can terminate and open its PR with blocked_reason=none and steps 5-8 non-pending; (2) rebasing an epic child onto an advanced integration tip conflicts only on the shared agent-memory MEMORY.md index (resolve as a union), and pr_context must be regenerated from the real diff in an isolated agent worktree. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
…: notnull constraint propagation Nullable-annotate the 5 Batch 6 concurrent-observable base files under per-file #nullable enable (ConcurrentObservableBag, ConcurrentObservableCollection[.Serialization], ConcurrentObservableDictionary, ObservableDictionary; DictionaryChangedEventArgs newValue/oldValue made TValue?). Zero CS86xx / zero CS8714 for the cluster (isolated pragma gate); 5702 tests pass. Apply the maintainer-RATIFIED (2026-07-19T22:14:30Z) `where TKey : notnull` public generic-parameter-list constraint to ConcurrentObservableDictionary<TKey, TValue>. The ConcurrentBag<T>-based ConcurrentObservableBag is NOT constrained. Cross-child two-file scope waiver (epic-orchestrator authorized 2026-07-19T23:10:00Z, Option A extended to two files): to keep the ratified public contract internally consistent, add EXACTLY ONE `where TKey : notnull` line to EACH of two #367-owned NewtonsoftHelpers consumers that otherwise emit CS8714 once ConcurrentObservableDictionary is constrained, and nothing else: - UtilitiesCS/NewtonsoftHelpers/WrapperScoDictionary.cs -> WrapperScoDictionary<TDerived, TKey, TValue> - UtilitiesCS/NewtonsoftHelpers/ScoDictionaryConverter.cs -> ScoDictionaryConverter<TDerived, TKey, TValue> The cascade is statically bounded at these two files; PeopleScoConverter.cs (commented-out reference) and WrapperPeopleScoDictionaryNew.cs (concrete type args) are SAFE and are NOT edited. A third cross-child consumer would require re-escalation to the epic layer (none surfaced). Additive constraint only; no runtime behavior change (ConcurrentDictionary already rejects null keys on net481). Refs #366. Epic: utilitiescs-nullable-remediation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
…gController Per-file #nullable enable annotation of the 7 Batch 7 files (NewSmartSerializableConfig, SmartSerializableBase, SmartSerializable, SmartSerializableStatic, SmartSerializableNonTyped, SmartSerializableLoader, ConfigController). Reflection-populated fields become `= null!` (// set by deserialization); uninitialized events become nullable; an inherited CS8766 mismatch on SmartSerializable<T>.DeserializeObject was conformed to the interface `T` return with a justified `!` rather than editing the out-of-scope interface. Zero CS86xx/CS87xx attributable to the 7 Batch 7 files under the isolated per-file pragma gate (whole-assembly nonzero exit is the pre-existing out-of-scope CS0618/CS0168 baseline only). 5702 tests pass; line 83.79% / branch 76.34%. Annotation-only: no record/init conversion, no file split (SmartSerializable.cs and SmartSerializableBase.cs remain single files), no NewtonsoftHelpers or exempt-WinForms file touched, no <Nullable> element added to the csproj. Refs #366. Epic: utilitiescs-nullable-remediation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
…ary constraint DEFERRED)
Per-file #nullable enable annotation of the 7 Batch 8 files (SerializableList, ScBag,
ScoDictionaryStatic, ScoDictionaryNew, SloLinkedList, SloStack, ScDictionary). Serialization
round-trip fields become `= null!` (// set by deserialization); SloLinkedList NotImplementedException
interface stubs annotated to the interface nullable contract without bodies. Zero CS86xx and zero
CS8714 attributable to the 7 files under the isolated per-file pragma gate; 5702 tests pass;
line 83.79% / branch 76.34%. Annotation-only: no record/init, no file split (SerializableList.cs
remains single), no NewtonsoftHelpers/exempt-WinForms touch, no <Nullable> element added.
Ratified `where TKey : notnull` constraint status for Batch 8 bases:
- ScoDictionaryNew<TKey, TValue>: APPLIED (cascade fully absorbed by the two already-waived
#367 files WrapperScoDictionary.cs + ScoDictionaryConverter.cs; 0 CS8714).
- ScoDictionaryStatic: NOT APPLICABLE — it is a non-generic static class of Type extension
methods with no TKey (the plan's "four generic bases" wording is inaccurate for this file);
reaches 0/0 regardless.
- ScDictionary<TKey, TValue>: DEFERRED / NOT APPLIED. Applying the constraint surfaces a THIRD
cross-child CS8714 in UtilitiesCS/NewtonsoftHelpers/WrapperScDictionary.cs(18) — a #367-owned
consumer distinct from the two epic-authorized waiver files. Per the AUTHORIZED PROGRAM
third-consumer clause, the child orchestrator STOPPED and re-escalated to the epic layer rather
than widen the waiver unilaterally. The tree is green WITHOUT this constraint (net481 no-op).
[P8-T1] complete; [P8-T2..T4] pending the epic-layer decision on the ScDictionary constraint.
Refs #366. Epic: utilitiescs-nullable-remediation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
Epic layer authorized extending the ratified `where TKey : notnull` cross-child waiver to a THIRD #367-owned NewtonsoftHelpers consumer, UtilitiesCS/NewtonsoftHelpers/WrapperScDictionary.cs (one constraint line on WrapperScDictionary<TDerived,TKey,TValue>), triggered by constraining the fourth ratified base ScDictionary<TKey,TValue>. Three-file waiver total (one `where TKey : notnull` line each): 1. WrapperScoDictionary.cs (Batch 6) 2. ScoDictionaryConverter.cs (Batch 6) 3. WrapperScDictionary.cs (A', Batch 8 completion) Factual correction: ScoDictionaryStatic is a non-generic static class of Type extension methods (no TKey); the ratified "four generic bases" wording is inapplicable there. The constraint applies to the three truly generic bases (ConcurrentObservableDictionary, ScoDictionaryNew, ScDictionary). ScBag remains unconstrained. Revises plan tasks [P8-T2], [P9-T9], [P9-T10] and appends the OPTION A-PRIME resolution section to the cs8714-notnull-ratification dossier. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
…our-file A'' cross-child waiver) Applies `where TKey : notnull` to the third truly-generic base ScDictionary and propagates it to the four #367-owned NewtonsoftHelpers consumers under the epic-authorized four-file waiver (A''): WrapperScoDictionary.cs, ScoDictionaryConverter.cs, WrapperScDictionary.cs, ScDictionaryConverter.cs. Cross-child consumer set is closed at four (Wrapper+Converter per base). P9-T3 solution-wide count carries expected cross-child fan-in from sibling files (capstone #376). Batch 8 isolated-cluster pragma gate: 0 CS86xx / 0 CS8714 in the #366 cluster including the four waived NewtonsoftHelpers lines. Tests 5702/5702 pass; line coverage 83.79% -> 83.88% (no changed-line regression). AC1-AC6 checked off in issue.md. Phase 8/9 final-QC evidence recorded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
Policy-audit, code-review, and feature-audit for the four-file A'' waiver completion. blocking_count 0; solution-wide CS86xx recorded as expected cross-child fan-in (capstone #376), sub-85% repo-wide line coverage dispositioned non-blocking (pre-existing baseline, AC4 no-regression PASS). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv
drmoisan
force-pushed
the
feature/utilitiescs-nullable-reusabletypes-366
branch
from
July 20, 2026 02:30
580c7c9 to
120365b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nullable remediation: UtilitiesCS/ReusableTypeClasses (#366)
Epic child of
utilitiescs-nullable-remediation(Wave 1). Base branch:epic/utilitiescs-nullable-remediation-integration.Status: COMPLETE — ready to merge
Per-file
#nullable enableopt-in remediation for the 51 in-scope reusable base/value types underUtilitiesCS/ReusableTypeClasses/, plus the maintainer-ratifiedwhere TKey : notnullgeneric-parameter-list constraint on the three truly-generic dictionary bases and its epic-authorized propagation to four cross-child NewtonsoftHelpers consumers. Annotation and null-safety only; no behavior changes.What this delivers
Per-file
#nullable enableacross all 51 in-scope files (Batches 1–8): trivial leaves / EventArgs / observers / interfaces, standalone value/utility types, matrices, timed actions, locking core, concurrent-observable bases, SmartSerializable family + ConfigController, and the Serializable wrappers. Each file carries a#nullable enablepragma and reaches zero CS86xx / zero CS8714 under the per-file pragma gate. Changes are annotation and null-safety only: nullable?annotations, guard clauses, justified!, unconstrained-genericT?/out TValue?, anddefault!/= null!for reflection/deserialization-populated fields (with// set by deserializationcomments). No behavior changes, no refactors, no file splits, no post-condition attributes (net481 lacks the polyfills), norecord/initconversion.Ratified
where TKey : notnullconstraint ([P6-T2], RATIFIED 2026-07-19)The maintainer ratified adding
where TKey : notnullto the public generic parameter list of the dictionary base types. Factual correction applied during execution:ScoDictionaryStaticis a NON-genericstatic classofTypeextension methods, so the constraint is mechanically inapplicable there. Net effect: the constraint applies to the three truly-generic bases —ConcurrentObservableDictionary,ScoDictionaryNew, andScDictionary.ScBag(ConcurrentBag<T>-based) andConcurrentObservableBagare correctly left unconstrained.On net481 the BCL
ConcurrentDictionary<TKey, TValue>reference assemblies are not nullable-annotated, so the constraint emits zero CS8714 against the base derivations in isolation; it is adopted as forward-looking public-contract hygiene.ConcurrentDictionaryalready rejects null keys at runtime, so the constraint is IL-metadata / compile-time-contract only, with no runtime behavior change (AC3/AC5).Epic-authorized four-file cross-child waiver (Option A'')
Because sibling child #367 (
UtilitiesCS/NewtonsoftHelpers, already merged onto the integration branch) is#nullable enableand declares wrapper/converter types with unconstrainedTKey, constraining the bases cascades CS8714 into #367-owned consumers. The epic layer (which owns cross-child boundaries) authorized a bounded waiver adding exactly onewhere TKey : notnullline to each of four #367-owned NewtonsoftHelpers files, and nothing else:UtilitiesCS/NewtonsoftHelpers/WrapperScoDictionary.csUtilitiesCS/NewtonsoftHelpers/ScoDictionaryConverter.csUtilitiesCS/NewtonsoftHelpers/WrapperScDictionary.csUtilitiesCS/NewtonsoftHelpers/ScDictionaryConverter.cs(noo; distinct from Auto hide inactive branches #2)An assembly-wide grep confirms the cross-child consumer set is closed at these four: each generic base with cross-child consumers has exactly a Wrapper and a Converter (a symmetric closed set).
WrapperPeopleScoDictionaryNew.csandPeopleScoConverter.csare verified safe (concrete type arguments / commented-out reference) and are not touched. Full authorization and empirical evidence:docs/features/active/utilitiescs-nullable-reusabletypes/evidence/other/cs8714-notnull-ratification.md.Verification
msbuild UtilitiesCS/UtilitiesCS.csproj /t:Rebuild /p:TreatWarningsAsErrors=true, no global/p:Nullable=enable): 0 CS86xx, 0 CS8714 across the 51 cluster files including the four waived NewtonsoftHelpers lines.msbuild TaskMaster.sln ... /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true): succeeds, 0 errors.UtilitiesCS.csproj: no<Nullable>element (AC2).Solution-wide gate deviation (expected cross-child fan-in)
The solution-wide pragma-gate rebuild (
msbuild TaskMaster.sln /t:Rebuild /p:TreatWarningsAsErrors=true) exits non-zero because ~148 pre-existing CS86xx originate in sibling-owned#nullable enablefiles (EmailIntelligence/**,OutlookObjects/**) plus two vendoredSVGControlCS0649. Zero solution-wide errors originate in a #366 file. The operative gate for #366 is the isolated-cluster result above; solution-wide zero is the Wave-2 CI capstone (#376) obligation. Documented in the feature-review artifacts.Acceptance criteria
<Nullable>element): satisfied.Feature-review: policy-audit, code-review, and feature-audit all PASS; blocking_count 0.
Refs #366.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UXCu1xPtNbJs2HwKxgS9Bv