Skip to content

feat: implement await-stats subcommand#1401

Open
Ameb8 wants to merge 5 commits into
git-ai-project:mainfrom
Ameb8:feat/await-stats-subcommand
Open

feat: implement await-stats subcommand#1401
Ameb8 wants to merge 5 commits into
git-ai-project:mainfrom
Ameb8:feat/await-stats-subcommand

Conversation

@Ameb8
Copy link
Copy Markdown

@Ameb8 Ameb8 commented May 20, 2026

Implements #1377: add git ai await-stats command

Summary

This PR adds a new read-only git ai await-stats subcommand for the post-commit gap between when git commit returns and when the git-ai daemon finishes writing the commit's authorship note. The command resolves a target commit (defaulting to HEAD), polls for the note through the existing notes API, validates that the note is parseable authorship data, and then prints the same commit stats users already get from git ai stats. It supports the expected CLI surface from the spec and design docs: --timeout, --interval, --commit, --json, --quiet, and command-specific help, while keeping successful output aligned with the existing terminal renderer and JSON schema instead of introducing a second stats format.

The implementation also makes the failure modes explicit so callers can distinguish "still waiting" from "bad input" and "bad note data". Timeouts return exit code 1 and can be silenced with --quiet, unresolved commit revs return exit code 2, and corrupt note data returns exit code 3. Alongside the new command module, this PR wires await-stats into git ai dispatch and top-level help output, and updates the integration test harness so commands in this path daemon-sync consistently with other note-reading subcommands. This gives us a small, reusable CLI primitive now, and it also establishes the user-facing contract needed for future plain Git post-commit hook usage without baking hook-specific behavior into the command itself.

Test Plan

  • Added command-module parser/unit coverage for default options, full option parsing, missing values, zero interval rejection, and unknown flag rejection.
  • Added integration coverage for successful await-stats --json output when a note exists.
  • Added integration coverage for default HEAD behavior and human-readable stats output.
  • Added integration coverage for --commit <rev> against an earlier commit.
  • Added integration coverage for timeout behavior when the authorship note is absent.
  • Added integration coverage for --quiet suppressing timeout output.
  • Added integration coverage for unresolved commit revs returning exit code 2.
  • Added integration coverage for corrupt authorship notes returning exit code 3.
  • Updated the integration harness so await-stats performs the same daemon sync used by other note-reading git-ai commands.

Open in Devin Review

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 20, 2026

CLA assistant check
All committers have signed the CLA.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Ameb8 and others added 5 commits May 23, 2026 11:13
Add the core `git ai await-stats` command implementation that resolves a target
commit, polls the git-ai notes backend for its authorship note, validates the
note payload, and then renders the same stats data exposed by `git ai stats`.

- `AwaitStatsOptions::default` defines the command defaults: `HEAD`,
  `--timeout 5000`, `--interval 100`, human-readable output, and non-quiet
  mode.
- `AwaitStatsError::exit_code` maps timeout, bad invocation, bad commit, and
  corrupt-note failures onto the public CLI exit-code contract.
- `From<GitAiError> for AwaitStatsError` keeps shared git-ai failures inside the
  command-specific error type.
- `handle_await_stats` executes the command, suppresses timeout noise for
  `--quiet`, prints user-facing errors, and exits with the correct status code.
- `run` keeps parsing and execution testable by separating command logic from
  process exit behavior.
- `run_with_options` discovers the repository, resolves the commit revision,
  waits for the note, validates `AuthorshipLog`, computes commit stats, and
  prints either JSON or the shared terminal renderer output.
- `parse_options` handles all supported flags, requires values where needed, and
  rejects unknown arguments.
- `parse_u64_option` provides a single parser for millisecond options with
  stable bad-argument messages.
- `resolve_commit` accepts any rev that peels to a commit and returns the SHA
  that owns the authorship note.
- `wait_for_note` polls `notes_api::read_note` until the note appears or the
  timeout expires, while capping sleep to the remaining wait budget.
- `is_quiet_timeout` detects `--quiet` early enough to suppress timeout output
  before parsed options are available.
