Files
promptfoo--promptfoo/docs/agents/codex-app-server-provider-notes.md
wehub-resource-sync 0d3cb498a3
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Waiting to run
Test and Publish Multi-arch Docker Image / test (push) Waiting to run
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Blocked by required conditions
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Blocked by required conditions
Validate Renovate Config / Validate Renovate Configuration (push) Waiting to run
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:24:08 +08:00

577 lines
24 KiB
Markdown

# Codex App Server Provider Notes
These notes track the planned Promptfoo integration for the Codex app-server protocol.
They are intentionally implementation-facing: keep them current as the provider, docs,
examples, and verification expand.
For the broader coding-agent provider taxonomy, see
[`coding-agent-provider-taxonomy.md`](./coding-agent-provider-taxonomy.md).
## Objective
Add an experimental Promptfoo provider that drives `codex app-server` directly. The
provider should complement, not replace, the existing OpenAI Codex SDK provider:
- Codex SDK provider: best default for CI and automation.
- Codex app-server provider: best for evaluating rich-client behavior exposed by the
Codex app-server protocol, including streamed item events, approvals, skills,
plugins, apps, filesystem requests, and thread lifecycle primitives.
Primary provider IDs:
- `openai:codex-app-server`
- `openai:codex-app-server:<model>`
- `openai:codex-desktop`
- `openai:codex-desktop:<model>`
Optional top-level aliases may be added after the OpenAI-scoped provider is stable:
- `codex:app-server`
- `codex:desktop`
## Source Material
- Official docs: https://developers.openai.com/codex/app-server
- Local CLI: `/Applications/Codex.app/Contents/Resources/codex app-server --help`
- Local generated schema command:
```bash
codex app-server generate-ts --out /tmp/codex-app-server-schema/ts
codex app-server generate-json-schema --out /tmp/codex-app-server-schema/json
```
Current local schema inspection was generated from `codex-cli 0.118.0`.
## Protocol Shape
Transport:
- `stdio://` default, JSONL messages.
- `ws://IP:PORT` experimental, one JSON-RPC message per WebSocket text frame.
Handshake:
1. Send `initialize` with Promptfoo client metadata.
2. Send `initialized` notification.
3. Start or resume a thread.
4. Start a turn.
5. Read notifications until `turn/completed`.
Core client requests:
- `initialize`
- `thread/start`
- `thread/resume`
- `thread/archive`
- `thread/unsubscribe`
- `thread/read`
- `turn/start`
- `turn/steer`
- `turn/interrupt`
- `review/start`
- `model/list`
- `skills/list`
- `plugin/list`
- `plugin/read`
- `app/list`
High-risk client requests that should not be exposed casually:
- `fs/writeFile`
- `fs/remove`
- `fs/copy`
- `config/value/write`
- `config/batchWrite`
- `plugin/install`
- `plugin/uninstall`
- `command/exec`
Core server notifications:
- `thread/started`
- `thread/status/changed`
- `turn/started`
- `turn/completed`
- `item/started`
- `item/completed`
- `item/agentMessage/delta`
- `item/commandExecution/outputDelta`
- `item/fileChange/outputDelta`
- `item/mcpToolCall/progress`
- `serverRequest/resolved`
- `thread/tokenUsage/updated`
- `error`
Core server requests requiring deterministic Promptfoo responses:
- `item/commandExecution/requestApproval`
- `item/fileChange/requestApproval`
- `item/permissions/requestApproval`
- `item/tool/requestUserInput`
- `mcpServer/elicitation/request`
- `item/tool/call`
## Provider Contract
### Inputs
Promptfoo prompt strings remain the default. The provider should also accept a JSON
array of Codex input items:
```json
[
{ "type": "text", "text": "Review this project" },
{ "type": "local_image", "path": "/absolute/path/to/screenshot.png" },
{ "type": "skill", "name": "skill-creator", "path": "/absolute/path/SKILL.md" }
]
```
Supported input item types for the first implementation:
- `text`
- `local_image`, mapped to app-server `inputImage`
- `skill`
Unknown prompt JSON should be treated as plain text instead of throwing.
### Output
The provider response should include:
- `output`: final assistant text, assembled from `item/agentMessage/delta` and
completed `agentMessage` items.
- `sessionId`: thread id.
- `raw`: serialized protocol-level turn summary and selected notifications.
- `metadata.codexAppServer`: thread id, turn id, model, cwd, sandbox, approvals,
server requests, item counts, command/file/tool trajectories, and app-server
protocol data useful for debugging.
- `metadata.skillCalls` / `metadata.attemptedSkillCalls`: heuristic skill usage
where available.
- `tokenUsage`: from `thread/tokenUsage/updated` if emitted.
- `cost`: estimated from Promptfoo's Codex pricing table when model is known.
### Config
Provider-level config should be strict. Prompt-level merged config should strip unknown
keys so generic Promptfoo prompt config does not break rows.
Core config:
- `apiKey`
- `base_url`
- `working_dir`
- `additional_directories`
- `skip_git_repo_check`
- `codex_path_override`
- `model`
- `model_provider`
- `service_tier`
- `sandbox_mode`
- `sandbox_policy`
- `approval_policy`
- `approvals_reviewer`
- `model_reasoning_effort`
- `reasoning_summary`
- `personality`
- `output_schema`
- `thread_id`
- `persist_threads`
- `thread_pool_size`
- `ephemeral`
- `persist_extended_history`
- `experimental_raw_events`
- `experimental_api`
- `cli_config`
- `cli_env`
- `inherit_process_env`
- `reuse_server`
- `deep_tracing`
- `request_timeout_ms`
- `startup_timeout_ms`
- `server_request_policy`
### Safety Defaults
Default stance should favor repeatable evals over convenience:
- `approval_policy`: `never`
- `sandbox_mode`: `read-only`
- `network_access_enabled`: `false`
- `ephemeral`: `true`
- `reuse_server`: `true` unless `deep_tracing` is enabled
- `inherit_process_env`: `false`
- Server-side approval requests: decline/cancel or empty grants unless explicitly
configured.
Rationale:
- The app-server exposes shell, filesystem, app connector, plugin, and config surfaces.
- Promptfoo evals should be deterministic and should not block on human approval.
- Eval prompts and target behavior can be adversarial.
## Implementation Phases
1. Stdio JSON-RPC client
- Spawn `codex app-server`.
- Parse JSONL stdout.
- Route responses, notifications, and server requests.
- Capture stderr for debug logs.
- Support abort and timeout.
2. Provider lifecycle
- Register with `providerRegistry`.
- Reuse app-server process by default.
- Shut down child processes, pending requests, and readline handles.
- Disable reuse when `deep_tracing` is enabled.
3. Thread and turn execution
- Validate working directory.
- Start/resume threads.
- Start turns with prompt input, model, cwd, sandbox, approvals, effort, personality,
service tier, and output schema.
- Serialize turns per reused thread.
- Unsubscribe/archive non-persistent threads during cleanup.
4. Streaming aggregation
- Track `turnId`.
- Assemble assistant deltas.
- Store completed items.
- Build item counts and trajectory metadata.
- Capture command output, file changes, MCP calls, dynamic tool calls, web search,
plans, reasoning summaries, and review output.
5. Server request handling
- Deterministically answer command approvals.
- Deterministically answer file-change approvals.
- Return empty permission grants by default.
- Support configured answers for `tool/requestUserInput`.
- Decline/cancel MCP elicitation by default.
- Support static dynamic-tool responses.
- Record all requests and decisions in metadata.
6. Tracing
- Wrap `callApi` in `withGenAISpan`.
- Add item-level spans when streaming notifications arrive.
- Sanitize command output, tool arguments, and message text before trace attributes.
- Inject OTEL env when `deep_tracing` is enabled.
7. Docs and examples
- Add provider docs.
- Add provider index entry.
- Add examples for basic usage, read-only repo review, structured output, approval
handling, skills, and tracing.
8. Verification
- Unit tests with mocked child process and mocked protocol frames.
- Registry tests for provider IDs and model-in-path parsing.
- Docs/examples lint where applicable.
- Local smoke config using a harmless prompt and `sandbox_mode: read-only` if
credentials/login are available.
- Final dogfood: run the new provider against the git diff and iterate on comments.
## Progress Log
### 2026-04-09
- Added initial provider implementation at `src/providers/openai/codex-app-server.ts`.
- Added provider IDs under the OpenAI registry:
- `openai:codex-app-server`
- `openai:codex-app-server:<model>`
- `openai:codex-desktop`
- `openai:codex-desktop:<model>`
- Implemented stdio JSON-RPC lifecycle:
- spawn `codex app-server --listen stdio://`
- `initialize`
- `initialized`
- `thread/start`
- `thread/resume`
- `turn/start`
- notification handling through `turn/completed`
- `thread/unsubscribe`/`thread/archive` cleanup modes
- Implemented safe config defaults:
- `approval_policy: never`
- `sandbox_mode: read-only`
- `ephemeral: true`
- `thread_cleanup: unsubscribe`
- process env isolation unless `inherit_process_env: true`
- Implemented deterministic server request responses:
- command execution approvals default to `decline`
- file changes default to `decline`
- permission requests default to empty grants
- user input requests default to empty answers
- MCP elicitations default to `decline`
- dynamic tools can use static configured responses
- Implemented output normalization:
- assistant delta aggregation
- completed `agentMessage` fallback/preference
- token usage from `thread/tokenUsage/updated`
- cost estimate for known Codex models
- metadata with item counts, items, server request decisions, thread/turn ids
- Implemented provider-level GenAI tracing and item spans.
- Added mocked protocol tests in `test/providers/openai-codex-app-server.test.ts`.
- Added registry tests in `test/providers/index.test.ts`.
- Verification so far:
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- `npx vitest run test/providers/index.test.ts -t "Codex app-server|Codex desktop" --sequence.shuffle=false`
- `npm run tsc -- --pretty false`
- Expanded mocked protocol tests to cover:
- `thread/resume`
- structured prompt input normalization
- default `thread/unsubscribe` cleanup
- user input request policy
- dynamic tool static response policy
- metadata sanitization
- Ran a real local smoke eval through `npm run local -- eval -c examples/openai-codex-app-server/promptfooconfig.yaml --no-cache -o /tmp/promptfoo-codex-app-server-example.json`.
- Result: pass.
- Provider returned Codex app-server `sessionId`, token usage, item counts, thread id,
turn id, and structured JSON output.
- Ran docs build:
- `cd site && SKIP_OG_GENERATION=true npm run build`
- Result: pass.
- First dogfood review through `examples/openai-codex-app-server/review-diff/promptfooconfig.yaml`
found four actionable provider issues:
- startup timeout could leak a spawned app-server and leave a rejected reusable
connection promise cached
- reused connections closed over the first turn's server request policy
- app-server exit during a turn could leave the eval waiting forever when no turn
timeout was configured
- `raw` response payload serialized unsanitized protocol items
- Fixed the dogfood findings and added regression coverage:
- failed startup closes the process and a later call spawns a fresh process
- active turns store their effective config so prompt-level server request policies are
honored on reused servers
- connection exit resolves active turns with a provider error and removes the dead
connection from reuse maps
- `raw` now contains sanitized thread, turn, token usage, notifications, and item
metadata
- final output now uses the last completed `agentMessage`, which avoids concatenating
progress messages with final structured review output
- Verification after fixes:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 13 provider tests.
- Second dogfood review passed the Promptfoo eval and returned valid JSON, but still
reported two provider comments:
- legacy `execCommandApproval` / `applyPatchApproval` requests identify the active
thread with `conversationId` and expect legacy review decisions
- persistent thread-pool eviction deleted local handles without unsubscribing the
evicted loaded thread
- Additional hardening from the second dogfood pass:
- stdio parser now buffers partial JSON-RPC lines and rejoins literal newlines inside
command-output strings as escaped newlines before parsing
- legacy approval requests now map prompt-level policy to `approved`,
`approved_for_session`, `denied`, and `abort`
- legacy server requests can find active turn state by `conversationId`
- evicted persistent cached threads now send `thread/unsubscribe` before being removed
- added regression coverage for literal-newline JSON-RPC notifications, legacy
approval requests, and persistent thread-pool eviction
- Verification after second dogfood fixes:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 16 provider tests.
- Third dogfood review passed transport/eval and reported two lifecycle comments:
- stale persistent thread handles remained after a reused app-server process exited
- JSON-RPC request timeout cleanup removed the pending request but left an abort
listener attached
- Additional hardening from the third dogfood pass:
- connection close now removes cached thread handles owned by that connection key
- per-request timeout cleanup now removes abort listeners before rejecting
- added regression coverage for cached-thread invalidation after process exit and
abort-listener cleanup on JSON-RPC timeout
- Verification after third dogfood fixes:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 18 provider tests.
- Fourth dogfood review passed transport/eval and reported two thread-cache comments:
- persistent thread caching was still enabled for fresh-per-call app-server processes
(`reuse_server: false` or `deep_tracing`)
- pool eviction could unsubscribe an active cached thread before its turn completed
- Additional hardening from the fourth dogfood pass:
- thread caching is now allowed only when the app-server connection itself is reusable
- active/reserved thread ids are protected with a small refcount while a call is using
them
- thread-pool eviction skips protected threads and temporarily allows the pool to
exceed its soft cap rather than evicting an in-flight turn
- added regression coverage for non-reusable persistent-thread configs and active-turn
eviction avoidance
- Verification after fourth dogfood fixes:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 20 provider tests.
- Fifth dogfood review passed transport/eval and reported one persistent-thread race:
- concurrent calls with the same persistent-thread cache key could both miss the cache
while the first `thread/start` was still pending, creating duplicate persistent
threads and leaking the earlier one
- Additional hardening from the fifth dogfood pass:
- added an in-flight thread promise map keyed by thread cache key
- concurrent same-cache `thread/start` / `thread/resume` callers now share the same
pending thread handle
- added regression coverage for concurrent same-cache persistent calls, ensuring only
one `thread/start` is sent and both turns use the shared thread
- Verification after fifth dogfood fix:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 21 provider tests.
- Sixth dogfood review passed transport/eval and reported two cache/default comments:
- reusable connections could keep the first request timeout for requests that did not
pass a per-call timeout
- persistent thread cache keys omitted thread-start options such as `ephemeral`,
`experimental_raw_events`, and `persist_extended_history`
- Additional hardening from the sixth dogfood pass:
- all provider-owned app-server requests now pass the effective per-call request
timeout explicitly
- persistent thread cache keys now include thread-start options that can change thread
semantics
- added regression coverage for prompt-level request timeouts on reused connections and
thread-start option changes in persistent cache keys
- Verification after sixth dogfood fixes:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 23 provider tests.
- Seventh dogfood retry:
- first attempt hit an external Codex connectivity failure (`Network is unreachable`,
`Reconnecting... 2/5`), which the provider surfaced as a clean provider error
- retry completed transport/eval and reported one metadata issue: skill-root detection
used the parent process env instead of the resolved app-server child env
- Additional hardening from the seventh dogfood pass:
- turn state now carries the resolved app-server environment produced by
`prepareEnvironment`
- skill root detection now uses the child env for `CODEX_HOME`, `HOME`, and
`USERPROFILE`
- added regression coverage for `cli_env.HOME` skill-call metadata detection
- Verification after seventh dogfood fix:
- `npm run tsc -- --pretty false`
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`
- Result: pass, 24 provider tests.
- Eighth dogfood review:
- `npm run local -- eval -c examples/openai-codex-app-server/review-diff/promptfooconfig.yaml --no-cache --no-share -o /tmp/promptfoo-codex-app-server-review.json`
- Result: pass.
- Provider output: `{"comments":[],"summary":"No actionable findings; TypeScript and focused provider tests passed."}`
- This confirms the provider can be used to review the current git diff and return
schema-valid JSON with no remaining actionable comments from the dogfood reviewer.
- Final verification sweep:
- `npm run f`: pass with existing complexity warnings only; no formatting changes needed
- `npm run tsc -- --pretty false`: pass
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`:
pass, 24 provider tests
- `npx vitest run test/providers/index.test.ts -t "Codex app-server|Codex desktop" --sequence.shuffle=false`:
pass, 2 registry tests
- `npm run l`: pass with existing complexity warnings only
- `cd site && SKIP_OG_GENERATION=true npm run build`: pass
- `npm run local -- eval -c examples/openai-codex-app-server/promptfooconfig.yaml --no-cache --no-share -o /tmp/promptfoo-codex-app-server-example.json`:
pass
## QA Matrix
Required mocked unit tests:
- Constructor defaults and strict config validation.
- Prompt-level unknown config stripping.
- Missing/inaccessible/non-directory working directory.
- Git check and `skip_git_repo_check`.
- API key/env isolation and explicit `cli_env`.
- Handshake order: `initialize`, `initialized`, `thread/start`, `turn/start`.
- Model from provider path overrides/defaults correctly.
- `thread_id` uses `thread/resume`.
- `persist_threads` reuses cached thread and serializes turns.
- Non-persistent calls unsubscribe/archive as configured.
- Assistant deltas aggregate into final output.
- Completed `agentMessage` fallback works when deltas are missing.
- Token usage from `thread/tokenUsage/updated`.
- Error notification produces provider error.
- Failed turn produces provider error.
- Abort before start.
- Abort during turn sends `turn/interrupt` and returns aborted error.
- Command approval request default decline.
- File change request default decline.
- Permission request default empty grant.
- User input request configured answers.
- Dynamic tool call configured static response.
- MCP elicitation default decline/cancel.
- Metadata contains item counts, trajectories, approvals, raw notifications, and server
request decisions without leaking API keys.
- `cleanup` kills child process and unregisters provider.
- `deep_tracing` injects OTEL env and disables reuse/thread persistence.
- Provider-level GenAI tracing records response body, token usage, session id, and item
count attributes.
Required docs/examples checks:
- Provider docs render in Docusaurus.
- Examples are listed and runnable from repo root with `npm run local -- eval ... --no-cache`.
- Config docs call out experimental status, safety defaults, and difference from Codex SDK.
## Open Questions
- Whether to expose WebSocket transport in the first public version. Stdio is enough for
Promptfoo-managed app-server processes; WebSocket is useful for external clients but
adds auth and lifecycle complexity.
- Whether to support top-level `codex:*` aliases immediately or keep all new IDs under
`openai:*` for consistency with the existing Codex SDK provider.
- Whether to persist generated app-server protocol types in source. The current plan is
to implement a narrow local type surface and document how to regenerate schemas instead
of committing a large generated bundle.
## Critical Audit Follow-up
Review feedback and red-team audit items addressed after the initial dogfood pass:
- Fixed registry env propagation for object-shaped provider configs. `loadApiProvider`
already merges suite-level and provider-level env into `providerOptions.env`; the
registry now passes that merged env to `OpenAICodexAppServerProvider`.
- Fixed `service_tier` to match the generated app-server schema from `codex-cli 0.118.0`:
`fast` and `flex` only.
- Reset the hoisted `spawn` mock implementation in `beforeEach` to satisfy `test/AGENTS.md`
mock isolation rules.
- Regenerated app-server TypeScript and JSON Schema into
`/tmp/codex-app-server-schema-current.XVTCwL` during the audit and compared rare
app-server fields against the implementation.
- Added coverage for schema-supported rare fields:
- `model_reasoning_effort: none`
- exact `personality` values: `none`, `friendly`, `pragmatic`
- granular approval policy objects
- app-server command approval amendment objects
- session-scoped permission grants
- accepted MCP elicitation responses with content and metadata
- `base_instructions`, `developer_instructions`, and `collaboration_mode`
- Dogfood review then found additional issues:
- reusable app-server connections stayed alive after JSON-RPC request timeouts, which
could leave late side-effecting responses unmanaged
- docs listed `thread_pool_size` as unlimited even though the implementation defaults
to `1`
- provider cleanup cleared active turns before resolving them, which could hang
shutdown while a turn was in flight
- raw JSON-RPC notifications were retained even when `include_raw_events` was false
- spawned app-server processes could be missed if cleanup ran while `initialize` was
still pending
- concurrent persistent thread starts could temporarily exceed `thread_pool_size` and
remain over capacity after active turns finished
- deep-tracing calls that shared a `thread_id` could overlap turns because the queue key
returned early
- the OpenAI provider docs heading change would have broken the existing `#codex-sdk`
anchor
- default `thread_id` resumes skipped unsubscribe cleanup
- sent JSON-RPC request aborts kept the reusable app-server alive
- retryable app-server `error` notifications with `willRetry: true` were treated as
terminal
- concurrent default-cleanup `thread_id` rows could unsubscribe while another row was
queued for the same thread
- Fixed these by closing/evicting connections on timeout and abort, resolving active
turns during cleanup, tracking pending initialization processes, making raw event
retention opt-in, rebalancing the persistent thread pool after turns finish, serializing
explicit `thread_id` turns even under deep tracing, preserving the OpenAI docs
`#codex-sdk` heading, default-unsubscribing non-persistent resumed threads, honoring
retryable app-server errors, and deferring resumed-thread unsubscribe until no other
protected queued caller remains.
- Updated docs to explain why the app-server provider should stay separate from the
Codex SDK provider: the SDK is the right default for CI and automation, while app-server
is for rich-client protocol event surfaces and does not attach to a running Codex
Desktop app.
Latest focused verification after these fixes:
- `npx vitest run test/providers/openai-codex-app-server.test.ts --sequence.shuffle=false`:
pass, 35 provider tests.
- `npm run local -- eval -c examples/openai-codex-app-server/review-diff/promptfooconfig.yaml --no-cache --no-share`:
pass with `{"comments":[],"summary":"No actionable issues found in the current diff."}`.