Skip to content

[Bug] Build agent reads designs from flat files, so orchestrator-run sections can't be built #4

Description

@sjohnston1972

Part of the "SQLite migration is half-done" parent issue.

Background

The orchestrator runs a designer/critic loop per section and saves each result to the SQLite section_designs table (backend/app/agents/orchestrator.py, step 3 in _drive_run_inner, writing SectionDesign.record). The build agent turns an approved design into a sandbox topology.

Problem / Goal

backend/app/agents/build.py:210 (converse_build) resolves the design it is about to build by calling get_design(design_id), imported from app.agents.loop. That function (backend/app/agents/loop.py:92) only reads data/designs/<id>.json from disk. Orchestrator designs live in SQLite, not on disk, so there is no way to build a sandbox from an orchestrator run — the core v2 workflow dead-ends.

Goal: let the build flow accept a SectionDesign (SQLite integer id) and read its record from the DB.

Where to look

  • backend/app/agents/build.py:190-306converse_build, where get_design is called and final_design = iterations[-1]["design"] is extracted.
  • backend/app/agents/loop.py:92 — the current flat-file get_design.
  • backend/app/db/models.py:82SectionDesign; its .record column already holds the exact dict shape the build agent expects ({"iterations": [...], ...}).
  • backend/app/api/build.py:37-67BuildConverseRequest.design_id and the converse endpoint.
  • backend/app/api/runs.py:112GET /api/runs/{run_id}/sections/{section_id} shows how a section record is fetched from SQLite.

Suggested approach

  1. Add a DB-backed lookup that, given a SectionDesign.id, opens a session (from app.db.session import engine), fetches the row, and returns sd.record (or None).
  2. Change converse_build to use that lookup instead of loop.get_design.
  3. Decide how design_id is typed on the request: accept the integer SectionDesign.id. Keep backward tolerance for the legacy hex id only if a flat-file fallback is still desired (optional; the parent issue's direction is SQLite-first).
  4. Guard the "no iterations" / "no design" error paths that already exist (build.py:215-219).

Acceptance criteria

  • Given an approved SectionDesign, POST /api/build/converse produces a topology and a saved build.
  • Building an orchestrator-run section no longer requires any file under data/designs/.
  • Missing/invalid section ids return a clean error event ({"type":"error", ...}), not a 500 traceback.

Testing

Local backend (cd backend && uvicorn app.main:app --reload --port 8080):

  1. Run intake + a run until one section is approved (see parent issue Testing).
  2. Note the section id from GET /api/runs/{id}.
  3. POST /api/build/converse with that id; confirm it streams to build_saved.

Add a unit test that stubs the DB session and asserts converse_build reads from SectionDesign.record.

Out of scope

  • Where the build record is saved (that's the BuildRecord sub-issue).
  • Frontend wiring of a "Build this section" button (backend contract only here).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions