Skip to content

t3code-seed-providers: seed script crashes on parseable-but-wrong-shaped settings.json — one bad shape disables all seeding and the OpenCode-1.x safety disable #2738

Closed

Description

@dezren39

Summary

t3code-seed-providers' seed script (pkgs/t3code-seed-providers/seed.sh, embedded Python) only guards against unparseable settings.json — a parseable-but-wrong-shaped document crashes it with a raw traceback, and because the script is set -euo pipefail and runs as the t3code-seed-providers oneshot user unit (home/common/default.nix:528, Before=t3code.service), one bad shape silently disables all seeding on every boot — including the OpenCode-1.x safety disable, which is the one part that exists to protect the shared 2.x session DB.

Hand-editing settings.json is explicitly supported upstream (the file's own header says so), so wrong shapes are a realistic input, not a theoretical one.

Evidence (main fa52fcb3, pkgs/t3code-seed-providers/seed.sh)

  • The only shape guard is the try around json.loads at :46-48: unparseable → sys.exit(0) ("don't clobber something we can't parse"). Nothing validates what the parsed value is.
  • doc.setdefault("providerInstances", {}) (:143) assumes doc is a dict.
  • The add loop assumes providerInstances is a dict (instances[k] = desired[k]).
  • The refresh-on-seed loop (:155-162) calls instances[k].setdefault("config", {}) and config.get(...) with no isinstance checks — unlike the safety loop right below it (:173), which does guard isinstance(inst, dict). A crash in refresh also means the safety loop never runs.
  • The unit always sets all four binary env vars (home/common/default.nix:544-549: OPENCODE_V2_BIN, ANTIGRAVITY_ACP_BIN, MUSE_BIN, PI_BIN), so the refresh loop is always armed for the fleet-owned ids.

Verified this run with the real script (md5-matched copy of main's seed.sh; probe on the laptop at ~/git/fleet/probe-2026-10-30-laneB-t3seed/, env mirroring the unit):

  • control {} → rc 0, all instances added (OK)
  • unparseable {not json → rc 0, file untouched (the designed path)
  • [] → rc 1, AttributeError: 'list' object has no attribute 'setdefault'
  • null → rc 1, AttributeError: 'NoneType' object has no attribute 'setdefault'
  • {"providerInstances": []} → rc 1, TypeError: list indices must be integers
  • {"providerInstances": null} → rc 1, TypeError: argument of type 'NoneType' is not a container
  • {"providerInstances": {"muse": "oops"}} → rc 1, AttributeError: 'str' object has no attribute 'setdefault' (refresh loop)
  • {"providerInstances": {"opencode-v2": {"driver": "opencode", "config": null}}} → rc 1, AttributeError: 'NoneType' object has no attribute 'get'
  • config: "oops" → rc 1, same site

In every crash case nothing is written and no seeding happens at all — the adds computed before the crash are discarded with the process.

Why it matters

The seed runs before t3code starts, every boot. A single malformed entry — from a hand edit, a t3 version writing a new shape, or a partially migrated file — turns the unit into a permanent failure whose only trace is a Python traceback in the journal, and the fleet loses three things at once: new-instance seeding, binaryPath refresh (the fix for stranded store paths), and the 1.x safety disable that keeps a V1 binary away from the shared 2.x session DB. The script's own contract for input it cannot handle is "exit quietly and don't clobber" — wrong shapes should get the same treatment as unparseable bytes, or be repaired per-instance, not abort the whole run.

Acceptance criteria

  • A settings.json whose top level is not a JSON object, or whose providerInstances is not an object, no longer crashes the script: it exits without modifying the file and logs a legible reason (stderr), matching the unparseable path's don't-clobber contract.
  • A fleet-owned instance whose stored value (or its config) is not an object does not abort the run: the remaining instances still seed/refresh, and the OpenCode-1.x safety disable still executes; the malformed entry is left untouched and named in the log line.
  • Regression tests (or a scripted fixture run) cover: [], null, providerInstances: [] / null, a fleet instance as a string, config: null / "oops", plus the {} control and the unparseable control.
  • Well-formed files behave exactly as today (adds, refresh, disable, single stderr summary line).

Dedup

  • Searched open + closed issues for t3code seed / settings.json shape handling this run: no match. The seed script and its refresh/safety behaviour have no prior filing.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    app/t3code-seed-providersPackage/app: t3code-seed-providers (pkgs/ or apps/ in this repo)
    effort/xsTrivial: expected under 30 minutes of work
    on Oct 30, 2026
  2. dezren39 commented on Oct 30, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator (lane B, new-issue-creator-code-b)
    • Session / ID: cron new-issue-creator-code-b, run 2026-10-30T12:59Z
    • Found via: filed this run
    • Task: Triage the seed script's shape handling — pin whether wrong-shaped settings.json content gets the don't-clobber exit (like unparseable input) or per-instance skip-and-continue, then route a small_fix packet.
    • Expectation: effort/xs — done looks like shape guards at the doc/providerInstances/refresh sites with the probed regression cases covered, and well-formed files behaving exactly as today.
    • Links: evidence in the issue body; probe on the laptop at ~/git/fleet/probe-2026-10-30-laneB-t3seed/ (real seed.sh, md5-matched to main fa52fcb)
  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  4. 24 remaining items

  5. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 31, 2026
  6. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  7. 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 Oct 31, 2026
  8. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), lane B shift
    • Session / ID: queue task 4410
    • Found via: queue claim (resume from park)
    • Task: PR fix(t3code-seed-providers): handle malformed settings shapes #3131 merged — seed.sh shape guards for wrong-shaped settings.json (top-level/providerInstances don't-clobber exits; malformed fleet-owned instances skipped + named; safety disable hardened). Merge commit 47214f1; this issue auto-closed by the merge.
    • Expectation: done. Verification: Codex review clean on head bdf08b7 (no findings); fixture suite re-run first-hand on the laptop at that head — 3 tests OK; the PR carries no CI workflow runs (nix-ci runs on push/merge_group per the CI tier policy, and the sole PR check, CodeRabbit, was neutral/rate-limited), so the merge proceeded under the standing directive on Codex-clean + first-hand tests.
    • Links: PR fix(t3code-seed-providers): handle malformed settings shapes #3131
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/t3code-seed-providersPackage/app: t3code-seed-providers (pkgs/ or apps/ in this repo)effort/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobsource/design-architectFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions