Skip to content

feat(tasks): task expiry enforcement and configurable timeout/reject outcomes - #3338

Merged
rubenvdlinde merged 3 commits into
developmentfrom
feat/task-expiry-and-outcomes
Sep 2, 2026
Merged

feat(tasks): task expiry enforcement and configurable timeout/reject outcomes#3338
rubenvdlinde merged 3 commits into
developmentfrom
feat/task-expiry-and-outcomes

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

What

Wave 2 of the fleet task consolidation: the expiry and outcome semantics integriq's app-local HITL implementation had, moved into the shared task service (openspec change task-expiry-and-outcomes).

  • openregister_tasks gains on_timeout and on_reject (nullable, reserved vocabulary skip|error|dead_letter) plus the or_tasks_open_expiry (is_terminal, expires_at) index (migration Version1Date20260902090000).
  • TaskBuilder validates both at intake; onTimeout without expiresAt is refused by name.
  • FlowTimerSweep gains a third bounded range scan: non-terminal tasks past expires_at that declare on_timeout are closed through the existing TaskService::applyTimerOutcome(). Same FlowTimerWorker, same pass, no second scheduler.
  • A fired non-enforcing expiry timer falls back to the subject task's declared onTimeout (an enforcing wettelijk timer's own onExpiry still wins), because project() nulls expires_at after the last expiry timer fires and would starve the scan.
  • A rejecting completion of a task declaring onReject: dead_letter records the dead-letter outcome through the same mapping the timer path uses; error/skip are stored for the resuming consumer and change nothing.
  • Both behaviours are serialized on the task, in the task-form description, and accepted by the user-task and portal-task nodes next to expiresAt.

Why

A task's expires_at claims to be the ENFORCING deadline but nothing enforced it without a wettelijk timer. integriq (and the next adopters) need timeout/reject behaviour to delegate onto; without it every app keeps its own sweep.

Verification

  • Full local unit suite: 0 failures (the 6 pre-existing DBAL-stub errors in Sources/Dbal tests are environment-only).
  • phpcs, phpmd (per subdir), phpstan, psalm: clean.
  • hydra gates --scope-to-diff: all applicable gates green.

Companion PR follows in ConductionNL/integriq (adoption seam).

…outcomes

Harvested from integriq's HITL semantics (fleet audit, wave 2): a task can
now declare onTimeout and onReject in the reserved outcome vocabulary
(skip|error|dead_letter). The timer sweep gains a third bounded range scan
that closes non-terminal tasks past their enforcing deadline through the
existing timer-outcome path (no second scheduler); a non-enforcing expiry
timer falls back to the subject task's declared onTimeout; a rejecting
completion of a task declaring onReject dead_letter records the dead-letter
outcome through the same mapping. Both behaviours are serialized and carried
by the user-task and portal-task nodes next to expiresAt.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ 3a6e2f5

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
test-l10n-parity
format
check-schema-l10n
check-l10n-js
composer ✅ 174/174
npm ✅ 543/543
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-02 12:17 UTC

Download the full PDF report from the workflow artifacts.

The coverage guard correctly flagged the one untested addition: the
migration adding on_timeout/on_reject and the expiry-scan index. Three
cases: fresh table gets both columns and the index, a re-run changes
nothing and returns null, an absent table is left alone.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ a27d4a6

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
test-l10n-parity
format
check-schema-l10n
check-l10n-js
composer ✅ 174/174
npm ✅ 543/543
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-02 12:29 UTC

Download the full PDF report from the workflow artifacts.

lib/Migration is excluded from clover, so the previous commit recovered
nothing; the actually-uncovered addition was TaskMapper::findDueTimeouts().
The new case pins the scan's predicates (openness, declared on_timeout,
deadline order) and the floored batch limit.
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/openregister @ e231c4e

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
test-l10n
test-l10n-parity
format
check-schema-l10n
check-l10n-js
composer ✅ 174/174
npm ✅ 543/543
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-09-02 12:43 UTC

Download the full PDF report from the workflow artifacts.

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