Skip to content

Proposition lifecycle events #8

Description

@jimador

Observation

When propositions change state (created, revised, superseded, contradicted), there's no event-driven notification. Consumers that need to react — cache invalidation, audit logging, metrics, cascading updates — must poll the repository or wrap every service method with callbacks.

PropositionReviser returns RevisionResult (New/Merged/Reinforced/Contradicted/Generalized), but this is a return value from a synchronous call. Independent components can't observe revision outcomes without being directly coupled to the caller.

What DICE already has

  • RevisionResult sealed hierarchy — captures what happened, but only as a return value
  • PropositionStatus — ACTIVE, SUPERSEDED, CONTRADICTED, PROMOTED — status changes are implicit in repository updates
  • PropositionPipeline — orchestrates extract → revise → persist, but no event hooks
  • Spring Framework — DICE already uses Spring; ApplicationEventPublisher + @EventListener is the idiomatic pattern

Proposal

A sealed event hierarchy published via Spring's ApplicationEventPublisher:

sealed class PropositionLifecycleEvent(
    val contextId: ContextId,
    val propositionId: String,
    val timestamp: Instant = Instant.now()
) {
    class Created(contextId, propositionId, val proposition: Proposition)
    class Revised(contextId, propositionId, val revisionResult: RevisionResult)
    class StatusChanged(contextId, propositionId,
                        val oldStatus: PropositionStatus, val newStatus: PropositionStatus)
    class Deleted(contextId, propositionId)
}

PropositionPipeline and PropositionReviser implementations publish events after state-changing operations. The publisher is optional (ApplicationEventPublisher? = null) for backward compatibility.

Consumers listen via standard Spring:

@EventListener
fun onCreated(event: PropositionLifecycleEvent.Created) {
    metricsRegistry.counter("dice.propositions.created").increment()
}

Use cases

  • Cache invalidation on state change
  • OTEL metrics/spans on lifecycle transitions
  • Audit trail with timestamps and reasons
  • Cascading updates (superseded proposition → update dependent abstractions)
  • Real-time UI updates

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions