Skip to content

UI ops slice: retry & guardrail depth, audit rejections, July event vocabulary in the feed#217

Merged
richard-devbot merged 6 commits into
mainfrom
feat/ui-ops-156-215
Jul 6, 2026
Merged

UI ops slice: retry & guardrail depth, audit rejections, July event vocabulary in the feed#217
richard-devbot merged 6 commits into
mainfrom
feat/ui-ops-156-215

Conversation

@richard-devbot

@richard-devbot richard-devbot commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Part of #156 (the ops remainder: retry traces + guardrail depth on Alerts & Guardrails, feed rendering slot filled). Part of #215 (approval audit visibility + checkpoint / context-pressure / memory / metrics / retry-decision / goal events in the feed).

Not closed by this PR: #156's Command Center items (pipeline next-action, BLOCKED-task treatment on the stage strip) and schema-version visibility ship in the sibling command-center PR of this wave — coordinate there before closing #156.

What ships

state/feed.js — July event vocabulary (sole owner this wave)

  • First-class summaries + levels for: stage_checkpoint_before/after_saved (verified flag, warn when NOT verified), context_pressure_warning (detect-only wording per the [BLE-6.2] Add context pressure warnings #136 rule — never claims pruning), approval_audit_failed, episode_memory_written / episode_memory_skipped_untrusted, metrics_write_failed, retry_decision (BLOCKED/NEEDS_CONTEXT → blocked level), evaluator-shaped goal_evaluated (iteration + criteria counts; legacy status/score shape keeps its existing summary).
  • Each type carries a structured data object — only fields the event actually had — so the panels below render depth without a second data path.
  • Unknown event types keep degrading exactly as today: no summary, no line, never an invented one.

pages/live-feed.js — distinct glyphs + detail chips

CP / CX / AU / MB / MX / RT / GR / GL glyphs with one meta chip per line (limit vs value, size vs threshold, attempt n/m, audit issue count, verified flag). Everything else falls back to the shared feed row.

pages/alerts-guardrails.js — retry & guardrail depth (#156)

  • Retry State panel: per-task state (scheduled / budget exhausted / human input required) with attempt counts, decision + reason; BLOCKED tasks whose events scrolled out of the recent window are listed and say so.
  • Guardrail Triggers: limit name, value vs limit, blocked task, and an honest override status (no override on file / requested / approved by whom — one-shot semantics / consumed and re-armed).
  • Context Pressure Warnings: source, size vs threshold, detect-only note.

pages/approvals.js — Audit Rejections (#215, tampering visibility)

approval_audit_failed events render with artifact, reason, failed-check list, record id and claimed status, under plain copy: the record failed the consistency audit and was treated as absent — the gate stayed closed and the gated work did not proceed.

All panels self-mount once, state their empty case honestly, and fabricate nothing.

Ownership discipline

Only state/feed.js, pages/live-feed.js, pages/alerts-guardrails.js, pages/approvals.js, one appended /* [wave:ops] */ block in styles.js, and the new test file. No changes to lib.js, drawer.js, client.js core, other pages, or the state payload.

Verification

  • New tests/dashboard-ops-signals.test.js executes the real page renderers against a DOM stub (13 tests); full suite 668/668, lint, rstack-agents validate, security audit, git diff --check all green; the bundle-compile test stays green.
  • Verified live against the local fixture run (…-ui-fixture-july-signals) from this worktree: all eight glyph types in the Live Feed, the BLOCKED 005-testing task in Retry State (attempt 1, decision BLOCKED, budget exhausted), maxTaskAttempts 2/2 with "No override on file", memory_summary 61000 vs 40000 chars, and the forged guardrail-override:005-testing record in Audit Rejections.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Enhanced the live observability feed with event-specific glyphs, richer metadata chips, and ops-formatted details.
    • Expanded the Alerts & Guardrails page with Retry State, Guardrail Triggers (including override status), and Context Pressure Warnings panels.
    • Added an “Audit Rejections” panel to the approvals view.
    • Updated ops UI styling for panels, icons, notes, and fail-state cards.
  • Bug Fixes

    • Feed entries are omitted when no meaningful summary can be generated.
    • Improved severity/status labeling and ensured structured event details only include explicitly provided fields.

richardsongunde and others added 5 commits July 6, 2026 20:23
…s signals

Checkpoints (verified flag), context-pressure warnings (detect-only wording
per the #136 rule), approval audit rejections, episode-memory write/skip
decisions, metrics-write drift, retry decisions and evaluator-shaped
goal_evaluated events now get first-class feed summaries and levels.

Each of these types also carries a compact structured 'data' object (only
fields the event actually had — nothing fabricated) so the client panels can
render depth without a second data path. Unknown event types keep degrading
exactly as before: no summary, no feed line, never an invented one.

Part of #156 / #215.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…abulary

Checkpoint (CP), context pressure (CX), approval audit (AU), memory write
(MB), metrics drift (MX), retry (RT), guardrail (GR) and goal-loop (GL)
events now read at a glance in the Live Feed, each with one meta chip from
the event's structured data (limit vs value, size vs threshold, attempt
counts, audit issue count, verified flag). Types outside the map fall back
to the shared level-based feed row, so unknown events keep rendering as
today. Ships the append-only [wave:ops] styles block the ops panels share.

Part of #156 / #215.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ssure panels

Three self-mounting panels on Alerts & Guardrails, derived from the recent
server-composed event feed plus task/approval state already in the snapshot:

- Retry State: per-task retry_state (scheduled / budget exhausted / human
  input required) with attempt counts, the retry_decision verdict and reason;
  BLOCKED tasks whose retry events scrolled out of the window are still
  listed and say so instead of pretending to know why.
- Guardrail Triggers: limit name, value vs limit, the blocked task, and an
  honest override status line (none on file / requested / approved by whom /
  consumed and re-armed).
- Context Pressure Warnings: source, size vs threshold, and the detect-only
  note — nothing was pruned or truncated.

Every panel states its empty case plainly. Part of #156 / #215.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…re visible, never silent

approval_audit_failed events (#133's trust boundary) now render on the
Approvals page with the artifact, the audit's reason, the failed check list,
the record id and the status the record claimed. The panel copy says exactly
what happened: the record failed the consistency audit and was treated as
absent — the gate stayed closed and the gated work did not proceed. This is
the tampering-visibility surface for forged or corrupted approvals.

Part of #215.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… states

Executes the real page renderers (template-literal client code) against a
minimal DOM stub instead of only string-matching the source: feed lines +
levels + structured data for every July event type from fixture-shaped
events, unknown-type graceful degradation, the retry/guardrail/pressure
panels, override status variants (none / approved / consumed), the audit
rejections panel, honest empty states, and single-mount across re-renders.

Part of #156 / #215.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds ops-specific feed summaries, severity mapping, and structured data, then renders new dashboard panels for retries, guardrails, context pressure, and audit rejections with updated live-feed rows, styling, and tests.

Changes

Ops signals feed, panels, and styling

Layer / File(s) Summary
Ops event summary, structured data, and severity mapping
src/observability/dashboard/state/feed.js
Adds ops-specific summary generation and whitelisted structured data, then extends event severity mapping for retry, checkpoint, pressure, audit, memory, metrics, and goal events.
Live feed row rendering for ops events
src/observability/dashboard/ui/pages/live-feed.js
Adds icon mapping, ops metadata chips, and custom row HTML for mapped ops feed items, with fallback to the existing row renderer.
Retry state, guardrail trigger, and context pressure panels
src/observability/dashboard/ui/pages/alerts-guardrails.js
Adds the ops panels scaffold and renders retry state, guardrail triggers with override status, and context pressure warnings from feed and run data.
Audit rejections panel
src/observability/dashboard/ui/pages/approvals.js
Adds the audit rejections panel, renders approval_audit_failed items, and mounts it into the approvals page.
Ops panel styling
src/observability/dashboard/ui/styles.js
Adds ops-specific CSS for feed icons, metadata, notes, issue lists, and fail-state alert cards.
End-to-end ops signals tests
tests/dashboard-ops-signals.test.js
Adds fixture-driven tests for feed generation, live-feed rendering, alerts/guardrails panels, audit rejections, empty states, and repeated mounting.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

Poem

A rabbit peeks at ops at dawn,
With retries, guards, and warnings drawn.
The feed now speaks in glyphs so bright,
And audit crumbs are set in sight.
Hop hop—these panels feel just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main UI ops, audit rejection, and feed vocabulary changes in this PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ui-ops-156-215

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/observability/dashboard/ui/pages/alerts-guardrails.js (1)

24-40: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

.grid-2 gives Guardrail Triggers / Context Pressure an uneven 1.55fr/.85fr split.

.grid-2 (styles.js line 830) was built for asymmetric main-content/sidebar layouts elsewhere. Reusing it here for two co-equal panels will visually skew Guardrail Triggers wider than Context Pressure Warnings, which doesn't look like the intended peer-panel layout.

💡 Suggested fix
-  '<div class="grid-2" style="margin-top:16px">' +
+  '<div class="grid-2-even" style="margin-top:16px">' +
.grid-2-even { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; align-items: start; }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/observability/dashboard/ui/pages/alerts-guardrails.js` around lines 24 -
40, The two side-by-side panels in OPS_ALERTS_PANELS_HTML are using the shared
.grid-2 layout, which creates an uneven main/sidebar split instead of equal peer
columns. Update this markup to use a dedicated equal-width grid class for the
Guardrail Triggers and Context Pressure Warnings section, and keep the existing
panel structure unchanged so both panels render with the same width. Use the
OPS_ALERTS_PANELS_HTML constant as the anchor when making the layout swap.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/observability/dashboard/ui/pages/alerts-guardrails.js`:
- Around line 24-40: The two side-by-side panels in OPS_ALERTS_PANELS_HTML are
using the shared .grid-2 layout, which creates an uneven main/sidebar split
instead of equal peer columns. Update this markup to use a dedicated equal-width
grid class for the Guardrail Triggers and Context Pressure Warnings section, and
keep the existing panel structure unchanged so both panels render with the same
width. Use the OPS_ALERTS_PANELS_HTML constant as the anchor when making the
layout swap.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 13750464-b66e-4f49-9212-094008a586d9

📥 Commits

Reviewing files that changed from the base of the PR and between 29c0a6c and ab41e79.

📒 Files selected for processing (6)
  • src/observability/dashboard/state/feed.js
  • src/observability/dashboard/ui/pages/alerts-guardrails.js
  • src/observability/dashboard/ui/pages/approvals.js
  • src/observability/dashboard/ui/pages/live-feed.js
  • src/observability/dashboard/ui/styles.js
  • tests/dashboard-ops-signals.test.js

…ontract (#217 review)

The retry-decision surfaces read an `ev.decision` field the harness never
emits. The pinned #123 contract is { action, next_status, retry_recommendation,
attempt, max_attempts, reason, issues } — so on every real run the Live Feed
showed "Retry decision: ?" and the Retry State panel could label any BLOCKED
task with a fabricated cause.

- feed.js / live-feed.js / alerts-guardrails.js: rekey the retry summary,
  level, structured data and panel state onto action/next_status. Distinguish
  action:exhausted ("budget exhausted") from action:block ("validator blocked")
  — both carry next_status BLOCKED, so keying on status alone mislabels a
  validator block as budget exhaustion.
- goal_evaluated: drop the fictional recommendation/criteria_met shape; the
  real pipeline-loop.js emitter carries iteration/max_iterations/goal_id/
  status/score/failing_stages. Defer the summary to the shared plain-language
  path and read pass/fail from `status`.
- approvals / live-feed: count only array-shaped `issues` on forged
  approval_audit_failed records — hostile input never throws into the page.
- opsEnsureSection moves to the earliest-concatenated wave:ops module.
- tests: fixtures + assertions now use the real emitted shapes; add a
  regression proving a validator block is never labelled budget exhausted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/observability/dashboard/state/feed.js (1)

159-159: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fallback /^retry_/ branch likely unreachable given current vocabulary.

retry_decision is already handled and returned at Lines 151-158; task_retry_scheduled/task_retry_exhausted/task_human_context_required are handled above too and don't match ^retry_. This line only fires for some hypothetical future event type prefixed retry_ that isn't in the pinned contract — currently dead code, but harmless as a defensive catch-all.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/observability/dashboard/state/feed.js` at line 159, The /^retry_/
fallback in the event-to-severity mapping is effectively unreachable because
retry_decision and the known retry-related event types are already handled
earlier in the same logic. Remove this dead branch from the relevant classifier
function (the one processing ev.type and returning 'warn') unless you
intentionally want a future-proof catch-all, in which case keep it only with an
explicit comment explaining that it is defensive and not part of the current
contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/observability/dashboard/state/feed.js`:
- Around line 86-89: The retry feed data is stripping the issues field from
retry decision payloads before they reach the UI. Update the field lists used by
OPS_EVENT_DATA_FIELDS for retry_decision and the task_retry_* entries so they
include issues, and make sure the feed mapping in feed.js preserves that
property alongside the existing task_id, stage_id, attempt, action, next_status,
and reason fields.

---

Nitpick comments:
In `@src/observability/dashboard/state/feed.js`:
- Line 159: The /^retry_/ fallback in the event-to-severity mapping is
effectively unreachable because retry_decision and the known retry-related event
types are already handled earlier in the same logic. Remove this dead branch
from the relevant classifier function (the one processing ev.type and returning
'warn') unless you intentionally want a future-proof catch-all, in which case
keep it only with an explicit comment explaining that it is defensive and not
part of the current contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a53141e9-5ffa-4720-a3d1-0c75012fb542

📥 Commits

Reviewing files that changed from the base of the PR and between ab41e79 and 9afe51a.

📒 Files selected for processing (5)
  • src/observability/dashboard/state/feed.js
  • src/observability/dashboard/ui/pages/alerts-guardrails.js
  • src/observability/dashboard/ui/pages/approvals.js
  • src/observability/dashboard/ui/pages/live-feed.js
  • tests/dashboard-ops-signals.test.js
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/observability/dashboard/ui/pages/live-feed.js
  • src/observability/dashboard/ui/pages/approvals.js
  • tests/dashboard-ops-signals.test.js
  • src/observability/dashboard/ui/pages/alerts-guardrails.js

Comment on lines +86 to +89
// Pinned #123 emitter contract: { task_id, stage_id, attempt,
// max_attempts, retry_recommendation, action, next_status, reason,
// issues[] } with action ∈ complete|retry|exhausted|human_context|block.
return `Retry decision for ${ev.task_id ?? 'task'}: ${ev.action ?? '?'}${ev.next_status ? ` → ${ev.next_status}` : ''}${ev.reason ? ` — ${ev.reason}` : ''}`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant file and search the retry/issue paths.
git ls-files src/observability/dashboard/state/feed.js src/observability/dashboard/state/live-feed.js src/observability/dashboard/alerts-guardrails.js

printf '\n--- feed.js outline ---\n'
ast-grep outline src/observability/dashboard/state/feed.js --view expanded || true

printf '\n--- live-feed.js outline ---\n'
ast-grep outline src/observability/dashboard/state/live-feed.js --view expanded || true

printf '\n--- alerts-guardrails.js outline ---\n'
ast-grep outline src/observability/dashboard/alerts-guardrails.js --view expanded || true

printf '\n--- feed.js relevant lines ---\n'
nl -ba src/observability/dashboard/state/feed.js | sed -n '100,180p'

printf '\n--- live-feed.js issue references ---\n'
rg -n "issues|retry_decision|task_retry_|approval_audit_failed" src/observability/dashboard/state/live-feed.js src/observability/dashboard/alerts-guardrails.js src/observability/dashboard/state/feed.js

Repository: richard-devbot/SDLC-rstack

Length of output: 887


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- files matching observability/dashboard ---\n'
git ls-files | rg '^src/observability/dashboard/'

printf '\n--- retry / issues references under observability ---\n'
rg -n "retry_decision|task_retry_|approval_audit_failed|issues" src/observability/dashboard

printf '\n--- feed.js whitelist section ---\n'
sed -n '110,150p' src/observability/dashboard/state/feed.js

Repository: richard-devbot/SDLC-rstack

Length of output: 255


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- files matching src/observability/dashboard ---'
git ls-files | rg '^src/observability/dashboard/' || true

echo
echo '--- retry / issues references under src/observability/dashboard ---'
rg -n "retry_decision|task_retry_|approval_audit_failed|issues" src/observability/dashboard || true

echo
echo '--- feed.js whitelist section ---'
python3 - <<'PY'
from pathlib import Path
p = Path('src/observability/dashboard/state/feed.js')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 108 <= i <= 150:
        print(f"{i:4d}: {line}")
PY

Repository: richard-devbot/SDLC-rstack

Length of output: 10084


issues is missing from retry feed data. OPS_EVENT_DATA_FIELDS drops issues for retry_decision and the task_retry_* entries, so any retry payload carrying validator-block detail loses it before the feed reaches the UI. Add issues to those field lists if the retry panels are meant to surface that contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/observability/dashboard/state/feed.js` around lines 86 - 89, The retry
feed data is stripping the issues field from retry decision payloads before they
reach the UI. Update the field lists used by OPS_EVENT_DATA_FIELDS for
retry_decision and the task_retry_* entries so they include issues, and make
sure the feed mapping in feed.js preserves that property alongside the existing
task_id, stage_id, attempt, action, next_status, and reason fields.

@richard-devbot richard-devbot merged commit 1fc07b8 into main Jul 6, 2026
7 checks passed
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.

2 participants