Skip to content

fix(views): a resolved case is not at risk — sla_at_risk selects on live work - #1331

Merged
os-trump merged 1 commit into
mainfrom
claude/issue-1325-sla-at-risk-live-work
Aug 26, 2026
Merged

fix(views): a resolved case is not at risk — sla_at_risk selects on live work#1331
os-trump merged 1 commit into
mainfrom
claude/issue-1325-sla-at-risk-live-work

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes #1325

Description

The ⏰ SLA at Risk tab selected on is_closed == false. That flag is derived by
case_sla_defaults as effStatus === 'closed' (src/objects/case.hook.ts) and never
flips on resolved — while case_sla_monitor, the flow that owns SLA breach
detection, has always filtered status: { $nin: ['resolved', 'closed'] }
(src/flows/case-sla-monitor.flow.ts).

So the two surfaces disagreed about the same case: the sweep would not flag a resolved
case as breached, and the tab still listed that case for a service agent to pick up. An
agent working the queue could be handed work the automation that owns SLA had already
decided was finished. That is the surface a human reads contradicting the surface that
acts — a defect, not an untidiness, and this is the distinction that separates it from
the sibling views.

The view now carries the predicate the producer already answered with, spelled in the
view layer as operator: 'not_in'. $nin is the lowered AST form and is not
authorable in a view filter[]; parseFilterAST(['status','not_in',[...]]) lowers to
exactly { status: { $nin: [...] } }.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Related Issues

Changes Made

  • src/views/case.view.tssla_at_risk selects on
    { field: 'status', operator: 'not_in', value: ['resolved', 'closed'] }. The priority
    half (high / critical) is unchanged.
  • test/live-work-predicate-parity.test.tsthe two-sided edit the guard requires.
    sla_at_risk moves out of the boundary roster (NOT_LIVE_WORK) and into the consumer
    roster (LIVE_WORK_CONSUMERS), and is added to the is_closed offender sweep. The
    boundary roster's header records why this one entry left it and why the remaining three
    must not follow it on the strength of this PR.
  • test/sla-at-risk-live-work.test.ts — new behavioural half.
  • .changeset/sla-at-risk-is-live-work.md — a real changeset: this narrows what an
    author-visible tab shows.

Testing

Gate chain pnpm verify green on cd5620a (the commit this PR is opened at):
validate, typecheck, lint, lint:i18n-gate, hygiene, hygiene:tokens, build,
test142 test files passed, 2993 passed / 1 skipped.

pnpm hygiene:tokens is green and the interaction layer is unmoved in the way that
matters to #1321: interaction layer ~37,431 tokens (ceiling ~40,000; headroom ~2,569).

The behavioural pin runs the SHIPPED view filter, lowered through the platform's own
parseFilterAST, against a real engine on both drivers (driver-memory, which stores
only written columns, and sqlite-wasm, which materialises every declared column — the
absent-vs-NULL axis a boolean gets wrong). Its fixture does not assert is_closed — it
runs the shipped case_sla_defaults handler through test/helpers/hook-harness.ts and
stores what the app itself derives, so "would otherwise qualify" is a measurement rather
than a fiction of the test. A dedicated case then proves that claim by running the OLD
is_closed == false spelling over the same rows and showing the resolved case coming
back.

Reverse-verification. The filter was reverted on a committed tree, the mutation was
proven to have reached disk before any verdict was read (git hash-object moved
52e5c65b1e6140; the anchor matched exactly once; the on-disk line counts moved as
predicted), and the guard went red naming this consumer in three separate assertions
rather than merely red:

  • every named consumer resolvessla_at_risk (view filter[] — src/views/case.view.ts)
  • sla_at_risk excludes exactly CLOSED_CASE_STATUSESexpected [] to deeply equal [ 'closed', 'resolved' ]
  • no live-work consumer keys the concept on is_closedsla_at_risk (view filter)

plus both driver blocks of the behavioural half:
expected [ 'live-critical', 'resolved-high' ] to not include 'resolved-high'.

The tree was then restored with git checkout HEAD -- PATH (the bare form restores from
the index, which is the mutation) and the restore proven byte-identical: git diff HEAD
empty and the blob hash back to 52e5c65.

One earlier run of that same procedure stopped rather than reporting, because the
predicted on-disk line count did not match. The mutation had in fact landed; the
expectation was miscalibrated (one of the three is_closed filters is written on a single
line and never matched the indented pattern). Recorded because the stop is the reason the
reading above can be trusted.

  • Unit tests pass
  • Linting passes
  • Build succeeds
  • New tests added

Checklist

  • I have added a changeset
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes

Additional Notes

Deliberately out of scope, each for a different reason:

The scope of this PR is one view. It is the one entry on that boundary roster that turned
out not to be a judgement call, because a producer had already answered the same question.

Generated by Claude Code


Generated by Claude Code

…ive work

`sla_at_risk` selected on `is_closed == false`. That flag is derived as
`effStatus === 'closed'` and never flips on `resolved`, while
`case_sla_monitor` — the flow that OWNS SLA breach detection — has always
filtered `status: { $nin: ['resolved', 'closed'] }`.

The two surfaces therefore disagreed about the same case: the sweep would not
flag a resolved case as breached while the tab still listed it for an agent to
work. The view now carries the same predicate the producer already answered
with, spelled in the view layer as `status not_in ['resolved', 'closed']`
(`$nin` is the lowered AST form and is not authorable in a view filter).

`sla_at_risk` moves from the boundary roster of
`test/live-work-predicate-parity.test.ts` into its consumer roster in the same
change, which is what that guard's by-name design requires.
`test/sla-at-risk-live-work.test.ts` adds the behavioural half on both drivers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ED4cusQ7pxZ7d7TCLKrZb
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hotcrm Ignored Ignored Aug 26, 2026 7:53am

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

2 participants