Skip to content

fix: route deep-review findings via structured output so empty model fails loudly#1010

Closed
ital0 wants to merge 1 commit into
mainfrom
fix/thunder-deep-review-structured-output
Closed

fix: route deep-review findings via structured output so empty model fails loudly#1010
ital0 wants to merge 1 commit into
mainfrom
fix/thunder-deep-review-structured-output

Conversation

@ital0

@ital0 ital0 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Why

The thunder-deep-review workflow's review check was passing green but doing nothing.

The model step runs read-only (--allowedTools Read,Grep,Glob — no Write/Bash), yet the prompt's OUTPUT CONTRACT told it to write the findings JSON to THUNDER_FINDINGS_FILE. With no Write tool, the file was never created → the post phase's readModelFindings() hit ENOENT → the orchestrator fail-soft exit(0) → a green check that never posted a review.

Fix

  • Emit findings through claude-code-action's --json-schema structured output channel instead of a model-written file. The model returns its findings as its final result; the action constrains it to the schema and exposes it on steps.model.outputs.structured_output. No write tool needed — model stays read-only.
  • A new non-model shell step (Materialize structured findings) bridges structured_outputTHUNDER_FINDINGS_FILE for the orchestrator.
  • Per a Codex second opinion: that step fails loudly on empty structured_output (model auth failure, --max-turns exhaustion, schema reject, etc. → red check, not a silent green no-op). A genuine empty review ({"findings":[]}) is non-empty JSON and passes the gate; the post step then no-ops cleanly.

No change to review-orchestrator.mjs — the structured output is {"findings":[...]}, which already matches what the post phase parses.


Note

Low Risk
CI workflow wiring only; no app runtime or auth logic changes, with clearer failure signaling when the model step breaks.

Overview
Fixes thunder-deep-review silently passing when the model never produced findings. The read-only model step (Read,Grep,Glob only) was still instructed to write THUNDER_FINDINGS_FILE, so the file was missing, the post orchestrator fail-soft exited 0, and the check went green with no comment.

The model step now returns findings through claude-code-action --json-schema structured output (steps.model.outputs.structured_output) with an inline findings schema, and the prompt OUTPUT CONTRACT tells the model to return structured JSON only (no file writes). A new Materialize structured findings shell step copies that output into THUNDER_FINDINGS_FILE for the existing post phase.

That materialize step fails the job if structured_output is empty or whitespace (broken auth, max turns, schema reject), while a real no-op review ({"findings":[]}) still passes and lets post no-op cleanly.

Reviewed by Cursor Bugbot for commit a24ae3f. Bugbot is set up for automated code reviews on this repo. Configure here.

…fails loudly

- read-only model step had no Write tool, so the file-write output contract
  produced nothing; the post phase ENOENT'd and the check went green-but-no-op
- emit findings via claude-code-action's --json-schema structured_output channel
- a non-model shell step materializes structured_output to THUNDER_FINDINGS_FILE
  and exits non-zero on empty output (broken model = red check), while a genuine
  {"findings":[]} passes
- model stays read-only (no Write/Bash)
@github-actions

Copy link
Copy Markdown

Semgrep Security Scan

No security issues found.

@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 and found 1 potential issue.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit a24ae3f. Configure here.

# ─────────────────────────────────────────────────────────────────────
- name: Compute diff to a bounded file
run: |
git diff "$PR_BASE_SHA".."$PR_HEAD_SHA" > "$THUNDER_DIFF_FILE" || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PR diff uses two-dot range

High Severity

The diff step uses a two-dot git diff between PR_BASE_SHA and PR_HEAD_SHA, which compares the two branch tips directly. GitHub PR diffs use merge-base-to-head (three-dot) semantics, so when the base branch moves ahead of the PR branch the patch can include unrelated base changes and misrepresent what the PR actually changes.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a24ae3f. Configure here.

@ital0

ital0 commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded: this fix belongs on PR #1003 (branch deep-review-tooling) and was folded there. This branch was created in error by a tooling mishap. Closing.

@ital0 ital0 closed this Jun 19, 2026
@ital0 ital0 deleted the fix/thunder-deep-review-structured-output branch June 19, 2026 12:59
@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

Preview environment deployed 🚀

Service URL
Marketing / blog / docs https://thunderbolt-pr-1010.preview.thunderbolt.io
App https://app-pr-1010.preview.thunderbolt.io
API https://api-pr-1010.preview.thunderbolt.io
Keycloak https://auth-pr-1010.preview.thunderbolt.io
PowerSync https://powersync-pr-1010.preview.thunderbolt.io

Stack: preview-pr-1010 · Commit: a24ae3f09f353f3f3ee2314c0f50ffbd0a02bf7f

Auto-destroys on PR close/merge. Login via the bundled Keycloak realm — demo@thunderbolt.io / demo by default.

@github-actions

Copy link
Copy Markdown

PR Metrics

Metric Value
Lines changed (prod code) +238 / -0
JS bundle size (gzipped) 🟢 682.3 KB → 682.1 KB (-191 B, -0.0%)
Test coverage 🟢 78.09% → 78.09% (+0.0%)
Performance (preview) Preview not ready — Render deploy may have timed out
Accessibility
Best Practices
SEO

Updated Fri, 19 Jun 2026 13:03:01 GMT · run #1970

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