Skip to content

feat(tools): add the stage performance statistics CLI (amadeus-stage-stats) - #2448

Merged
j5ik2o merged 9 commits into
mainfrom
bolt-stage-stats-cli
Aug 8, 2026
Merged

feat(tools): add the stage performance statistics CLI (amadeus-stage-stats)#2448
j5ik2o merged 9 commits into
mainfrom
bolt-stage-stats-cli

Conversation

@j5ik2o

@j5ik2o j5ik2o commented Aug 7, 2026

Copy link
Copy Markdown
Member

概要

ステージ実行パフォーマンスレポート CLI amadeus-stage-stats.ts を新設する(intent 260807-stage-perf-report、Bolt 1 = walking-skeleton ゲート付き)。監査シャード 2 世代の正規化読取・idle 減算による net 実作業時間・§12a レビューイテレーション集計・センサー FAILED 率・モデル帰属を、Markdown / CSV / --json の 3 形で決定的に出力する read-only ツール。

Refs #2405(クローズは intent 完了時の着地確認後)

変更内容

  • packages/framework/core/tools/amadeus-stage-stats.ts(新規、944 行)— 依存は node:fs(read)/ node:path / amadeus-journal.ts のみ(readJournalRecords/journalRecordField を再利用、第 3 の正規化実装なし)。export function main(argv) + import.meta.main(in-process seam)
  • tests/unit/t486-stage-stats.test.ts(55 tests / 126 assertions — 純関数のみ)
  • tests/integration/t487-stage-stats.integration.test.ts(15 tests / 70 assertions — 実 FS fixture + spawn exit ladder 実測 + fs write API import 0 件検査)
  • tests/.coverage-registry.json / tests/.coverage-ratchet.json 再生成

検証(実測 exit code)

  • typecheck 0 / lint 0 / t486+t487 = 70 pass 0 fail / t460+t461(C-2 挙動不変)39 pass / complexity-gate 0 / unchecked-cast 0 new / source-only:check 0 / coverage-registry check 0(ratchet held)
  • NFR-1: 実ワークスペース(225 シャード / 133,663 行)1 回実行 0.653 秒(上限 60 秒)
  • 恒等 W: 構成窓 1563 = net 1126 + unclosedIdle 34 + zeroSecond 403 / 恒等 M: 7404 = 10 + 7394
  • 落ちる実証 3 セット(除外バケット報告削除 → 3 fail / fail-loud 無効化 → 1 fail / 黙示救済化 → 3 fail)— いずれも注入 → 赤実測 → 復元・残渣ゼロ確認済み

申告事項

  • テスト番号は base 前進の採番衝突により t484/t485 → t486/t487 へ改番(cid:code-generation:c1-tnnn-collision-on-regrounding)
  • unparseableReviewHeading 実測 117 vs 上流 observed 参照値 3 — 2 段マッチの寛容側が裸の ## Review 等を拾う仕様どおりの挙動(OQ-2 により実装の機械集計値を最終確定とし、build-and-test 成果物へ記録)

Note

Low Risk
New read-only reporting CLI with extensive tests; no writes to workspace data and no changes to runtime auth or workflow execution paths.

