feat(s-escalate2): a second (final) escalation tier → Top Management#300
Merged
Conversation
Tier-2 escalate_2 at +3 business days past due → Top Management role (→ QMS Owner floor), reusing the task-timer machinery. BE-only, migration 0069 (escalate_2_after / escalated_2_at + global task.escalated_final template seed). Owner-ratified policy: recipient + timing; DOC_ACK/PERIODIC_REVIEW carve-out preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6 tasks: migration 0069 + ORM mirrors → timer.py ESCALATE_2 step → event wiring (constants/classes) → claim disjunct → escalation.py tier-2 dispatch (Top Management → QMS floor) → verification + live-smoke. TDD steps with copy-pasteable code; blast-radius + cross-test-leak handled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ric with due_steps)
….escalated_final + tier audit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-2 QM-fallback test test_escalate_2_qm_fallback asserted via=="qm_fallback" but required zero Top Management role-holders in the shared default org — a shard-composition-dependent precondition that other integration files (test_capa / *_authorization) violate by leaking un-cleaned SYSTEM-scoped assignments. Fixed by clearing any leaked Top Management RoleAssignment rows at test-top before seeding the scenario, self-providing the precondition per engineering-patterns. Also adds a clarifying comment to TimerPolicy.escalate_2_after explaining the = None default is deliberate (existing constructors stay valid; production sites wire by keyword). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5759ce3c8c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… valid recipient Codex P1: resolve_escalation_2_recipients returned non-empty-but-all-invalid Top Management ids, so the dispatch loop dropped them (attempted==0), stamped escalated_2_at as a terminal no-op, and silently never escalated even with an active QMS Owner. Fall through to the QM floor on "no VALID Top Management recipient" (mirrors the tier-1 manager→QM fallthrough; honors the spec's "always delivers" intent). + a mutation-distinguishing integration test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CoJoA13
added a commit
that referenced
this pull request
Jun 26, 2026
- slice-history.md: full per-slice narrative under NOTIFICATIONS (newest-first) + migration head → 0069. - CLAUDE.md: Recent-learnings bullet (oldest S-notify-5b demoted to the trimmed index to hold the ~8 cap) + Current-status escalate_2 pointer + head → 0069 (next 0070). - dev-workflow.md: the "full -m integration isn't a clean local gate on this box" note (pg_dump host-missing + single-DB Organization/mirror pollution → use scoped runs + CI shards). No code change. Co-authored-by: Claude Opus 4.8 (1M context) <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.
S-escalate2 — a second (final) escalation tier
When an escalation-enabled task stays unactioned to +3 business days past due, fire a distinct
task.escalated_finalnotification to the Top Management role (→ QMS Owner floor), reusing the existing task-timer sweep. BE-only; migration 0069. Closes the namedescalate_2residual.Changes
sla_policy.escalate_2_after(Interval) +task.escalated_2_at(timestamptz), seeds a globaltask.escalated_finaltemplate, and setsescalate_2_after = INTERVAL '3 days'for escalate-enabled policies (WHERE escalate_1_after IS NOT NULLcarve-out keeps DOC_ACK / PERIODIC_REVIEW tier-2-free). RESTRICT-FK-guarded downgrade; ORM mirrors.timer.py—TimerStep.ESCALATE_2+ adue_stepsAFTER-direction branch (reusesbusiness_threshold,now_is_working-gated, chronologically last).escalation.py— a 5th policy-aware_due_task_idsclaim disjunct (symmetric withdue_steps);resolve_escalation_2_recipients(Top Management → QMS Owner floor); a tier-2 dispatch branch emittingtask.escalated_final+ aTASK_ESCALATEDaudit carrying atierdiscriminator (tier:1/tier:2).constants.py/classes.py—task.escalated_finalevent key + variable whitelist + CRITICAL class (pierces quiet hours).Design notes
task.escalated_final(nottask.escalated) — the(recipient, task_id, event_key)dedup would otherwise collapse a 2nd escalation onto tier-1 (the S-remind2 lesson).app_user.manager_idis unpopulated in practice; QMS Owner is the always-delivers floor.due_stepssymmetry preserved — the claim is a strict superset of the firing condition (can only DELAY, never DROP a real tier-2) and configured-offset-gated (no S-claim-filter re-claim churn). The carve-out keepsescalate_2_after = NULLfor DOC_ACK / PERIODIC_REVIEW.Verification
pytest -m unit1071 · web 1292 (unchanged — BE-only).checkclean on a throwaway PG16. Seed live-smoke confirmed the carve-out:escalate_2_after = 3 daysfor the 10 escalate-enabled types, NULL for DOC_ACK / PERIODIC_REVIEW; guarded downgrade drops the column + template cleanly.test_capa→test_escalate_2_qm_fallback).Tests: api unit +8 (6 timer + 2 classes), +3 integration (tier-2 wiring, QM fallback, claim positive-control). Migration head 0069.
🤖 Generated with Claude Code