Skip to content

research_workflow(scaffold): the --outline JSON is shape-trusted — wrong shapes and non-JSON fail with raw type errors naming no file or field #6862

Closed

Description

@dezren39

Problem

scripts/research_workflow.py's init command (scaffold()) reads the --outline JSON file with a bare json.loads(...) (research_workflow.py:243-244) and then uses the parsed value's fields raw. Sibling inputs in the same tool were hardened in #6854 (profile/state/trigger shapes) and #6857 (note/resolution shapes), but the outline — the file that seeds a new research package's title, concepts, and state — was not covered. A valid-JSON-but-wrong-shape (or non-JSON) outline therefore surfaces as a bare Python error that names neither the file nor the field, instead of the tool's own fail() diagnostic used everywhere else in the file. The CLI (main(), research_workflow.py:1079-1088) catches these types, so the run exits 1 with e.g.:

$ research_workflow.py init --input transcript.txt --slug x --outline outline.json
error: 'list' object has no attribute 'get'

— an operator cannot tell which field of which file is malformed.

Evidence (verified this run, laptop @ 65beb42, real files verbatim, probe ~/git/fleet/probe-rw-scaffold-outline/)

The probe copies scripts/research_workflow.py (+ its two extension modules) verbatim from origin/main (md5 match), builds a fixture repo root with a valid profile, and drives the real CLI (init --allow-duplicate, 2-line transcript).

Control: a well-formed outline (object with string title, one concept with string title/slug/summary and source_lines: [[1, 2]]) scaffolds successfully (rc=0, package created). No malformed case creates a partial package.

Wrong shapes (all raw, none via fail()):

  • Outline top level [] → error: 'list' object has no attribute 'get'; "x" → same for str — outline.get("title", "") at research_workflow.py:262 runs before any isinstance guard.
  • Outline title: 42 → error: expected string or bytes-like object, got 'int' — re.search(...) on the unchecked title at :262.
  • Concept entry "just-a-string" → error: 'str' object has no attribute 'get' — concept.get("title") at :271.
  • Concept slug: 42 → error: expected string or bytes-like object, got 'int' — slug() runs re.fullmatch on the unchecked value (:276 → :121-124). An explicit "slug": null takes the same path.
  • Concept summary: 42 → error: can only concatenate str (not "int") to str — summary is concatenated raw at :355 (its thoughts/suggestions siblings ARE validated as string lists at :294-298; summary is not).
  • Outline file containing non-JSON (not json{) → error: Expecting value: line 1 column 1 (char 0) — the bare json.loads at :244; the message names no file.

Why it matters

The outline is the machine-generated seed for every new research package (produced by the research-prepare step and handed to init); a truncated or mis-shaped generation is exactly the corruption this tool's fail() idiom exists to diagnose precisely. Today the operator gets a type error with no file, no field, and no expected shape, and must read the source to find which of the outline's fields is wrong. This is one more instance of the #3068 parsed-is-not-validated pattern, in the one research_workflow.py input surface #6854/#6856/#6857 did not reach.

Acceptance criteria

  • scaffold() validates the outline before use: non-object top level, non-JSON body, non-string title/introduction, non-object concept entries, non-string concept slug, and non-string concept summary each fail via fail() with a message naming the outline file and the field/expectation.
  • Validation happens before any package directory is created (today's no-partial-package property is preserved).
  • Regression tests in scripts/tests/test_research_workflow.py cover each wrong shape above and assert the clean fail() diagnostic.
  • A valid outline behaves byte-identically to today (existing test suite green; the probe control above still scaffolds).

Activity

  1. developing-today commented on Nov 7, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/research-workflowscripts/research_workflow* + sync_research_workflow tooling
    on Nov 7, 2026
  3. dezren39 commented on Nov 7, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-11-07 03:35 CST
    • Found via: filed this run
    • Task: Validate the init --outline JSON shape in scripts/research_workflow.py's scaffold() with the tool's fail() idiom — top level, title/introduction, concept entries, slug and summary are used raw today, so wrong shapes and non-JSON fail with bare type errors naming no file or field. Verified this run on the laptop @ 65beb42 (probe ~/git/fleet/probe-rw-scaffold-outline, real files verbatim + real CLI: 7 wrong shapes raw, valid-outline control OK, no partial package).
    • Expectation: effort s — shape validation in scaffold() plus regression tests in scripts/tests/test_research_workflow.py; "done" is every wrong-shape outline failing with a fail() diagnostic naming the outline file and field, valid outlines byte-identical.
    • Links: queue packet enqueued this run (repo-health-code-pilot)
  4. developing-today commented on Nov 8, 2026

    @developing-today
    Contributor

    🤖 Agent note · picked up

  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 8, 2026
  6. 5 remaining items

  7. dezren39 commented on Nov 8, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 8, 2026
  9. added a commit that references this issue on Nov 8, 2026
  10. dezren39 commented on Nov 8, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/research-workflowscripts/research_workflow* + sync_research_workflow toolingkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobstatus:donetask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions