Skip to content

fix(notifications): revive the overdue notification and correct a leftover Dutch default - #846

Merged
rubenvdlinde merged 1 commit into
developmentfrom
fix/dead-overdue-notification-and-enum-default
Aug 22, 2026
Merged

fix(notifications): revive the overdue notification and correct a leftover Dutch default#846
rubenvdlinde merged 1 commit into
developmentfrom
fix/dead-overdue-notification-and-enum-default

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Closes #845

Two silent defects, both fallout from the Dutch→English value rename (lib/Repair/RenameDutchDecideskValues.php).

1. actionOverdue could never fire

The scheduled filter was:

"filter": { "taskStatus": "overdue" }

That is the strict-equality shortcut against a status nothing in the app ever writes:

  • ActionItemWriter is the only write path (the schema is a read-only VTODO projection) and its mapStatus() maps open|in-progress|completed|cancelled — no overdue entry.
  • Overdue-ness is derived at read time in ActionItemAnalyticsService (dueDate < today) for dashboard grouping, never persisted.

So the daily job ran, matched nothing, and notified nobody — while reading as configured and enabled.

The fix, in the dialect the engine actually implements

I checked ScheduledFilterEvaluator before writing the replacement rather than copying an existing example. It supports exactly four operators — equals, notEquals, withinNext, olderThan — as a flat field => spec map with entries ANDed:

"filter": {
  "dueDate":    { "operator": "olderThan",  "value": "PT0S" },
  "taskStatus": { "operator": "notEquals", "value": "completed" }
}

Overdue is now derived by the filter instead of depending on a stored status no writer maintains.

⚠️ Worth knowing — the obvious precedent is itself broken. shillinq's ContractObligation.obligationDeadline uses {"all":[{"field":…,"operator":"notIn",…}]}. ScheduledFilterEvaluator has no all/any/notIn/before — it would read "all" as a field name, compare $objectData['all'] ?? null against an array, and never match. Had I copied it, I would have replaced one dead notification with another. Being reported separately, together with the validator gap that lets that shape through at save time.

2. ProxyAuthorization.signatureStatus defaulted outside its own enum

"default": "ongetekend" against enum: [unsigned, signed, refused], and disagreeing with the lifecycle's initial: unsigned. The enum and lifecycle were migrated; default, example and the prose were left in Dutch. Corrected all three.

The notification triggers on this schema already used the English values correctly, so nothing else was firing blind here.

Not changed (recorded so it is not lost)

Several long _note / description prose blocks in fragment 63 still narrate the state machine in Dutch (getekend/geweigerd). I corrected the lifecycle _note and the signatureStatus description — the two that document the machine this PR touches — and left the rest, since they are descriptive text with no runtime effect. The seed slug machtiging-alv-jansen-ongetekend is deliberately untouched (changing it would change object identity).

Context

Found during the ADR-098 fleet task inventory (ConductionNL/hydra#609).

…tover Dutch default

Two defects from the Dutch->English value rename, both silent.

1. actionOverdue could never fire. Its scheduled filter was {taskStatus:
   'overdue'} — a strict-equality shortcut against a status nothing in the app
   ever writes. ActionItemWriter::mapStatus() has no 'overdue' entry, and
   overdue-ness is derived at read time in ActionItemAnalyticsService instead.
   The daily job ran, matched nothing, and notified nobody.

   Replaced with the condition the app actually means, in the dialect
   ScheduledFilterEvaluator implements (equals|notEquals|withinNext|olderThan,
   entries ANDed): dueDate olderThan PT0S AND taskStatus notEquals completed.
   Overdue is now derived by the filter rather than depending on a stored
   status that no writer maintains.

2. ProxyAuthorization.signatureStatus defaulted to 'ongetekend', which is not
   in its own enum (unsigned|signed|refused) and disagrees with the lifecycle's
   initial state 'unsigned'. The enum and lifecycle were migrated by
   RenameDutchDecideskValues; default, example and the prose were left behind.

Refs #845
@rubenvdlinde
rubenvdlinde merged commit cedff83 into development Aug 22, 2026
76 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/dead-overdue-notification-and-enum-default branch August 22, 2026 10:37
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/decidiq @ 473320c

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-nav-ceiling
test-l10n
format
composer ✅ 104/104
npm ✅ 538/538
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-22 10:46 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.

The actionOverdue notification can never fire — it filters on a status nothing writes

2 participants