Skip to content

feat(flare-workflow): instance/step metrics query layer (workflow_metrics) - #509

Merged
getappz merged 3 commits into
masterfrom
task/128-flare-workflow-instance-step-metrics-que
Aug 15, 2026
Merged

feat(flare-workflow): instance/step metrics query layer (workflow_metrics)#509
getappz merged 3 commits into
masterfrom
task/128-flare-workflow-instance-step-metrics-que

Conversation

@getappz

@getappz getappz commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Working tree is clean and the commit is in place.

Summary

The implementation from the prior (interrupted) run was already complete and correct against the design spec — it just hadn't been committed due to a git invocation failure. I verified it against all 8 acceptance criteria, fixed one trivial clippy warning (20 + 40 + 020 + 40 in the test), and committed:

  • Migration: added duration_ms/input_tokens/output_tokens columns to step_state (5th M::up), and write_state's UPSERT now writes them.
  • Types: MetricsFilter, WorkflowMetrics, StepMetrics in types.rs, plus Hash derives on WorkflowStatus/StepStatus needed for HashMap keys.
  • StateStore trait: new workflow_metrics(&self, filter: MetricsFilter) -> WorkflowResult<WorkflowMetrics>.
  • SqliteStore: real SQL aggregation (GROUP BY status/step_id, status with a shared WHERE builder for the filter) — no full-row JSON deserialization.
  • InMemoryStore: mirrors the same signature via in-memory iteration.
  • WorkflowEngine::metrics: thin passthrough to the store, no CLI/HTTP/GraphQL surface added.
  • Tests: new tests/metrics_test.rs (3 tests) covering mixed-status aggregation, step breakdown/averages, workflow_id scoping, and the empty-store case.

Full crate test suite (70 tests across all test files) and cargo clippy --all-targets both pass clean. Confirmed no other crate implements StateStore (only imports the trait), so the new trait method doesn't break anything downstream.

Add MetricsFilter/WorkflowMetrics/StepMetrics types, a workflow_metrics
method on StateStore (SqliteStore via GROUP BY aggregation, InMemoryStore
by iterating the map), and a thin WorkflowEngine::metrics passthrough.

SqliteStore migration adds duration_ms/input_tokens/output_tokens columns
to step_state so per-step aggregates don't require deserializing run JSON.

Agentflare-Agent: claude-code
Agentflare-Branch: task/128-flare-workflow-instance-step-metrics-que
Agentflare-Item: 128
@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1ad795e-aaf3-44b2-a913-89ae9d203820

📥 Commits

Reviewing files that changed from the base of the PR and between ca0d591 and f2cdfae.

📒 Files selected for processing (5)
  • crates/flare-workflow/src/engine.rs
  • crates/flare-workflow/src/sqlite_store.rs
  • crates/flare-workflow/src/store.rs
  • crates/flare-workflow/src/types.rs
  • crates/flare-workflow/tests/metrics_test.rs
✨ 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 task/128-flare-workflow-instance-step-metrics-que

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

@getappz getappz changed the title flare-workflow: instance/step metrics query layer (workflow_metrics) feat(flare-workflow): instance/step metrics query layer (workflow_metrics) Aug 15, 2026
shiva and others added 2 commits August 15, 2026 20:20
Agentflare-Agent: claude-code
Agentflare-Branch: task/128-flare-workflow-instance-step-metrics-que
Agentflare-Item: 128
@getappz
getappz merged commit 70bd076 into master Aug 15, 2026
16 checks passed
@getappz
getappz deleted the task/128-flare-workflow-instance-step-metrics-que branch August 15, 2026 14:59
getappz added a commit that referenced this pull request Aug 16, 2026
* feat(workflow): surface instance/step metrics via CLI and MCP

The workflow_metrics query layer (PR #509) had no caller outside
flare-workflow's own tests -- no CLI command, MCP action, or
dashboard route ever called engine.metrics(). Debugging a failing
pipeline meant hand-querying workflows.db directly.

Add `agentflare workflow metrics` and the MCP `workflow` tool's
`metrics` action, both wired to the existing engine.metrics()/
StateStore::workflow_metrics() layer, with --workflow-id/--status/
--since filters.

Metrics alone only gives counts, not the actual error text, so
also add a recent_failures list: the most recent failed runs with
their failing step and its real last_error message. This queries
workflow_runs/step_state directly by raw SQL rather than through
StateStore::list_all::<D>() -- the store is shared by several
WorkflowData types (PipelineData, WorkItemData, ...), and
deserializing through a fixed D silently skips every run of a
different type, same class of bug as the list_active/list_all fix.
workflow_metrics's own SQL aggregation already takes this same
type-agnostic approach for the same reason.

Agentflare-Agent: claude-code_2-1-233_agent
Agentflare-Branch: feat/workflow-metrics-surfacing

* fix(workflow): status hard-fails for any run not typed PipelineData

agentflare workflow status / mcp__flare__workflow(action="status")
went through engine.get_status -> StateStore::load::<PipelineData>,
which hard-fails for a run of any other WorkflowData type (e.g. the
internal SDD work-item pipeline's WorkItemData) with "storage
error: deserialize state: invalid type: map, expected unit struct
PipelineData". Reproduced live against a real agentflare-work-item
run while narrowing metrics down to a single job.

Every field this view reports (run_id, workflow_id, status,
current_step, step_states, input, output, error, variables) lives
outside context.data, so read the raw state_json generically via
serde_json::Value instead of through the typed store -- same
reasoning as recent_failures_async's raw-SQL query in the prior
commit.

Agentflare-Agent: claude-code_2-1-233_agent
Agentflare-Branch: feat/workflow-metrics-surfacing

* fix(workflow): address CodeRabbit review findings on #517

- recent_failures_async's LIMIT bounded the joined run x
  failed-step rows, not distinct runs -- a run with several failed
  steps (fan-out) could crowd out more recent failed runs. Bound
  the run-level query first, then join to failed step states.
- Its since filter checked updated_at; MetricsFilter's since means
  created_at (sqlite_store::metrics_where). Match that semantics.
- Both raw-SQL helpers opened a bare Connection with no
  busy_timeout, unlike agentflare-db-kit::open_file, and ran
  synchronously on the calling async runtime. Add the same
  5-second busy_timeout and move the blocking work into
  spawn_blocking.
- Extend workflow_metrics's test with workflow_id/since filter
  cases (matching and non-matching) and invalid-input cases,
  exercising recent_failures_async's parameter binding order.

Agentflare-Agent: claude-code_2-1-233_agent
Agentflare-Branch: feat/workflow-metrics-surfacing
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.

1 participant