6.11.3 Schema + the read-exclusion-everywhere invariant
Estimate: 70m · Depends on: 6.11.2
⚠️ Partially superseded (Yue, 2026-06-14). The externalSubmitter embedded columns added here are now dead — intake is signed-in only, so attribution is always a real submittedByUserId. The columns remain in the DB until 6.11.10 drops them (ADR amend + migration); this card kept as the record of what shipped. submittedByUserId + snoozedUntil + the exclusion invariant are unchanged.
Implement the triage marker on work_item and enforce the exclusion invariant across EVERY normal read (the load-bearing correctness work of this story). Per 6.11.2:
- Schema: add the
triagemarker (atriagedAt: DateTime?/isTriagecolumn per the ADR) +snoozedUntil: DateTime?+ the submitter-attribution columns (submittedByUserIdnullable@relation;externalSubmitterembedded fields) towork_item, with a migration and a partial index supporting the cheap exclusion predicate + the queue read. Model every FK as a Prisma@relation(CLAUDE.md migration rule — no raw-SQL-only FK). - Central exclusion: thread a single shared "not-in-triage"
wherefragment (or a repository default scope) through EVERY normal list read so the predicate is defined once: the issue tree, every board column read, every list/saved-view read, the ready-set read, and the 6.1.1 FilterAST search compilation. A triage item (and a snoozed item, in the inbox sense) is absent from all of them. - The queue read: a new repository read + service method returning ONLY triage items for a project, paginated/cursor’d (finding #57 — never load-all), excluding currently-snoozed items, newest-first, with submitter attribution.
All reads stay 4-layer (Route→Service→Repository→Prisma); the queue and exclusion live in the repository read layer so no future read can bypass them.
Acceptance criteria
- The migration adds the triage marker + snooze + submitter columns with the supporting index;
prisma migrate devreports no drift (every FK modelled as@relation). - The exclusion predicate is defined ONCE and applied to the tree, every board read, every list read, the ready set, and FilterAST search — verified by the 6.11.8 tests at each read.
- The triage-queue read returns ONLY triage items for the project, paginated, excluding snoozed items, with submitter attribution; no load-all.
- 4-layer respected; no raw Prisma outside repositories; the queue read goes through a service.
Context refs
- 6.11.2 — the model decision this implements (marker shape + the reads-to-exclude checklist).
motir-core/lib/repositories/workItemRepository.ts+ the tree / board / ready-set read paths — where the shared exclusion fragment threads in.- 6.1.1 FilterAST search compiler — the search read to extend with the exclusion.
motir-core/CLAUDE.md§ 4-layer + § migration FK-as-relation rule.