fix(964): guard every EngineToggleStateCoordinator sink call and split the coordinator into partials - #977
Merged
drmoisan merged 19 commits intoOct 3, 2026
Conversation
… fix Active minor-audit folder with acceptance criteria AC1 to AC8, the atomic plan v1.3 cleared by executor preflight after four rounds, the preflight clearance record, and the promoted potential record for issue 964. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rdinator-947-review-residuals-964
P2-T8 diffs against the merge commit 981abef with two negative controls; wording corrections from the confirming preflight. Confirming preflight ALL CLEAR; plan validator ok. No acceptance criterion changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X979KwR3sAjLjLkJJtnTQR
…k block The P0-T4 phrase-count payload was denied by the promotion-only hook. Evidence and plan check-offs for P0-T1 to P0-T3 are committed so nothing is lost. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X979KwR3sAjLjLkJJtnTQR
P0-T4 to P0-T14 completed; P0-T4 PHRASE rows recorded from the coordinator-run CMD-PHRASE-COUNT under the maintainer one-time bypass (2026-10-03). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
Behaviour-preserving move of the prime members to EngineToggleStateCoordinator.Prime.cs and the message helpers to EngineToggleStateCoordinator.Messages.cs (P1-T1 to P1-T8). The split census admits only the declaration keyword, scaffolds and redistributed usings; the unchanged fixture passes 39 of 39. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…recorded) Adds the OnNotify harness hook, the SinkGuard partial with the four NEW-NAMES-964 tests and the Race.cs remark rewording (P1-T9 to P1-T14). Against the split but unfixed coordinator the three FAIL-BEFORE-NAMES fail with their required reasons; the issue 948 guard and all invariant tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
Applies delivered sources F1 to F8 (P1-T15 to P1-T21): the refusal-path notification is guarded and its failure is logged once through the guarded log sink; one TryInvokeSink helper holds the only sink catch; CompletePrime records a reported fault kind only on the success branch of the guard; documentation corrected. P1-T22 halted pending maintainer approval. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…and line-count evidence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…rison and footprint evidence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…t handoff (P2-T9 to P2-T20) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…tifacts Review verdict PASS with 0 blocking findings. CR-1 and CR-4 are related non-blocking findings and are remediated in this item under the related-defect directive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…and CR-4 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…ric sink-guard assertions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013cov8xWT2homg3SU8L3MMT
…o P2-T16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…NOW) Policy audit and code review written so far; feature audit still in progress. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Name the null-or-empty engine-key refusal-path test in the SinkGuard partial summary and correct the cycle 1 plan status header. Comment and documentation only; csharpier check on the touched file exits 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Suggested title
fix(964): guard every EngineToggleStateCoordinator sink call and split the coordinator into partials
Summary
EngineToggleStateCoordinator.HandleToggleClickAsync, taken when the engines accessor returns null, no longer lets a throwingnotifyUnavailablesink escape into theasync voidOffice handler. The notification failure is reported once throughlogError, and alogErrorfailure on that path is contained.logError, prime-faultlogErrorinCompletePrime) now go through one private guard,TryInvokeSink. Only twocatchclauses remain in the type: the click boundary and the guard.GetPrimeTaskdocumentation now describes the registration marker rather than "the prime task".TaskMaster/Ribbon/EngineToggleStateCoordinator.csis split, as a pure move, into three cohesive partials (302, 197 and 86 lines), all registered inTaskMaster.csproj.Why
Issue #964 records the residual findings of the #947 review. The refusal-path notification was the one sink call left unguarded, so a throwing sink could crash the click handler. The three sites guarded the sink in three different ways, the
GetPrimeTaskdoc comment had drifted from the marker semantics, and the coordinator file had grown past the size the follow-up changes needed.What Changed
Production (
TaskMaster/Ribbon/)EngineToggleStateCoordinator.cs: the type contract, fields, constructor,GetPressed,HandleToggleClickAsync,ExecuteToggleAsync, and the newTryInvokeSinkguard. The constructor and theGetPressed/HandleToggleClickAsyncremarks state the non-throwing precondition on the engines accessor.EngineToggleStateCoordinator.Prime.cs(new): the prime lifecycle, moved unchanged apart from routing theCompletePrimesink call through the guard.EngineToggleStateCoordinator.Messages.cs(new): the null-name token,RenderEngineNameand the message builders, plus the newBuildNotifyFailedMessage.TaskMaster.csproj: twoCompileitems.Tests (
TaskMaster.Test/Ribbon/)EngineToggleStateCoordinatorTests.SinkGuard.cs(new):EngineToggleStateCoordinatorTests.cs: a harnessOnNotifyhook, so a test can model a throwing notification sink.EngineToggleStateCoordinatorTests.Race.cs: documentation-only update.TaskMaster.Test.csproj: oneCompileitem.Docs and evidence
docs/features/active/2026-10-01-engine-toggle-coordinator-947-review-residuals-964/: the issue record, the atomic plan, the remediation inputs and plan for one review cycle, the review artifacts, and evidence underevidence/. The evidence is projections and summaries only; no raw coverage or trx documents are committed.Architecture / How It Fits Together
TryInvokeSink(Action sinkCall, out Exception sinkFailure)invokes a sink. It returnstrueon a normal return, orfalsewith the contained exception, and never rethrows. Each caller decides what a failure means:logErrorthrough the guard once more;logErrorfailure;CompletePrimerecords the fault kind only in thetruebranch, then clears the marker as its last statement.The ordering invariants from #942, #944, #947 and #948 are unchanged.
Verification
Completed (recorded under the feature folder's
evidence/)/t:Rebuildwith 0 errors and 0 warnings;TreatWarningsAsErrors/t:Rebuildwith 0 errors and 0 warnings;Invoke-MSTestWithCoverage.ps1passed 7390 of 7390.TryInvokeSinkandBuildNotifyFailedMessageat 100% of lines.Recommended
Backward Compatibility / Migration Notes
None. The type is
internal, the split is a pure move within onepartialclass, and no public signature changed.Risks and Mitigations
TryInvokeSink: it contains every exception a sink throws. This is accepted and documented in place; it mirrorsRibbonCommandBoundary.SafeLog, and the caller is anasync voidOffice handler, where an escaping exception is the worse outcome.Review Guide
TaskMaster/Ribbon/EngineToggleStateCoordinator.cs: theTryInvokeSinkguard and the refusal-path and click-boundary call sites.TaskMaster/Ribbon/EngineToggleStateCoordinator.Prime.cs:CompletePrime, where the record happens only after the sink returns and the marker is cleared last.TaskMaster.Test/Ribbon/EngineToggleStateCoordinatorTests.SinkGuard.cs.EngineToggleStateCoordinator.Messages.csis a mechanical move. Most of the evidence Markdown under the feature folder is audit trail.Follow-ups
#nullable enable;artifacts/csharp/coverage.xmlpath andquality-tiers.ymlare absent repository-wide (already tracked).GitHub Auto-close