Trouble ticket status workflow: transition events, commands, projections - #299
Merged
Merged
Conversation
Wires runTroubleTicketIngest into the sync worker's existing 20-minute trouble-ticket beat, guarded by the SAFETY comment: this must not deploy until the one-time timeline backfill has run and been verified on prod, because the append path claims each row's hash at recordedAt = now. Repoints the /trouble-tickets POC page from the sheet cache to the troubleTickets read model (still super-user only, still windowed to 6 months), rendering the parsed answers as labelled lines instead of the double-stringified JSON blob. The sheet cache stays: it remains the ingestion source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The /trouble-tickets repoint left deps.getTroubleTicketData unread by any production code; drop the field and its wiring (the underlying function stays - the sync worker path and tests use it directly). Also reword the ingest driver's comment, which still claimed it wasn't wired into the sync worker. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-applied from the stale feature/trouble-tickets-status branch onto the new events foundation. Six transition events (Assigned, Resolved, Parked, NeedsHelp, EquipmentSet, TitleEdited), each strict-codec'd with its required context. Transition rules in the projection: assignment moves Todo/Needs Help/Parked tickets to In Progress (multi-assignee), resolving clears assignees, needs-help unassigns the flagging trainer, parking keeps assignees. Authorization: assign/resolve/park/needs-help require a trainer on the ticket's equipment (or admin/super user); title edits require an area owner; set-equipment accepts an owner of either the current or target equipment. Status actions get GET confirmation forms via the shared troubleTicketActionForm factory; create/set-equipment/edit-title are API-only. The seed-oriented create command is adapted to the value-based row hash. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Audit findings: - The GET confirmation pages for assign/resolve/park/needs-help rendered the ticket title (submitter free text) to any logged-in member. They now enforce the same isTicketTrainer rule as the actions themselves, checked before the existence lookup so unauthorized viewers cannot probe ticket ids. Covered by tests. - The seed-oriented create command claimed idempotency its time-based rowHash could not deliver; it now dedups by ticket id (and gets its missing test). - populate-local-dev.sh seeds two tickets (one resolved to the Metal Lathe, one Unassigned); CLAUDE.md's API endpoint list caught up with reality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JamesMoulang
force-pushed
the
feature/tt-status
branch
from
September 21, 2026 07:57
f28e8a3 to
554191c
Compare
JamesMoulang
force-pushed
the
feature/tt-poller
branch
from
September 21, 2026 07:57
e6fc801 to
f6bdedd
Compare
An old sync bug left rows with every column NULL; the sheet_id-scoped cache replacement can never delete them (NULL never matches =), so prod carried 542 of them forever and the ingest would warn about them every cycle. Sweep them in the same atomic batch as the cache update. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #298. The status workflow, re-applied from the stale
feature/trouble-tickets-statusbranch onto the new event foundation (the stale branch pre-dated the quiz migration and could not be merged directly).TroubleTicketAssigned,Resolved(summary),Parked(why/path/intermediate actions),NeedsHelp(what was tried/why it didn't work),EquipmentSet,TitleEdited.InconsistentEventError.src/commands/trouble-tickets/authorization.ts): status actions need a trainer on the ticket's equipment (or admin/super user) — an Unassigned ticket has no trainers, so only admins can act until an owner sets its equipment; title edits need an area owner; set-equipment accepts an owner of either current or target equipment.command()(confirmation form + POST) for assign/resolve/park/needs-help via the sharedtroubleTicketActionFormfactory;api()(bearer only) for create/set-equipment/edit-title. The seedcreatecommand is adapted to the value-based row hash from Record trouble tickets as events: event, command, projection, ingest driver #296.tests/commands/trouble-tickets/commands.test.ts) and the full transition matrix (tests/read-models/shared-state/trouble-tickets-status.test.ts).Next in the stack: the board UI, then status-change email notifications.
🤖 Generated with Claude Code