feat(observability): issue triage workflow + durable log read-back - #154
Conversation
Add a persisted per-Issue triage state (__lunora_issue_state__), keyed by fingerprint hash, and fold it into the derived getIssues read: status (open/resolved/ignored), assignee, and severity. A resolved Issue that errs again after the resolution auto-reopens to open (regression); ignored stays sticky. Four admin RPCs (resolveIssue/ignoreIssue/assignIssue/setIssueSeverity) upsert the state and flush so the live Issues subscription re-folds. The studio Issues panel gains a status filter, status/severity badges, an assignee input, and per-row action buttons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
Add createPipelineLogReader over the Iceberg table @lunora/bindings/r2sql queries, with keyset pagination and level/function/trace/shard/user filters, and wire a `lunora logs --durable` mode to consume it. observability-sinks documents the written-column contract as the read-side mirror and gains an opt-in serializeFields. The pipelineLogSink is no longer write-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
✅ Deploy Preview for lunorash ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Warning Review limit reached
Next review available in: 6 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (11)
📒 Files selected for processing (1)
WalkthroughThis PR adds R2 SQL-backed durable log archive reading through runtime APIs and the CLI, documents archive setup, and introduces persisted issue triage with admin RPCs, status filtering, and Studio controls. ChangesDurable log archive
Issue triage workflow
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Operator
participant DurableLogsCLI
participant PipelineLogReader
participant R2SQL
Operator->>DurableLogsCLI: run lunora logs --durable
DurableLogsCLI->>PipelineLogReader: submit filters and cursor
PipelineLogReader->>R2SQL: execute escaped SQL query
R2SQL-->>PipelineLogReader: ordered log page
PipelineLogReader-->>DurableLogsCLI: rows and nextCursor
DurableLogsCLI-->>Operator: table or NDJSON output
sequenceDiagram
participant IssuesPanel
participant ShardDO
participant IssueStateTable
IssuesPanel->>ShardDO: resolve, ignore, assign, or set severity
ShardDO->>IssueStateTable: upsert issue state
IssueStateTable-->>ShardDO: updated state
ShardDO-->>IssuesPanel: triage result
IssuesPanel->>ShardDO: request issues with status filter
ShardDO-->>IssuesPanel: filtered issues with persisted triage fields
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
Thank you for following the naming conventions! 🙏 |
|
Thank you for confirming the Contributor License Agreement! 🙏 |
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@packages/do/src/issue-state.ts`:
- Around line 123-144: Update readIssueStates to process hashes in batches of no
more than 100 parameters, executing one query per batch and merging each
hydrated row into the existing states Map. Preserve the empty-input early return
and ensure all requested hashes are covered without exceeding the parameter
limit.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 28e29cac-ffc9-4e76-96f7-fbeb00bfd5c4
⛔ Files ignored due to path filters (6)
packages/do/__tests__/issue-state.test.tsis excluded by!**/__tests__/**,!**/*.test.tsand included bypackages/**packages/do/__tests__/request-log.test.tsis excluded by!**/__tests__/**,!**/*.test.tsand included bypackages/**packages/runtime/__tests__/observability-sinks.test.tsis excluded by!**/__tests__/**,!**/*.test.tsand included bypackages/**packages/runtime/__tests__/pipeline-log-reader.test.tsis excluded by!**/__tests__/**,!**/*.test.tsand included bypackages/**packages/studio/__tests__/features/issues/issues-panel.test.tsxis excluded by!**/__tests__/**and included bypackages/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yamland included by none
📒 Files selected for processing (16)
apps/docs/src/content/docs/concepts/observability.mdxpackages/cli/package.jsonpackages/cli/src/commands/logs/durable.tspackages/cli/src/commands/logs/handler.tspackages/cli/src/commands/logs/index.tspackages/do/src/introspect.tspackages/do/src/issue-state.tspackages/do/src/request-log.tspackages/do/src/shard-do.tspackages/runtime/package.jsonpackages/runtime/src/index.tspackages/runtime/src/observability-sinks.tspackages/runtime/src/pipeline-log-reader.tspackages/studio/src/features/issues/issues-panel.tsxpackages/studio/src/lib/admin.tspackages/studio/src/locales/en.ts
Merging this PR will degrade performance by 0.39%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ❌ | sum merge: 4 scalars |
1.4 ms | 1.8 ms | -19.41% |
| ⚡ | union: single UNION-ALL probe across all tables |
235.3 µs | 212.2 µs | +10.87% |
| ⚡ | baseline (Object.keys + toInternal + path spread per field) |
72 µs | 65.1 µs | +10.63% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing feat/observability-followons (3900efc) with alpha (b16cc0e)
Footnotes
-
1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports. ↩
Durable Objects SQLite caps bound parameters at 100 per query. A shard with >100 distinct issue fingerprints would blow the cap on the single `WHERE hash IN (?…)` read, failing getIssues. Read in 100-hash chunks and merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
The astro template is on `astro@^7.1.3` but LATEST_MAJORS still pinned the guard to 6, reddening the templates suite. Bump the guard to match the template. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
These landed via #151 (merged into this branch) with unwrapped prose that `prettier --check .` rejects, reddening the repo-wide prettier pipe. Format-only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
Records the intended surface additions: the four issue-triage ADMIN_FUNCTIONS + issue types (do, studio), and createPipelineLogReader / DEFAULT_LOG_COLUMNS + types (runtime, re-exported by lunora). Additions only, no removals. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0197KjhmBDB3PXAc6TXiPqZ9
Finishes the two actionable observability follow-ons from the gap analysis. (The third — cloud-side trace/log viewers — is blocked:
apps/cloudisn't onalphayet, so there's nothing to wire the viewers into.)1. Issue triage workflow (
@lunora/do+@lunora/studio)Issues were read-only groupings. Now they carry persisted triage state.
__lunora_issue_state__(packages/do/src/issue-state.ts), keyed by fingerprinthash:status(open/resolved/ignored),assignee,severity,updated_at/by.ensureIssueStateTable/readIssueStates(batchedWHERE hash IN (…)) /upsertIssueState(partial-patchCOALESCE, explicit-nullclears).getIssues(readErrorIssues): each derived Issue joins its state. Auto-reopen — aresolvedIssue that errs again after the resolution surfaces asopen(a regression never hides behind a stale resolve);ignoredstays sticky. Astatusfilter is applied after the fold.resolveIssue/ignoreIssue/assignIssue/setIssueSeverity— upsert the state, mark the table changed, and flush so the live admin-wildcard Issues subscription re-folds. Gated by the existingLUNORA_ADMIN_TOKENbearer.2. Read the durable
pipelineLogSinkback (@lunora/runtime+@lunora/cli)The pipeline log sink was write-only.
createPipelineLogReader(packages/runtime/src/pipeline-log-reader.ts) queries the Iceberg table via@lunora/bindings/r2sqlwith keyset pagination (ts DESC) and level / function / trace / shard / user filters.observability-sinks.tsnow documents the written-column contract as the read-side mirror and gains an opt-inserializeFields.lunora logs --durableconsumes it (added as a mode on the existinglogscommand, so no command clashes).Tests
@lunora/do: issue-state (6) + request-log fold/auto-reopen/filter cases + shard-do admin — 131 green.@lunora/studio: issues-panel (7) + unit (190) + app-level (28) green.@lunora/runtime: pipeline-log-reader (17) + observability-sinks (57) green.@lunora/cli: logs (5) green.lint:typesclean, eslint clean (--max-warnings=0).🤖 Generated with Claude Code
Summary by CodeRabbit