Skip to content

fleet(queue): packet string fields and string-list elements are never type-checked — body, problem, evidence & friends accept numbers/objects and are forwarded verbatim #6430

Open

Description

@dezren39

Problem

validate_packet in the fleet-queue crate type-checks some packet fields but not the packet's string fields or string-list elements. A packet whose top-level body is a number/object/array/bool, whose payload problem or priority_reason is a number/object/array, whose evidence / acceptance / tests / context_refs lists contain numbers, nulls, objects, bools, or nested arrays, whose scope.include / scope.exclude / risk.flags lists contain non-strings, or whose dedupe.checked_at / dedupe.basis are numbers validates with zero errors and zero warnings — and task_from_packet forwards every one of those values verbatim into the agent.tasks row the broker inserts on /enqueue. The queue worker and every packet consumer downstream then read strings that are not strings.

This is the same shape-vs-type gap #5549 fixed for packet identity (placeholder prs elements like [null], [{"number": "5424"}], [{}] used to pass on the array being non-empty alone). The identity fields got element-type checks; the prose fields never did.

Evidence (all at origin/main a2b4345e80; validate.rs md5-identical in the laptop primary, origin, and the probe copy)

  • pkgs/fleet/crates/fleet-queue/src/validate.rs:38-46 — is_empty() returns false for any number/bool value, so a non-string can never be "empty".
  • validate.rs:72-76 — payload problem / priority_reason are checked only with is_empty(...): problem: 123 and problem: {"x": 1} pass.
  • validate.rs:77-88 — payload evidence / acceptance / tests / context_refs are checked only for being a list (and, for the first three, non-empty). Element types are never inspected: evidence: [123], [null], [{"x": 1}], tests: [["t"]] all pass.
  • validate.rs:91-94 and :101-103 — scope.include and risk.flags get the same list-only check; scope.exclude gets only the is_empty check: [123] passes everywhere.
  • validate.rs:115-116 — dedupe.checked_at / dedupe.basis are checked only with !is_empty(...): the number 123 passes for both.
  • validate.rs:467-474 — top-level body is read only if let Some(Value::String(body)), for the >250-word warning. A non-string body skips even that; an empty-string body passes silently too (contrast title at validate.rs:~455, which is required to be a non-empty string — the probe's title: 123 control correctly errors).
  • validate.rs:521 — task_from_packet copies packet.body verbatim into the task row; the whole payload (with the malformed fields above) is copied verbatim at the same time.
  • pkgs/fleet/crates/fleet-queue/src/queue_broker.rs:327-347 — the broker's /validate and /enqueue both run this same validate_packet, and /enqueue inserts task_from_packet's output. There is no second, stricter layer for non-CLI callers; the tasks table's payload is jsonb, so the database accepts the malformed values as-is.

Verified this run (laptop probe, real crate)

Probe ~/git/fleet/probe-queue-body on the laptop, built against the real fleet-queue crate (path dependency, queue-broker feature), calling validate_packet + task_from_packet on an otherwise-valid packet (the same base packet shape the #6426 probe used):

  • Control (valid packet): errors=[] warnings=[], fields forwarded as strings.
  • Controls that must fail, and do: title: 123 → ["packet.title: required non-empty string"]; evidence: [] → ["payload.evidence: must not be empty"].
  • All 19 malformed cases returned errors=[] warnings=[] and were forwarded verbatim in the task row: body = 12345 / {"x":1} / ["a"] / true / ""; problem = 123 / {"x":1}; priority_reason = ["r"]; evidence = [123] / [null] / [{"x":1}]; acceptance = [false]; tests = [["t"]]; context_refs = [42]; scope.include = [123]; scope.exclude = [123]; risk.flags = [123]; dedupe.checked_at = 123; dedupe.basis = 123.

Why it matters

The packet is the queue's contract: producers are scripts and agents, and a producer bug that emits evidence: [null] or problem: 123 (a JSON-serialization slip, a templating bug) currently enqueues a task that looks valid in every listing — the worker only discovers the corruption when it tries to read the evidence/acceptance strings mid-task, if it notices at all. The validator already type-checks title, priority, dedupe_key, issue.number, and (since #5549) every prs element, precisely so malformed packets die at the producer with an error naming the field. The prose fields are the unguarded remainder of the same contract.

Acceptance criteria

  • validate_packet rejects a top-level body that is present and not a string, with an error naming packet.body; string bodies keep the existing word-count warning behavior.
  • validate_packet rejects non-string payload.problem / payload.priority_reason and non-string payload.dedupe.checked_at / payload.dedupe.basis, with errors naming the field.
  • validate_packet rejects any non-string element in payload.evidence, payload.acceptance, payload.tests, payload.context_refs, payload.scope.include, payload.scope.exclude, and payload.risk.flags, with errors naming the field (index included where the codebase's message style allows).
  • Every real packet in the fleet corpus still validates (the fleet-queue(validate): payload identity accepts placeholders — prs:[null], string/absent PR numbers, and set:{} validate with no usable identity #5549 fix verified the same property for identity shapes: 87/87 real prs elements already conformed — the fix should re-run that corpus check for the newly typed fields).
  • Tests pin each malformed case above plus the valid control, in the style of the existing validate.rs tests (placeholder_identities_do_not_validate).

Dedup / relations

Activity

  1. developing-today commented on Nov 6, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    app/fleetpkgs/fleet multicall binary + platform crates
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 6, 2026
  3. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    Lane B (code-b) claimed task 10881 for issue #6430. Execution-lane assignment returned opencode (§1b), so this task is handed off to the opencode claimant — checkpointed handed_off and parked 1200s for the claimant to launch the bound session. Issue verified OPEN with no hard-stop labels (held / user/owned / do-not-merge / do-not-auto-edit).

  5. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 6, 2026
  6. 36 remaining items

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

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. 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 Nov 6, 2026
  10. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  11. dezren39 commented on Nov 6, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

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/fleetpkgs/fleet multicall binary + platform crateskind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/parkedQueue task is parked (waiting on CI, time, or an event)source/creatorFiled by the new-issue-creator jobsource/design-architectFiled by the repo design architect jobstatus/parkedDeliberately paused with a recorded resume conditiontask/triageQueue packet kind: verify, reproduce, and route this itemwork/assignedQueue worker lifecycle state

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions