Skip to content

fix(OMN-17427): enforce json_schema for local-coder code-edit turns - #3295

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-17427-code-edit-structured-output
Oct 3, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-17427-code-edit-structured-output

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The worst answer-quality class in the last 24 h of lab delegation is code_generation turns from the delegated code-edit loop refused no_schema_conforming_json: the model answers a prose line instead of the declared JSON object. This declares supports_response_format_json_schema: true on local-coder, so the code-edit response contract goes out as a provider-native json_schema constraint instead of prose only, and closes each action in that contract over its own tool's arguments so the gate and the loop's parser accept the same replies. On the same 20 failing turn prompts, first-attempt acceptance on local-coder went from 12/20 to 20/20.

Ranking (lab dev lane, last 24 h)

task_type events gate failed failure rate local-rung climbs
code_generation 938 43 4.6% 468
document 611 34 5.6% 16
review 117 29 24.8% 0
summarization 235 14 6.0% 31
test 22 3 13.6% 10

Most terminal failures in document and review are timeouts, provider errors and runtime shutdowns, not answer quality. In code_generation the largest answer-quality class is DELIVERABLE_EXTRACTION: no_schema_conforming_json: 304 attempts across 170 events, every one on a code-edit loop turn; local-coder 234 of its 747 code-edit attempts, local-omnipc2-chat 48 of 485.

Cause

The response contract reaches local-coder only as prose inside a 20-30k token prompt, and the model drifts into narration instead of emitting schema-conforming JSON.

  • Read 20 failing code-edit turn prompts from the projection and replayed them on the .201 endpoint the way local-coder sends them (same system prompt composition, enable_thinking false, no response_format): 18 of 23 replies refused no_schema_conforming_json. The replies were one prose line such as "I'll write a Python script to do both steps, then run it." or "I need to see the remaining sections of the files I'll edit before making changes.", or empty content; one repeated "</no_think>" lines.
  • The prompt states the JSON reply format once at the top of a 20-30k token prompt whose HISTORY renders actions as "> view(path=...) -> ok"; the model drifts into narration.
  • Category: the response contract. It reaches local-coder only as prose. local-coder does not declare supports_response_format_json_schema, while local-heavy-reasoning, on the same endpoint (BIFROST_LOCAL_CODER_ENDPOINT_URL) and served model Qwen3.8-27B, does.
  • Same replay with response_format json_schema: 0 of 20 refused; 2 of 20 still rejected by the loop's parse_turn_reply ("action 6 (grep) takes no name, summary") because the flat item schema allowed every argument on every tool; with a per-tool contract both parsed.
  • The earlier lane's code_review prompt-template change was not repeated; this is a capability declaration and a response-contract change, not a template change.

Change

  • src/omnimarket/configs/bifrost_delegation.yaml: local-coder declares supports_response_format_json_schema: true, with the probe evidence in a comment.
  • node_delegated_code_edit_orchestrator/handlers/turn_protocol.py: RESPONSE_CONTRACT items are an anyOf of one closed object per tool (two for replace_in_files: file_paths or glob), derived from ALLOWED_ARGUMENTS and REQUIRED_ARGUMENTS; parse_turn_reply, build_turn_prompt and TOOL_SCHEMAS unchanged.
  • Tests updated for the new contract shape; new tests for contract/parser agreement and for local-coder declaring the flag.

A/B: same 20 prompts through onex delegate

All arms: onex delegate --task-type code_generation --backend-id local-coder --response-contract <code-edit contract> over the same 20 failing code-edit turn prompts; pass = the first attempt accepted by the quality gate.

arm route config first attempt accepted other runs runs ending accepted (on local-coder)
before dev lane (--bus kafka --lane dev --locus deployed-lane) deployed omnimarket 0.4.283 12/20 8 first attempts refused no_schema_conforming_json; 29 attempts in all 19/20 (15/20)
before in-process (--bus inmemory --locus in-process) packaged contract 12/20 2 accepted on a retry, 5 failed after 3 local-coder attempts, 1 cancelled at the 240 s budget 14/20 (14/20)
after in-process this branch's bifrost_delegation.yaml and RESPONSE_CONTRACT 20/20 none; 20 attempts in all 20/20 (20/20)
control in-process this branch's RESPONSE_CONTRACT, flag off 9/20 7 accepted on a retry, 4 failed after 3 local-coder attempts 16/20 (16/20)

The in-process arms raise local-coder's max_grounded_input_tokens from 8000 to 60000 in both before and after, because the in-process path refuses these 20k-token prompts at the 8000 grounding budget and the dev lane does not; nothing else differs between before and after. The after arm cannot run on the dev lane until this deploys, because the deployed lane runs the released contract and a pin to local-heavy-reasoning for code_generation is refused by routing; the control arm shows the json_schema directive carries the gain.

Lab readback

Runtime-affecting (routing contract). Lab evidence above is from h201 against the .201 endpoint, after-arm run ids d7086335-43b2-4125-a15d-fa2ec38966a6, 0b47cc17-7670-43a6-8fcf-a6268354532f, ce33b7d1-7b19-46e9-9c75-c92296e6bbf0 (first three of twenty). After deploy, the readback is the same 20 prompts on the dev lane pinned to local-coder, expecting first-attempt acceptance near 20/20, and the no_schema_conforming_json count on local-coder in delegation_events falling.

Tests

Focused: test_handler_delegated_code_edit_orchestrator.py, test_declared_label_set_membership_omn18989.py, test_loop_ports.py, test_tool_use_rubric.py: 336 passed. Routing/config files (same-model spread, in-process spread, weighted spread, runtime dispatch port, wire completion fidelity, backend id model family, routing authority gate, bifrost renderer reducer seam): 75 passed. ruff check, ruff format --check and mypy --strict on turn_protocol.py clean; pre-commit passed.

Ticket: OMN-17427

Evidence-Source: OCC#12518
Evidence-Ticket: OMN-17427

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

⚠️ Architectural Review — WARNINGS

Errors: 0
Warnings: 1

What this checks

Rule Description
ARCH-TOPIC-001 No hardcoded Kafka topic strings in handler code
ARCH-DI-001 No event_bus=None bypass
ARCH-DI-002 No direct Handler instantiation outside workflow_runner/adapters
ARCH-DI-003 No reinvented DI containers
ARCH-TOPIC-002 contract.yaml topics follow `onex.{cmd

ARCH-DI-002: Direct Handler instantiation (warning)\n\n```\nsrc/omnimarket/cli/cli_local.py:236: HandlerLocalDashboardServe().handle(

src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:965: self._effect_handler = effect_handler or HandlerLlmDelegationCall()
src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:966: self._projection_handler = projection_handler or HandlerProjectionDelegation(
src/omnimarket/nodes/node_delegate_skill_orchestrator/ports/port_local_delegation_dispatch.py:3289: HandlerProjectionLlmCost().project(call_event, self._evidence_db)
src/omnimarket/nodes/node_delegation_orchestrator/handlers/handler_delegation_workflow.py:1370: loop = HandlerComplianceLoop()
src/omnimarket/nodes/node_delegation_orchestrator/handlers/handler_delegation_workflow.py:2265: HandlerEscalationDecision()
src/omnimarket/nodes/node_local_dashboard_serve_effect/handlers/handler_local_dashboard_serve.py:226: handler=HandlerProjectionRead(topic_map=topics, row_source=source),\n```\n\nHandler classes should be wired only in workflow_runner.py or adapter modules. Direct instantiation elsewhere bypasses the contract system.\n\n

Static architectural lint — no model inference (OMN-14176).

@jonahgabriel
jonahgabriel enabled auto-merge (squash) October 3, 2026 06:50
local-coder now declares supports_response_format_json_schema: true.
This aligns with local-heavy-reasoning, which serves the same model.
The code-edit turn protocol now closes each action over its own tool.
Arguments come from ALLOWED_ARGUMENTS and REQUIRED_ARGUMENTS.
This ensures replies accepted by the gate are parse_turn_reply valid.
In the last 24 h, 304 local-rung attempts were refused no_schema.
All refusals occurred on code-edit loop turns in the dev lane.
A/B on 20 failing turn prompts: first-attempt accepted 12/20 -> 20/20.
@jonahgabriel
jonahgabriel force-pushed the jonah/omn-17427-code-edit-structured-output branch from 6988fa0 to 397b422 Compare October 3, 2026 06:51
@jonahgabriel
jonahgabriel changed the base branch from main to dev October 3, 2026 06:51
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

✅ Hostile Reviewer — PASSED

Blocking findings (critical/error): 0
Total findings: 12
Models succeeded: qwen3-review,gpt-oss-review


Gate semantics

Verdict Meaning Blocks merge?
passed >=2 models succeeded, no critical/error findings No
blocked CRITICAL or ERROR findings found Yes
degraded Fewer than 2 models succeeded (infra unavailable/timeout) Yes (OMN-15110)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)

@jonahgabriel

Copy link
Copy Markdown
Contributor Author

Lab: host=h201 lane=deleg-quality-2-2a21 head=397b42253 rebase and retarget complete
Rebased onto dev (0c3748b) and retargeted to dev, new head 397b422
RESPONSE_CONTRACT at head is byte-identical to the one measured in the body
Measured against omnimarket 0.4.283@117b144 (dev at #3285), both on dev lane and in-process
Command: onex delegate --task-type code_generation --backend-id local-coder --response-contract
Observed: 12/20 before (dev lane), 12/20 before (in-process), 20/20 after (in-process), 9/20 control
Focused tests after rebase: 351 passed; ruff, ruff format and mypy --strict clean

@jonahgabriel
jonahgabriel merged commit 6203815 into dev Oct 3, 2026
290 of 326 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-17427-code-edit-structured-output branch October 3, 2026 10:08
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