Skip to content

Worker item kind exists only as prose in agents[].label, so comparable work cannot be grouped without matching text #331

Description

@thedavidmeister

Problem

Nothing records, as a typed field, what KIND of work item a dispatched worker handled. The only carrier is agents[].label, which is free prose the main loop writes:

"Rework cyclo.site#434"
"Fix red PR st0x.deploy#300"
"Mutation pass on PR 160 diff"
"Rework rain.erc4626.words#188"

So grouping comparable work — every rework item, every step-3b red triage — means pattern-matching that prose. That is the exact shape the org has ruled against: a heuristic join over text, where the fix is to capture the fact typed at its source.

Why it blocks measurement

Run cost is dominated by WHICH work the queue served, not by how efficiently it was done. Measured across four producer runs:

run usd wall worker mean work drawn
20260816T170156Z 18.32 31m 2.42 5 step-3b red PRs (triage)
20260817T000148Z 20.30 68m 2.49 5 rework items (CI round-trips)
20260817T050103Z 10.84 28m 1.24
20260817T110404Z 25.50 46m 3.08

A 2.4× spread in run cost, with the two runs whose composition is known differing in kind rather than in efficiency. Any before/after comparison over run totals is therefore measuring the queue's draw, not the change under test — which is why the backgrounding change (#327) could not be evaluated: a ~9% effect inside one worker is invisible against that.

The fix is to compare like with like — rework workers against rework workers — and that needs the kind as data, not as a substring of a label somebody wrote for a human to read.

Why not parse the label

  • It is written for a reader, so its shape is whatever the main loop chose that run. Nothing constrains it and nothing fails when it changes.
  • The vocabulary is not declared anywhere: "Rework", "Fix red PR", "Mutation pass" are observed, not specified, so a matcher is a guess about a set nobody owns.
  • A run that phrases it differently silently drops out of the grouping, and the resulting figure is quietly computed over fewer items with no signal that it was.

The producer already CLASSIFIES the item before dispatching it — the prompt's step 3b routing decides red-triage vs rework vs migration vs design. That classification exists and is then thrown away, leaving prose behind.

Proposed fix

Emit the item kind as a typed field on the agents[] entry at dispatch, from the classification the producer already performed — not derived afterwards from the label.

The vocabulary should be the one the routing step already uses rather than a new one invented here; whoever implements this should read campaign-prompt.txt's step 3b and take its categories verbatim, so the field and the routing cannot drift into two different taxonomies. Where an item genuinely does not fit a category, an explicit other is honest and a silently absent field is not.

Note what this is NOT: it is not a regex over label, and it is not a mapping table maintained beside the prompt. Either would reproduce the defect one level down — a second source of truth for a fact the router already knows.

Done when

  • Every agents[] entry carries the item kind as a typed field, written at dispatch.
  • The kind's vocabulary is the routing step's own, with a test pinning the two together so a new route cannot appear without the field learning it.
  • "Tool calls per rework worker, before vs after" is a query over metrics/runs.jsonl, with no prose matching anywhere in it.

Related

rainlanguage/issue-pr-cron — per-agent toolCalls (filed alongside this). The two compose: the kind says which workers are comparable, toolCalls says what to compare. Neither is useful alone for this question, and both are useless until enough runs accumulate — KEEP_RUNS was raised from 20 to 2000 on 2026-08-17, so the history starts rebuilding from the next producer tick.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions