Skip to content

Feat/execution contract#538

Closed
romamo wants to merge 8 commits intogoogleworkspace:mainfrom
romamo:feat/execution-contract
Closed

Feat/execution contract#538
romamo wants to merge 8 commits intogoogleworkspace:mainfrom
romamo:feat/execution-contract

Conversation

@romamo
Copy link

@romamo romamo commented Mar 18, 2026

Motivation

AI agents calling gws currently receive exit code 1 for every failure —
auth errors, bad input, API blips, and internal panics all look identical.
This forces agents to parse stderr JSON to decide whether to retry, abort, or
escalate, which is fragile and couples them to error message formatting.

What This Adds

PR #428 established the exit code constants and exit_code() method. This PR
builds the agent-facing contract on top of that foundation:

Feature File(s)
exit_codes_json() — JSON taxonomy using EXIT_CODE_* constants src/error.rs
gws exit-codes command — machine-readable taxonomy at runtime src/main.rs
timeout_ms: 30000 + exit_codes array in every gws schema response src/schema.rs
--idempotency-key global flag — injects Idempotency-Key on POST/PUT/PATCH src/commands.rs, src/executor.rs
SIGTERM handling in +watch and +subscribe pull loops src/helpers/gmail/watch.rs, src/helpers/events/subscribe.rs

Impact

An agent can now:

  • Branch on exit code alone — no stderr parsing needed
  • Discover the taxonomy at startup via gws exit-codes | jq
  • Retry mutations safely with --idempotency-key
  • Read timeout budget from gws schema <method> before calling
  • Shut down cleanly when orchestrators send SIGTERM