Overview
Adds amadeus-stage-stats.ts, a read-only Bun CLI that aggregates audit journal shards and record markdown into a stage performance report (issue #2405).

It pairs STAGE_STARTED → STAGE_COMPLETED per intent×stage, subtracts idle spans (approval, park, session gaps) to produce net duration stats, and also tallies §12a review iterations, sensor outcomes by Stage slug, and subagent model attribution. Output is deterministic markdown, CSV, or JSON, always led by a measurement ref and a prominent notice that net is an estimate. Journal v1/v2 fields come only from amadeus-journal.ts; the tool does not import amadeus-lib.ts. Exit 1 when a shard exists but is unreadable; 2 on usage errors.

Tests: t486 (pure aggregation) and t487 (FS scan, CLI spawn, read-only invariant). Coverage registry/ratchet updated; function:main gains CLI coverage via t487; prior entries for evaluateDispatchGuard / amadeus-subagent-model-guard are dropped from the registry diff (renumbering/collision), not new product removals in this tool file.

Reviewed by Cursor Bugbot for commit 0a1daf3. Configure here.

Summary by CodeRabbit

  • 新機能

    • ジャーナルや Markdown artefact を走査し、ステージ性能、実働時間、アイドル時間、レビュー反復、センサー結果、モデル帰属を集計する読み取り専用 CLI を追加。
    • Markdown、CSV、JSON 形式のレポート出力に対応。
    • v1/v2 データ、破損行、未読シャード、未完了データを適切に処理し、終了コードで状態を通知。
  • テスト

    • 集計、出力形式、引数検証、異常系、実ファイルシステム上の CLI 動作を包括的に検証。

j5ik2o added 2 commits August 8, 2026 08:03
amadeus-stage-stats.ts derives a per-stage duration baseline from the audit
shards and the review-iteration distribution from the record artefacts. Stage
windows pair STAGE_STARTED with STAGE_COMPLETED; the reported net duration
subtracts approval waits, parks and session gaps, which is what makes raw
wall-clock unusable as a performance signal.

net is an estimate, and the header says so on every run.

Exclusion buckets are layered by the three disjoint populations they count in,
so the window identity stays checkable on the output: constructed windows =
net population + unclosed-idle + zero-second. Every bucket is reported
whatever its value, and a shard that exists but cannot be read is fail-loud at
the exit code.

Two-generation journal normalization is reused from amadeus-journal.ts rather
than reimplemented; the tool imports no filesystem write API.

Refs #2405
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@j5ik2o, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 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: ASSERTIVE

Plan: Pro Plus

Run ID: d21f0a08-7443-4c82-9bfc-84457c6bf1e9

📥 Commits

Reviewing files that changed from the base of the PR and between ca87682 and fc0dde5.

📒 Files selected for processing (5)
  • packages/framework/core/tools/amadeus-stage-stats.ts
  • tests/.coverage-registry.json
  • tests/integration/t-coverage-mechanism-ratchet.test.ts
  • tests/integration/t487-stage-stats.integration.test.ts
  • tests/unit/t486-stage-stats.test.ts
📝 Walkthrough

Walkthrough

監査ジャーナルと Markdown artefact を走査する読み取り専用のステージ統計 CLI を追加した。実働時間、レビュー反復、センサー、モデル帰属を集計し、Markdown、CSV、JSON で出力する。単体テストと統合テストも追加した。

Changes

ステージ統計集計

Layer / File(s) Summary
コーパス走査と実働時間測定
packages/framework/core/tools/amadeus-stage-stats.ts, tests/unit/t486-stage-stats.test.ts, tests/integration/t487-stage-stats.integration.test.ts
v1/v2 イベントからステージ窓を構築する。承認待ち、停止、セッション間隔を控除する。破損行、未対応イベント、未完了区間、ゼロ秒窓を除外数として記録する。
帰属集計とレポート生成
packages/framework/core/tools/amadeus-stage-stats.ts, tests/unit/t486-stage-stats.test.ts, tests/integration/t487-stage-stats.integration.test.ts
レビュー反復、センサー、モデル、ステージ統計を集計する。Markdown、CSV、JSON の決定的な出力を生成する。
CLI 解決と実行
packages/framework/core/tools/amadeus-stage-stats.ts, tests/integration/t487-stage-stats.integration.test.ts, tests/.coverage-registry.json, tests/integration/t-coverage-mechanism-ratchet.test.ts
引数、環境変数、作業ディレクトリ、active space を解決する。正常終了、部分結果、使用エラーに対して終了コード 0、1、2 を返す。読み取り専用性を検証する。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • amadeus-dlc/amadeus#1924: 追加された SUBAGENT_STARTED イベントと生存期間の対応付けが、ステージ窓の集計対象に関係する。
  • amadeus-dlc/amadeus#2194: Quality Repair の監査イベント、センサー、モデル情報を本 CLI が集計する。
  • amadeus-dlc/amadeus#2362: 本 CLI が同 PR で導入されたモデル帰属フィールドを集計する。
🚥 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 タイトルは、変更の中心であるステージ性能統計CLIの追加を簡潔かつ具体的に示しています。
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.

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 0a1daf3. Configure here.

Comment thread packages/framework/core/tools/amadeus-stage-stats.ts
@j5ik2o

j5ik2o commented Aug 7, 2026

Copy link
Copy Markdown
Member Author

Bugbot 指摘(Subagent model rows double counted)を e4b1962 で修正しました。attributeModels の母集団を SUBAGENT_COMPLETED のみに限定(1 dispatch = 1 completion — 兄弟ツール amadeus-subagent-stats と同じ帰属契約)。STARTED 行が母集団に入らないことをピンする unit テストを追加し、実ワークスペース再実測で恒等 M(7326 = 9 attributable + 7317 unresolved)の成立を確認済みです。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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/framework/core/tools/amadeus-stage-stats.ts`:
- Around line 853-862: Update markdownUnder to enumerate entries with
readdirSync(..., { withFileTypes: true }) and use Dirent metadata to recurse
only into directories, while collecting .md files as before. Skip directory
symlinks (or otherwise track visited real paths) so symlinked ancestors cannot
cause infinite recursion, and preserve the existing audit/node_modules
exclusions and intent-relative paths.
- Around line 361-365: SENSOR_EVENTS を Object.prototype
を継承しないマップとして定義し、イベント名によるプロトタイプキーの誤マッチを防いでください。あわせて、SENSOR_EVENTS[event]
のルックアップでも own-property のみを受け入れ、constructor や toString など信頼できない入力が outcome として
counter や SensorTally に流入しないようにしてください。
- Around line 115-120: Update epochSeconds and its callers to detect invalid
timestamp parsing instead of allowing NaN to flow into rawSeconds and net
statistics. Exclude invalid records from the measurement population or route
them into a dedicated invalid-timestamp bucket, ensuring they are not silently
treated as the zero-second bucket.

In `@tests/integration/t487-stage-stats.integration.test.ts`:
- Around line 381-389: Update the import assertion in the test “no filesystem
write API is imported or referenced by the tool” to ignore type-only imports
such as Dirent while still validating runtime fs imports. Keep the WRITE_APIS
check and node:fs/promises prohibition unchanged, and assert only the non-type
imports against the existing expected list.
- Around line 339-362: 3つの spawnSync 呼び出しに明示的な timeout と killSignal
オプションを追加し、CLI
がハングした場合に子プロセスを終了できるようにしてください。既存の実行引数、encoding、env、終了ステータス検証は維持してください。

In `@tests/unit/t486-stage-stats.test.ts`:
- Around line 454-493: Add two focused tests to the renderer describe block:
verify renderMarkdown sanitizes a stage name containing a newline and control
byte so only the cleaned value appears, and verify renderCsv escapes commas and
quotes in a model name by quoting the field and doubling embedded quotes. Use
sampleReport-based fixtures and assert the injected content cannot alter output
structure.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 1157a386-33f9-436d-a757-c5c8652ca389

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfa48e and ca87682.

📒 Files selected for processing (5)
  • packages/framework/core/tools/amadeus-stage-stats.ts
  • tests/.coverage-registry.json
  • tests/integration/t-coverage-mechanism-ratchet.test.ts
  • tests/integration/t487-stage-stats.integration.test.ts
  • tests/unit/t486-stage-stats.test.ts

Comment thread packages/framework/core/tools/amadeus-stage-stats.ts
Comment thread packages/framework/core/tools/amadeus-stage-stats.ts Outdated
Comment thread packages/framework/core/tools/amadeus-stage-stats.ts Outdated
Comment thread tests/integration/t487-stage-stats.integration.test.ts
Comment thread tests/integration/t487-stage-stats.integration.test.ts
Comment thread tests/unit/t486-stage-stats.test.ts
…type-safe sensor lookup, symlink-safe record walk, spawn timeouts, sanitize tests
@j5ik2o

j5ik2o commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

CodeRabbit 指摘 6 件を ee2e5b9 で対応しました:

  1. 不正タイムスタンプの NaN 汚染(Major): invalid-timestamp バケットを windowing グループへ新設。buildWindows は parse 不能タイムスタンプのイベントを窓化前に計数・除外し、indexIdle も同様に計数・スキップ(NaN が net 統計へ流れない)。unit テスト 2 件追加(窓側・idle 側)
  2. SENSOR_EVENTS のプロトタイプ継承(Major): オブジェクトリテラル → ReadonlyMap へ変更(constructor 等のイベント名は miss する)
  3. markdownUnder の symlink 無限再帰(Major): readdirSync(dir, { withFileTypes: true }) へ変更し isDirectory() の実ディレクトリのみ再帰(Dirent は symlink を directory と報告しない)。syscall も削減
  4. spawnSync timeout(Trivial): 3 箇所へ timeout: 60_000, killSignal: SIGKILL を付与
  5. import 完全一致 assert の brittle 性(Trivial): 型 import(type 接頭辞)を除外してから値 import を照合
  6. サニタイズ契約のテスト不在(Trivial): 制御バイト+改行の stage 名の markdown 縮約テストと、カンマ+引用符の CSV 列偽造防止テストを追加

検証: typecheck 0 / lint 0 / twin 79 pass 0 fail / 実ワークスペース再実行で invalid-timestamp: 0・恒等 W 不変(1563 = 1126 + 34 + 403)

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