- `print_error` formats each failure mode into the command's stderr contract.
- `short_sha` trims commit IDs for timeout messages.
- `print_help` adds command-local usage output for `await-stats`.
- The parser unit tests cover defaults, full option parsing, missing values,
  zero interval rejection, and unknown arguments.

Co-authored-by: OpenAI GPT 5.5 <noreply@openai.com>
Wire the new `await-stats` implementation into the top-level `git ai` CLI so it
can be invoked as a first-class subcommand and discovered through built-in help.

- `handle_git_ai` dispatches `await-stats` to `commands::await_stats::handle_await_stats`.
- `print_help` documents the new subcommand plus its `--timeout`, `--interval`,
  `--commit`, `--json`, and `--quiet` flags in the shared CLI help output.
- `src/commands/mod.rs` exports the new module so the command is compiled into
  the CLI command set.

Co-authored-by: OpenAI GPT 5.5 <noreply@openai.com>
Add integration coverage for the new `await-stats` command and update the test
helpers so note-dependent commands wait for daemon output before asserting on
results.

- `extract_json_object` isolates the JSON payload from command output so the
  tests can deserialize `CommitStats` directly.
- `run_git_ai_raw` invokes the git-ai binary without the higher-level helpers so
  the tests can assert exact exit codes plus stdout/stderr behavior.
- `output_text` combines stdout and stderr into one assertion string for failure
  cases.
- `await_stats_prints_json_when_note_exists` verifies JSON stats output for a
  commit whose note is already present.
- `await_stats_defaults_to_head` verifies the command resolves `HEAD` by default
  and renders the shared human-readable stats output.
- `await_stats_accepts_commit_rev` verifies `--commit` can target a non-`HEAD`
  revision and report stats for that specific commit.
- `await_stats_times_out_when_note_absent` verifies missing notes return exit
  code `1` with the timeout message.
- `await_stats_quiet_suppresses_timeout_output` verifies `--quiet` still exits
  non-zero on timeout but suppresses stderr output.
- `await_stats_bad_commit_exits_2` verifies unresolved revisions return exit
  code `2` with the expected bad-commit message.
- `await_stats_corrupt_note_exits_3` verifies malformed note payloads return
  exit code `3` with the corrupt-note error message.
- `git_ai_command_requires_daemon_sync` now treats `await-stats` as a
  note-dependent command so the test harness waits for daemon-produced notes
  before running command assertions.
- `tests/integration/main.rs` registers the new integration test module.

Co-authored-by: OpenAI GPT 5.5 <noreply@openai.com>
@Ameb8 Ameb8 force-pushed the feat/await-stats-subcommand branch from 228d7b3 to 457d398 Compare May 23, 2026 18:14
@Ameb8
Copy link
Copy Markdown
Author

Ameb8 commented May 23, 2026

PR Updated

I added the automatic await-stats behavior to the managed git wrapper's successful git commit path. After the wrapper proxies a commit to real Git and the commit succeeds, it now waits briefly for the async authorship note, validates that note, and renders the same stats output through shared await-stats code instead of keeping separate polling/rendering logic in the wrapper.

The main refactor is in src/commands/await_stats.rs: the CLI entrypoint still behaves the same, but the note resolution, note polling, note validation, and stats rendering pieces are now reusable helpers that accept an existing Repository. src/commands/git_handlers.rs then calls those helpers from maybe_show_async_post_commit_stats(...) while preserving the wrapper-specific automatic-output rules: no output for dry-run, quiet, porcelain, no-status, config-quiet, or non-interactive commits, and no expensive stats computation for merge or large commits.

I wired this through the wrapper path rather than a literal .git/hooks/post-commit hook because the managed wrapper is the current post-commit-equivalent integration point in this codebase, and the old core hook symlink path appears to be sunset. The wrapper also already has the parsed git args, terminal context, and repo handle needed to make the automatic behavior conservative. A real post-commit hook should still be able to invoke git ai await-stats manually, but this change does not install or modify hook files.

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