Skip to content

[OpenSpec] dossiq-delegation-via-events #1330

Description

@github-actions

⚠️ OpenSpec-managed issue — this content is automatically synced
from the openspec/ directory. Manual edits will be overwritten on next sync.

Artifacts

Summary

The delegation of contract / besluit / bezwaar / advice decisions from dossiq to decidesk
was implemented against a transport that does not exist. ContractDecisionDelegationService
resolves decidesk by calling
container->get('OCA\OpenRegister\Service\IntegrationService')->getLeaf(name:'decidesk') and then
->createDecision(payload:...). There is no OCA\OpenRegister\Service\IntegrationService class and
no getLeaf() / createDecision() method — every call throws, is caught, and resolveIntegrationService()
returns null, so delegation always fail-closes and never reaches decidesk. The flow is only
"safe" because it fails closed; it has never actually delegated a decision.

decidesk has since MERGED a concrete event contract on its development branch. The chosen transport
is the Nextcloud IEventDispatcher: a consumer dispatches OCA\Decidesk\Event\DecisionRequestedEvent
synchronously, decidesk's in-process listener handles it and writes the result back onto the event
(isHandled() + getDecisionId()), and decidesk later dispatches OCA\Decidesk\Event\DecisionConcludedEvent
carrying the terminal outcome. This change rewires dossiq's delegation services onto that contract.

What changes:

  1. ContractDecisionDelegationService injects OCP\EventDispatcher\IEventDispatcher. raiseContractDecision()
    and raiseDecision() build and dispatchTyped() a DecisionRequestedEvent
    (guarded by class_exists(\OCA\Decidesk\Event\DecisionRequestedEvent::class) — fail closed when
    decidesk is absent), then read back isHandled() / getDecisionId(). The dead getLeaf /
    IntegrationService / createDecision(payload:...) / getDecisionOutcome / resolveIntegrationService()
    / consumeOutcome() paths are removed.
  2. A new DecisionConcludedListener listens for DecisionConcludedEvent, filters
    getSourceApp() === 'dossiq', builds the normalised outcome from the event getters, and drives
    BesluitMaterialisationService to materialise the

Specs

Tasks

  • Inject OCP\EventDispatcher\IEventDispatcher into ContractDecisionDelegationService.
  • Rewrite raiseContractDecision() to build + dispatchTyped() a
  • Rewrite raiseDecision() (shared core used by the bezwaar/advice siblings) the same way.
  • Delete resolveIntegrationService(), consumeOutcome(), and all createDecision(payload:...) /
  • Keep the public method signatures of BezwaarDecisionDelegationService,
  • Add lib/Listener/DecisionConcludedListener.php implementing IEventListener, filtering
  • Add BesluitMaterialisationService::materialiseFromConcludedEvent() that maps the event getters
  • Register the listener for \OCA\Decidesk\Event\DecisionConcludedEvent::class in
  • Update Bezwaar/DecisionService::applyToBezwaar() to stop polling decidesk via consumeOutcome()
  • grep -rn "getLeaf|OCA\\OpenRegister\\Service\\IntegrationService|createDecision(payload:|consumeOutcome|getDecisionOutcome" lib/
  • php -l every changed PHP file.
  • Run the hydra mechanical gates (scripts/run-hydra-gates.sh); report results.
  • openspec validate dossiq-delegation-via-events --strict exits 0.

Design

See design.md for technical design details.


Synced from openspec/changes/dossiq-delegation-via-events by OpenSpec workflow
App: dossiq

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions