Skip to content

refactor(AI-006): single shared verdict-JSON extractor in ai_runtime#100

Merged
DoRmAmMu1997 merged 3 commits into
mainfrom
refactor/ai-006-json-extractor-dedup
Jul 11, 2026
Merged

refactor(AI-006): single shared verdict-JSON extractor in ai_runtime#100
DoRmAmMu1997 merged 3 commits into
mainfrom
refactor/ai-006-json-extractor-dedup

Conversation

@DoRmAmMu1997

Copy link
Copy Markdown
Owner

Ticket scope (AI-006)

Goal: eliminate the last copy-paste-drift hazard in the Claude-agent subsystems. The three agents (backend/fundamentals/fundamental_agent.py, backend/technical/technical_agent.py, backend/sixty_seven/agent.py) each carried a private _extract_json_object — the tolerant "fenced block, then outermost {...} span" verdict extractor. REFACTOR-003 (#93) deduplicated the sync bridge after one of its three copies drifted; its ADR accepted the extractor leftover as a Con. This ticket re-opens exactly that accepted Con, deliberately.

In scope

  • backend/ai_runtime.py: new public extract_json_object(text) -> dict | None, moved verbatim (the three copies were verified logic-identical line-by-line before the move — only docstrings differed).
  • Each agent replaces its local copy with from backend.ai_runtime import extract_json_object as _extract_json_object — the alias keeps every call site, parse-fallback path, and test seam byte-identical. Now-unused import re lines removed.
  • ADR amendment in docs/architecture/refactor-003-ai-runtime.md: documents why the extractor met the same three-part test as the bridge (shared-and-identical / correctness-critical / drift-prone) and why this does not reopen the rejected Option B (options-construction blocks differ for real domain reasons and stay per-agent).
  • 8 extractor unit tests in tests/test_ai_runtime.py: bare object, ```json fence, fence without language tag, surrounding prose, empty text, no braces, unparseable braces, reversed braces.

Out of scope (deliberate)

  • Usage-limit helpers stay where they are_usage_limit_from_message / _mentions_usage_limit are already single-sourced in fundamental_agent and imported by the other two; no drift risk exists there.
  • No Option B creep — SDK options construction, retry loops, and error taxonomies remain per-agent (they differ materially; unifying them was rejected in the original ADR and that rejection stands).
  • No behavior change anywhere: the extractor logic is character-identical to all three replaced copies.

Behavior lock: the three agent suites (212 tests) pass unmodified — no test file for the agents was touched.

This is ticket 3 of a 10-ticket second improvement wave (TEST-007 #98, REF-003 #99, AI-006, IPO-006, TEST-006, PERF-002, DEPLOY-004, QUAL-006, QUAL-007, DOC-003), each shipped as its own PR off main.

Gates (all green, local, Python 3.13)

Gate Result
pytest -q --cov=backend --cov=screeners --cov=ui --cov-fail-under=87 1,394 passed, 1 skipped; coverage 88.17%
Three agent suites 212 passed, unmodified
pre_commit validate-config clean
compileall clean
ruff check clean
mypy (119 files) clean
bandit clean
pip_audit -r constraints.txt no known vulnerabilities

constraints.txt / pyproject.toml diff vs main: empty (as required).

Review

/code-review: Approve — the moved function is verbatim (diff-verified against all three originals); the aliased import preserves each module's private name so no call site changed; dead import re removals confirmed by ruff. /security-review: no findings — the extractor consumes model output that is already inside the trust boundary established by the agents' prompt-injection quarantine, and the shared implementation removes the risk of one copy silently diverging on parse tolerance (a consistency win for the fail-closed verdict validation downstream).

🤖 Generated with Claude Code

The three Claude-agent subsystems each carried a private
_extract_json_object copy (fundamental_agent, technical_agent,
sixty_seven/agent). The copies were logic-identical (verified line by line
- only docstrings differed), which is the same drift-prone shape as the
_run_sync bridge REFACTOR-003 deduplicated after it DID drift once. Two of
the copies even said "kept local so the agents stay independent" while
being character-for-character the same logic.

- backend/ai_runtime.py: add extract_json_object(text) - the tolerant
  fenced-block-then-outermost-span extractor, verbatim.
- Each agent now does
  `from backend.ai_runtime import extract_json_object as _extract_json_object`
  so every call site, parse-fallback path, and test seam is unchanged; the
  now-unused `import re` lines are removed.
- ADR amendment (docs/architecture/refactor-003-ai-runtime.md): the
  extractor met the same shared-and-identical/correctness-critical/
  drift-prone test as the bridge; the options-construction blocks remain
  per-agent (this does NOT reopen Option B).
- tests/test_ai_runtime.py: 8 extractor tests (bare object, json fence,
  fence without language tag, surrounding prose, empty text, no braces,
  unparseable braces, reversed braces).

Behavior lock: the three agent suites (212 tests) pass unmodified.

Gates: 1,394 passed, coverage 88.17% (floor 87); pre-commit validate,
compileall, ruff, mypy (119 files), bandit, pip-audit all clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@DoRmAmMu1997 DoRmAmMu1997 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Self-review (posted as COMMENT — the bot runs as the PR author and cannot APPROVE). Verdict: Approve.

Checks performed against the diff:

  1. Verbatim move — the three replaced copies were compared line-by-line before the move: same fence regex, same find/rfind outermost-span fallback, same json.JSONDecodeError guard, same isinstance(parsed, dict) gate. Only docstrings differed. The shared implementation is character-identical in logic to all three.
  2. Call sites untouched — the aliased import (extract_json_object as _extract_json_object) re-creates each module's private global, so the three internal call sites resolve identically; repo-wide grep confirms no test references the private name.
  3. Behavior lock holds — the three agent suites (212 tests) pass with zero modifications to their files, and 8 new extractor tests in tests/test_ai_runtime.py cover the ticket-spec cases (fenced / prose-wrapped / no-JSON) plus edges (missing language tag, empty text, unparseable braces, reversed braces → None, not an exception).
  4. No cycle, no dead importsai_runtime remains a stdlib-only leaf; import re removed from all three agents (no remaining re. usage); json retained where still used.
  5. ADR amendment — honest about re-opening REFACTOR-003's accepted Con, explicit that Option B (options-construction/retry/error-taxonomy unification) stays rejected; usage-limit helpers deliberately left single-sourced in fundamental_agent.
  6. Known pre-existing quirk, deliberately preserved — a message with two fenced JSON blocks greedily captures across both and returns None (no span fallback). Identical in all three replaced copies; changing it would be out-of-scope behavior change.

Gates: 1,394 passed + 1 skipped, coverage 88.17% (floor 87); agent suites 212/212 unmodified; ruff/mypy(119)/bandit/pip-audit/pre-commit/compileall clean; constraints/pyproject diff vs main empty. Security review: no findings (parse-only helper; Pydantic validation and the injection quarantine downstream are untouched).

Copy link
Copy Markdown
Owner Author

Codex review plan before fixes:

  • Make the shared verdict JSON extractor reject non-standard NaN, Infinity, and -Infinity constants.
  • Treat JSON ValueError and RecursionError as normal parse failures.
  • Configure strict AI models with allow_inf_nan=False as a second boundary.
  • Add retry/error-receipt tests proving invalid model values never reach cache signing.

I’ll implement these with TDD, run the full gates and diff-security review, and push the follow-up to this branch.

@DoRmAmMu1997 DoRmAmMu1997 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Codex review finding for AI-006: the shared parser must define a strict JSON boundary because all three agents now trust it.

Comment thread backend/ai_runtime.py Outdated
DoRmAmMu1997 and others added 2 commits July 11, 2026 18:36
Co-authored-by: Hemant <hemantdhamija@gmail.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Hemant <hemantdhamija@gmail.com>
Co-authored-by: Codex <codex@openai.com>
@DoRmAmMu1997 DoRmAmMu1997 merged commit 1f67d59 into main Jul 11, 2026
3 checks passed
@DoRmAmMu1997 DoRmAmMu1997 deleted the refactor/ai-006-json-extractor-dedup branch July 11, 2026 13:32
@DoRmAmMu1997

Copy link
Copy Markdown
Owner Author

Completion verdict

Complete — no remaining reportable findings. This is a completion comment, not an approval.

Commits 52a1d78 and 7938e99 hardened the shared verdict-JSON path by rejecting NaN, Infinity, and -Infinity; catching ValueError and RecursionError; enforcing allow_inf_nan=False; and adding retry and cache-signing coverage. Verification completed with 1,401 tests passed, 87.93% coverage, and green hosted CI.

A formal diff-security review found no remaining reportable findings.

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