Exit Codes (from PR #428)

Code Reason Agent action
0 Success
1 API error Retry with backoff
2 Auth error Abort, fix credentials
3 Validation error Abort, fix input
4 Discovery error Retry
5 Internal error Retry once, then escalate

Dry Run Output:
gws exit-codes

{                                                                                                                 
  "exit_codes": [                                                                                                                                                               
    { "code": 0, "meaning": "Command completed successfully",          "reason": "success"          },
    { "code": 1, "meaning": "Remote API returned an error response",   "reason": "apiError"         },                                                                          
    { "code": 2, "meaning": "Missing or invalid credentials",          "reason": "authError"        },
    { "code": 3, "meaning": "Bad input or wrong arguments",            "reason": "validationError"  },                                                                          
    { "code": 4, "meaning": "Could not load API Discovery document",   "reason": "discoveryError"   },            
    { "code": 5, "meaning": "Unexpected or transient failure",         "reason": "internalError"    }                                                                           
  ]                                                                                                               
}                                                                                                                                                                               

gws drive files create --idempotency-key my-key-123 --dry-run

{                                                
  "body": null,
  "dry_run": true,
  "idempotency_key": "my-key-123",
  "is_multipart_upload": false,                                                                                                                                                 
  "method": "POST",
  "query_params": [],                                                                                                                                                           
  "url": "https://www.googleapis.com/drive/v3/files"                                                              
}                                                

gws schema drive.files.list | jq '{timeout_ms, exit_codes}'

{                                                                                                                                                                               
  "timeout_ms": 30000,                                                                                            
  "exit_codes": [                                
    { "code": 0, "reason": "success",         "meaning": "Command completed successfully"        },
    { "code": 1, "reason": "apiError",         "meaning": "Remote API returned an error response" },                                                                            
    { "code": 2, "reason": "authError",        "meaning": "Missing or invalid credentials"        },                                                                            
    { "code": 3, "reason": "validationError",  "meaning": "Bad input or wrong arguments"          },                                                                            
    { "code": 4, "reason": "discoveryError",   "meaning": "Could not load API Discovery document" },                                                                            
    { "code": 5, "reason": "internalError",    "meaning": "Unexpected or transient failure"       }                                                                             
  ]                                                                                                                                                                             
}                                                                                                                                                                               

Checklist:

  • My code follows the AGENTS.md guidelines (no generated google-* crates).
  • I have run cargo fmt --all to format the code perfectly.
  • I have run cargo clippy -- -D warnings and resolved all warnings.
  • I have added tests that prove my fix is effective or that my feature works.
  • I have provided a Changeset file (.changeset/execution-contract.md) to document my changes.

@romamo romamo requested a review from jpoehnelt as a code owner March 18, 2026 08:52
@changeset-bot
Copy link

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: 8fbb88a

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@googleworkspace-bot googleworkspace-bot added area: docs area: http area: core Core CLI parsing, commands, error handling, utilities labels Mar 18, 2026
@google-cla
Copy link

google-cla bot commented Mar 18, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the gws command-line tool's execution contract, primarily to improve its reliability and predictability when used by AI agents. By introducing semantic exit codes, machine-readable error taxonomies, and idempotency support, agents can now make more informed decisions regarding error handling and retries. Additionally, improved signal handling ensures more robust operation for long-running processes.

Highlights

  • Semantic Exit Codes: Errors now exit with typed codes (1=validation, 2=auth, 3=api, 4=discovery, 5=internal) instead of a uniform exit(1), allowing AI agents to distinguish between retryable and non-retryable errors.
  • New gws exit-codes Command: A new command outputs a machine-readable JSON taxonomy of all exit codes, enabling agents to programmatically understand error meanings at startup.
  • Schema Enrichment: gws schema <method> output now includes timeout_ms (30000) and the full exit_codes array, making every method self-documenting for agents.
  • Idempotency Key Support: A new global flag --idempotency-key sends an Idempotency-Key HTTP header on POST/PUT/PATCH requests, ensuring safe retries for mutating operations.
  • SIGTERM Handling: Long-running gws gmail +watch and gws events +subscribe loops now gracefully handle SIGTERM signals, in addition to Ctrl+C, for clean shutdowns in containerized environments.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Generative AI Prohibited Use Policy, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly improves the execution contract for AI agents by introducing semantic exit codes, an idempotency key for safe retries, and graceful SIGTERM handling for long-running processes. The changes are well-implemented and include relevant tests. However, I've found a critical issue in the new SIGTERM handling logic where a potential panic could prevent a clean shutdown, which I've detailed in the comments.

@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a stable execution contract for AI agents, which is a great improvement for reliability. The changes include semantic exit codes, an --idempotency-key for safe retries, and SIGTERM handling for clean shutdowns. The implementation is solid, but I have a couple of suggestions to improve the maintainability of the new exit code contract and the robustness of the exit-codes command.

@romamo romamo force-pushed the feat/execution-contract branch from 37ce64c to 7cc3fb5 Compare March 18, 2026 09:12
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a stable execution contract with semantic exit codes, an idempotency key for safe retries, and SIGTERM handling for graceful shutdowns. This is a great improvement for agent reliability. My review found a critical inconsistency in the implementation of the semantic exit codes. The codes defined in the code do not match what is described in the pull request description and the updated README.md, which could lead to incorrect error handling by agents.

@romamo
Copy link
Author

romamo commented Mar 18, 2026

Rebased onto main after PR #428 merged and addressed all review feedback:

Exit code mappingexit_codes_json() now uses GwsError::EXIT_CODE_*
constants directly, so the JSON output is guaranteed to stay in sync with
exit_code(). No more divergence between the documented contract and the
implementation.

SIGTERM panic — replaced .expect("failed to register SIGTERM handler")
with .context(...)? in both watch.rs and subscribe.rs so a registration
failure propagates as GwsError::Other instead of panicking.

Duplicate exit code tests — removed the tests added in this PR that
conflicted with the ones already introduced by PR #428.

The exit code constants and exit_code() method in this PR's original scope
were already covered by PR #428 — this PR now focuses purely on what was
missing: the JSON taxonomy, schema enrichment, idempotency key, and signal
handling.

romamo added 3 commits March 18, 2026 11:36
- Semantic exit codes: errors now exit with typed codes (1=validation,
  2=auth, 3=api, 4=discovery, 5=internal) instead of always exiting 1
- `gws exit-codes`: new command outputs machine-readable exit code
  taxonomy as JSON for agent retry/abort branching
- Schema enrichment: `gws schema <method>` now includes `timeout_ms`
  (30000) and `exit_codes` array so agents can self-document a method
- SIGTERM handling: `gws gmail +watch` and `gws events +subscribe` now
  handle SIGTERM for clean shutdown alongside existing Ctrl+C support
- `--idempotency-key`: new global flag injects an `Idempotency-Key`
  HTTP header on POST/PUT/PATCH requests; surfaced in --dry-run output
Add exit code taxonomy, --idempotency-key usage, and gws exit-codes
examples to the "For AI agents" section so agents can discover the
retry/abort contract without reading source.
Replace .expect() with .context()? so a failure to register the SIGTERM
handler returns a GwsError::Other rather than panicking — consistent with
the clean-shutdown goal.

Addresses review comment from gemini-code-assist.
@romamo romamo force-pushed the feat/execution-contract branch from 7cc3fb5 to 84fc563 Compare March 18, 2026 09:36
@googleworkspace-bot
Copy link
Collaborator

/gemini review

@gemini-code-assist
Copy link
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

…ion error

- Introduce EXIT_CODE_TABLE as the canonical (code, reason, meaning) array;
  EXIT_CODE_DOCUMENTATION and exit_codes_json() both derive from it so the
  three representations can no longer drift
- Replace unwrap_or_default() in the exit-codes command with proper error
  propagation so a serialization failure surfaces as GwsError::Other instead
  of silently printing empty output

Addresses gemini-code-assist review comments on PR googleworkspace#538.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a more robust execution contract for AI agents by adding semantic exit codes, a command to discover them, schema enrichment with timeouts, idempotency keys for safe retries, and graceful SIGTERM handling. The implementation is solid, but there are a few critical inconsistencies in the documentation regarding the new exit codes that could confuse users and agents. I've also identified a couple of areas in the code that could be made more robust to prevent future maintenance issues.

…docs

- Replace hardcoded EXIT_CODE_TABLE index literals in EXIT_CODE_DOCUMENTATION
  with a const macro loop so adding/reordering entries never silently breaks
  the documentation array
- Derive test_exit_codes_json_contains_all_codes expected codes from
  EXIT_CODE_TABLE instead of hardcoded 0..=5
- Fix incorrect exit code mapping in README and changeset (was 1=validation,
  3=api; correct is 1=api, 3=validation per EXIT_CODE_API/VALIDATION constants)

Addresses gemini-code-assist review 3966742572.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable execution contract for AI agents, including semantic exit codes, an idempotency key feature, and SIGTERM handling. The implementation is solid, but I've identified two issues. One is a critical discrepancy where a timeout advertised in the schema is not enforced in the HTTP client, which could cause agents to hang. The other is a high-severity issue where providing an empty idempotency key would likely lead to API errors.

…ncy key

- Extract SCHEMA_TIMEOUT_MS constant from schema.rs and apply it as the
  reqwest client timeout in client.rs so the contract advertised in schema
  output is actually enforced on every request
- Filter out empty --idempotency-key values so passing "" behaves the same
  as omitting the flag instead of sending a blank Idempotency-Key header

Addresses gemini-code-assist review 3966832626.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly improves the execution contract for AI agents by introducing semantic exit codes, a new gws exit-codes command, schema enrichment with timeouts, an --idempotency-key for safe mutations, and graceful SIGTERM handling for long-running commands. The changes are well-structured and the new features are valuable for improving reliability.

I have one high-severity suggestion to improve the implementation: to make the new test for exit codes more robust.

… extras

Addresses gemini-code-assist review 3966901258.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a more robust execution contract for AI agents, including semantic exit codes, a new gws exit-codes command, schema enrichment with timeouts, an --idempotency-key flag for safe mutations, and graceful SIGTERM handling. The implementation is solid, but I've identified a couple of areas for improvement regarding code duplication and the use of modern Rust idioms, which would enhance maintainability.

…ration

- Replace macro_rules! with a const fn build_exit_code_documentation() —
  same compile-time derivation from EXIT_CODE_TABLE, more idiomatic Rust
- Extract SIGTERM signal registration into helpers::register_sigterm() so
  gmail::watch and events::subscribe share one definition instead of two

Addresses gemini-code-assist review 3966990380.
@googleworkspace-bot
Copy link
Collaborator

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly enhances the execution contract for agent reliability by introducing semantic exit codes, a new gws exit-codes command, schema enrichment with timeouts, an --idempotency-key for safe mutations, and SIGTERM handling for long-running processes. The implementation is robust and well-tested.

@codecov
Copy link

codecov bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 53.06122% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.73%. Comparing base (9c26e3c) to head (8fbb88a).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/main.rs 0.00% 11 Missing ⚠️
src/error.rs 71.87% 9 Missing ⚠️
src/helpers/events/subscribe.rs 33.33% 6 Missing ⚠️
src/helpers/gmail/watch.rs 33.33% 6 Missing ⚠️
src/executor.rs 71.42% 4 Missing ⚠️
src/helpers/sheets.rs 0.00% 2 Missing ⚠️
src/schema.rs 0.00% 2 Missing ⚠️
src/helpers/calendar.rs 0.00% 1 Missing ⚠️
src/helpers/chat.rs 0.00% 1 Missing ⚠️
src/helpers/docs.rs 0.00% 1 Missing ⚠️
... and 3 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #538      +/-   ##
==========================================
+ Coverage   68.10%   68.73%   +0.63%     
==========================================
  Files          40       41       +1     
  Lines       17954    18761     +807     
==========================================
+ Hits        12227    12895     +668     
- Misses       5727     5866     +139     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jpoehnelt jpoehnelt closed this Mar 18, 2026
@jpoehnelt
Copy link
Member

Exit codes already in use, no need for a command, pr includes too many other changes.

@romamo romamo deleted the feat/execution-contract branch March 18, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Core CLI parsing, commands, error handling, utilities area: docs area: http

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants