Skip to content

PHASE-001: DispatchPhase model, registry phase, dispatcher queueing - #79

Merged
keithdv merged 2 commits into
PHASEfrom
PHASE-001-phase-model-and-queueing
Aug 15, 2026
Merged

PHASE-001: DispatchPhase model, registry phase, dispatcher queueing#79
keithdv merged 2 commits into
PHASEfrom
PHASE-001-phase-model-and-queueing

Conversation

@keithdv

@keithdv keithdv commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

First plan of the PHASE arc (phased factory-event dispatch). Adds the phase model and the per-scope deferral queue; nothing drains yet — PHASE-003 (stacked behind this) owns the entry-call drain.

What lands

  • DispatchPhase enum (Immediate/AfterFlush/AfterCommit), Immediate the default and today's exact contract.
  • FactoryEventHandlerAttribute<T> moved to its own file so DispatchPhase is never linked into the netstandard2.0 generator (a duplicated public type broke every project referencing both — recorded as a Discovery Log entry).
  • FactoryEventHandlerRegistry carries a phase per handler; new 3-arg RegisterHandler overload alongside the generator-emitted 2-arg one, both preserving the [DynamicallyAccessedMembers(All)] trimming invariant.
  • IFactoryEventPhaseScheduler (public in Internal, so generated code can reach it): enqueue + drain. The drain sweeps the requested phase and every earlier one, earliest first, until empty.
  • Dispatcher queues non-Immediate handlers; log events 9001–9004.

Gates

Plan review (CONCERNS, 4 vetoes addressed pre-implementation), test review (found a real defect: the drain resolved only the requested phase's queue, silently dropping work enqueued into an already-passed phase — fixed, 3 tests verified red against the pre-fix code), code review. Suites at close: unit 653×2, integration 561×2, Design 86×2 — 0 failures.

Interim-behavior note: three acceptance bullets here pin behavior PHASE-003 is chartered to invert (queue-whenever-a-scheduler-exists). That restatement is pre-declared, not test-gutting — PHASE-003's evidence map lists each amended test with its intent preserved.

Docs: docs/todos/PHASE-phased-event-dispatch/plans/001-phase-model-and-queueing.md, reviews in the sibling reviews/ folder.

🤖 Generated with Claude Code

keithdv and others added 2 commits August 14, 2026 15:04
Handlers registered with [FactoryEventHandler<T>] can now declare when they
run relative to the factory operation that raised the event:

- Immediate (default, unchanged): dispatched at Raise time, in the caller's
  transaction, observing staged state.
- AfterFlush / AfterCommit: deferred into a per-scope queue and run when that
  phase drains, so read-only projections stop inheriting the in-transaction
  contract built for atomic write handlers.

This plan lands the model, the registry phase, the queueing, and the drain
primitive (IFactoryEventPhaseScheduler in the Internal namespace). The drain
POINTS come next: entry-call tracking in PHASE-003, the consumer-facing
coordinator in PHASE-004.

Failure semantics key off the drain point rather than the phase: an
in-transaction drain propagates handler exceptions so the caller can roll back;
a post-completion drain logs (9003) and swallows, since a throw there can no
longer roll anything back. A drain covers the requested phase and every earlier
one, so nothing a handler enqueues mid-drain is silently dropped.

FactoryEventHandlerAttribute<T> moved to its own file: FactoryAttributes.cs is
linked into the netstandard2.0 generator, and compiling DispatchPhase there
would duplicate a public runtime type. The generator matches the attribute by
metadata name, so it never needed the type.

Backward compatible: no phase argument means Immediate, the generator's
existing two-argument RegisterHandler call is untouched, and no existing test
was modified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@keithdv
keithdv merged commit 721218a into PHASE Aug 15, 2026
2 checks passed
@keithdv
keithdv deleted the PHASE-001-phase-model-and-queueing branch August 17, 2026 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant