Skip to content

fix(report): scope the write_report schema to the phase and name missing dimensions - #134

Merged
Inakitajes merged 1 commit into
mainfrom
fix/write-report-phase-schema
Oct 20, 2026
Merged

Inakitajes merged 1 commit into
mainfrom
fix/write-report-phase-schema

Conversation

@Inakitajes

Copy link
Copy Markdown
Owner

Bug

In the review pipeline, the read-only scoring phase on openrouter/z-ai/glm-5.3 always aborted: GLM called write_report with rejected arguments six times in a row and the loop guard stopped the phase (run 20261020-091952-sup5):

  1. and 2. {markdown, confidence, commit: {...}}: "read-only phases cannot supply commit metadata"
  2. {markdown, confidence}: "dimensions must include every quality dimension…"
  3. {markdown, confidence, commit: {subject: "noop"}}: same read-only commit error
  4. and 6. {markdown, dimensions: {maintainability: 86.0166}}: "dimensions.prd must be 0–100", then aborted

Root causes: the tool schema was identical for every phase. It offered commit to read-only phases, and it never marked dimensions (or any of its six keys) as required or bounded. GLM follows the schema over the prose. The dimensions error also said prd must be 0–100 when prd was simply missing, so the model couldn't correct itself.

Changes

  1. Per-phase schema. writeReportInputJsonSchemaFor(scope) and writeReportToolDescriptionFor(scope) build the contract from a WriteReportScope (writable, scoring), which writeReportScope(agentName, readOnly) derives from the phase:

    • read-only: no commit, and the description doesn't invite one
    • non-scoring: no dimensions / mustFix / gaps / confidence
    • scoring: dimensions is required, with all six keys (taken from qualityDimensions) required as {type: "number", minimum: 0, maximum: 100}

    OpenCode: V2 registers a plugin tool once per server, and the plugin is installed once per run. So the generated plugin still registers the unscoped tool, and it also embeds a per-agent map built from the run's agents. A ctx.session.hook("context", …) swaps in that agent's scoped write_report entry on each model request. An agent's read-only flag is its phase's, because forced read-only steps run on the synthesized __ro agent. Sessions on other agents keep the unscoped schema.

    CLI runners (Claude/Codex): the attempt bridge passes the scope to the MCP host as CONVOY_REPORT_SCOPE, so every runner offers the same contract.

  2. Clearer dimensions error. Missing keys are reported separately from invalid values, all at once, along with what was received. Examples: dimensions is missing prd, tests, security, operational, scope (received: maintainability) and dimensions.prd must be a number from 0–100 (received: "85"). A missing dimensions and a non-object dimensions each get their own message.

The loop guard and the read-only commit rejection are unchanged.

Testing

  • bun run typecheck: clean
  • bun test: 3972 pass, 1 skip, 0 fail
  • New unit tests: the schema for each scope (read-only has no commit; non-scoring has no scoring fields; scoring requires all six bounded dimensions); the generated plugin's context hook applied per agent; the MCP host's scoped schema and the Codex bridge file's scope; the new dimensions error messages (missing keys, wrong type, out of range, combined, missing, non-object)
  • New integration test against the real opencode runtime with a scripted provider: implementer, bug-auditor and quality-scorer are each offered their own scoped write_report parameters. It passes on opencode 2.0.32 and on 2.0.26 (the version CI pins).

🤖 Generated with Claude Code

…ing dimensions

The write_report schema was static: read-only phases were offered commit,
non-scoring phases the scoring fields, and a scoring phase was never told
dimensions (or any of its six keys) is required or bounded. Models that
follow the schema over the description (GLM 5.3 on the review score phase)
were rejected six times in a row and the loop guard aborted the phase.

- Build the schema and description from the phase's scope (writable,
  scoring). OpenCode registers the tool once per server, so the plugin
  narrows it per run agent through the session context hook; the CLI
  runners' MCP host reads the scope from the attempt bridge.
- dimensionsError now names every missing key with what was received,
  every wrong-typed or out-of-range value, and a non-object dimensions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Inakitajes
Inakitajes merged commit 47b3db7 into main Oct 20, 2026
2 checks passed
@Inakitajes
Inakitajes deleted the fix/write-report-phase-schema branch October 20, 2026 11:21
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