Skip to content

analysis: dsh-superagent-prototype vs our fleet — findings and adoptable ideas #3450

Open

Description

@dezren39

Standalone analysis commissioned by Drew, 2026-11-01: full comparison of DeepSeek's dsh-superagent-prototype against our repo-health fleet — same-path check, concept mapping, adoptable ideas (fed into #3424 and #3418), and the deliberate differences we keep. Full text below; also sent to Aster for review.

DeepSeek dsh-superagent-prototype vs. our repo-health fleet — comparison & adoptable ideas

Date: 2026-11-01. Scope: whole system, not just code#3424.
Sources read: their docs/000-philosophy.md, 001-domain.md, 002-authorization.md,
003-execution.md, 004-prompts.md, 005-panel.md, 007-architecture.md
(006-deployment / 008-cookbook not read). Ours: goal GOAL.md, code#3424 + newest
comments, code#3418, opencode#1014 + directive comments, fleet instruction files,
standing Drew rules (merge authority, quota doctrine, decision surfacing).
Every claim about their system cites the doc it came from. Nothing posted to GitHub.


1. Their core concepts (compact)

Philosophy / operating stance

  • Prime metric: take as little human attention as possible, give as much value as
    possible; every message, notification, question, setting, and panel element must
    earn its attention cost or be removed (000-philosophy).
  • Acts only when asked, or when a written rule allows it; unrequested work starts
    in a record-only mode (000-philosophy, 002-authorization).
  • Speaks only when a person must act or can use a result; confirms a request once,
    stays quiet while working (000-philosophy, 004-prompts).
  • One concrete question at a time, in structured form (000-philosophy; implemented
    as the Report's structured question field, 001-domain / 003-execution).
  • Stops by impact, not effort: local change → reviewable result; a change needing
    a design decision stops with a clear question (000-philosophy).
  • Honest reporting: drafts marked unfinished, failures reported as failures,
    limits never bypassed to avoid asking (000-philosophy, 004-prompts).

Domain (001-domain)

  • Source — an event stream (kind + instance config); holds its read position and
    bot identity; drops the bot's own messages before they enter the domain.
  • Trigger — one immutable event; the unit of audit and idempotence (accepting it
    twice creates one Ticket).
  • Thread — Triggers in time order; at most one Eval at a time; holds
    Subscriptions and Decision history.
  • Eval — stateless judgement on a batch of Triggers in two layers: a deterministic
    Gate, then model Assessment. Output is a Decision: accept / stop / ignore /
    unavailable.
  • Mandate — what an accept grants: Policy version, scope, strength, matched
    rules, sender identity. Immutable; wider scope = new Ticket; only a person's
    stop withdraws it; revalidated against current Policy before an ended Ticket
    resumes.
  • Ticket — the unit of authorized work; open → ended → resumable by a person's
    message on its Threads; defines its own state, independent of the Executor.
  • Assignment — binding of a Ticket to one Executor instance; a Ticket has several
    over time; pending → running → ended independently of the Ticket.
  • Subscription — many-to-many Ticket↔Thread relation; fan-out delivers Thread
    messages to live Tickets as context with no authority check; context-only
    subscriptions lend context but no authority and do not resume.
  • Correlation — relation between Threads sharing a Trigger; adds context, never
    routes.
  • Channel — the write side of a Thread (acks, replies, PRs, review replies).
  • Policy — versioned assessment rules + per-Source parts (allowed list, admission
    table, bot list); a Policy change notifies affected live Tickets but does not
    revoke their Mandates.
  • Attention — a structured question on a Ticket waiting for a person's answer.
  • Disposition — the record of where each Trigger went (filtered / evaluated /
    fanned out / handed back / answered).
  • Report — the Executor's structured state report to its Ticket: progress /
    waiting / ready / blocked / failed / dropped, plus an optional question.
  • Explicitly rejected concepts (001-domain "Rejected concepts"): cross-Source
    identity mapping, Eval scheduling its own delayed Triggers (waiting belongs to
    Sources), waiting/revoked Eval states, one-live-Ticket-per-Thread, Ticket state
    following the Executor session, an Executor declaring a person asked to stop,
    cancelling running Tickets on Policy change, inferring "waiting on a person"
    from free-text reports.

Authorization (002-authorization)

  • Strength: explicit (allowed person addresses the agent, or follows up on a
    Thread with a Ticket) vs inferred (bot on the bot list, unlisted follow-up,
    admission-cell candidates). Bots can never make explicit requests or stop work.
  • Admission table per Source: rows = receiving scopes, cells decide
    explicit / inferred / ignore by sender membership × addressed-or-not.
  • Accept mode per Policy: off / observe (default; inferred accepts are
    recorded as "would accept" and nothing starts) / auto. Explicit requests
    work in every mode. Proactive accept requires ≥1 matching rule, and every
    enabled rule is judged exactly once per assessment.
  • Follow-up ownership: a message on a Ticket's Thread is owned by that Ticket's
    Executor (no Eval); the Executor handles it in-scope or hands it back once,
    with a reason; only when no Ticket owns it does it go to fresh Eval. The main
    Session may act on an owned follow-up only to stop work.
  • Revalidation before resume: an ended Ticket's Mandate is checked against
    today's Policy (mode, rules still enabled, sender still listed, bot still
    listed); failure = the Ticket stays ended and its waiting messages re-enter
    the intake path as unowned.
  • Eval failure discipline: an expired Eval requeues twice, then records
    unavailable; assessment failure also records unavailable; Policy change
    mid-Eval records unavailable and requeues under the new version immediately.

Execution (003-execution)

  • Ticket stages are derived, not stored: a precedence table (first match wins)
    computes the stage from facts — input-undelivered, has-Attention, latest
    Report ready / blocked / failed, queued, idle (waiting), working. A person/*
    stage means the Ticket cannot continue without a human.
  • One Executor Session + one directory per Ticket (worker-<ticket id>);
    prepare command (typically git worktree) runs once before the first
    Assignment; a PR belongs to the Ticket when its branch's last segment matches
    the Ticket's short name.
  • Worker slots: a Ticket holds a slot through background work; background work
    gets ≤30 min after turn end, then shell jobs are killed and the Ticket reports
    waiting with which jobs were killed. One extra slot beyond the concurrency
    limit is reserved for a person's message or a status request, and human wakes
    take priority over new launches.
  • Blocked/failed hold: on a blocked/failed Report the Ticket takes no
    automatic Input (CI/bot messages are recorded, not delivered); transient
    provider/network failures (408/429/5xx, refused/reset/timeout) retry 3× with
    growing backoff before the hold; a person's message, a non-blocked Report, or
    a manual Retry ends the hold.
  • Stored work: side effects are stored first, executed after (transactional
    outbox); retries with doubling backoff; a kind of work surfaces as a system
    problem only after 3 consecutive failures of an item.
  • Restart recovery: interrupted Assignments restart with a recovery note ("check
    directory, git history and GitHub before repeating any outside action"),
    oldest Ticket first; read/unread Input accounting survives restarts, and a
    replacement Assignment re-receives exactly the Inputs the old one never took.
  • Pause processing: stops dispatch, Evals, deliveries and replies; Sources keep
    recording Triggers; running turns are not interrupted; Eval deadlines shift
    by the pause length.
  • Merge governance is prompt text ("Delivery requirements"), not host logic:
    the agent account never enables auto-merge (attribution goes to whoever
    enabled it); default rule allows auto-merge only for the Ticket's own PR,
    ready, approvals covering the head commit, <200 changed lines.
  • A Ticket following PRs ends when none of the PRs it opened remain open (or all
    followed PRs closed); outcome = the last relevant close; it keeps its
    Subscriptions afterwards so a later human comment resumes it.

Panel (005-panel)

  • The panel answers three questions in order: (1) does anything need me now?
    (2) is the system healthy and doing the right things? (3) what is the history
    of one piece of work, Trigger → Eval → Ticket?
  • Overview lists Tickets needing action first; a healthy state takes no space;
    every count equals the length of the list it links to; a label says whom a
    row waits for and what it needs, not an internal status code; problems must
    be actionable (a one-off network error is not enough); rows needing a person
    offer their action (Retry, stop, dismiss, evaluate-again) directly.
  • An unavailable Decision asks for human attention only when <24h old, still
    the latest on its Thread, undismissed, and the Thread is neither queued nor
    evaluating.

Prompts (004-prompts)

  • Prompt assembly has a fixed precedence ladder: (1) facts enforced by tools/
    host, (2) built-in + generated sections as overridden, (3) a proactive
    Ticket's matched-rule requirements for that Ticket only, (4) team sections
    and skills, (5) outside text — data, never authorization.
  • The Policy section is regenerated from settings on every model request and
    placed last, so a Policy change leaves the preceding prompt text unchanged.
  • Prompts and settings are immutable versions with base-revision optimistic
    concurrency; a conflicting save is refused without discarding the draft;
    Sessions read the latest version on every request, even mid-turn; an override
    identical to the default is deleted so the part follows future defaults.
  • Role split: the main Session only routes (forwards the original Trigger +
    routing facts, no technical decisions, routing note ≤30 words, one routing
    call batches up to 20 decisions); Executors read original sources, judge
    scope, implement and verify. The main Session never waits — a host guard
    refuses sleep, shell timeouts >30s, and job waits >5s.
  • Chat messages: one sentence by default, hard limit 100 words; main-Session
    coordination notes to a Ticket ≤100 words and grant no authority.

Architecture (007-architecture)

  • One Engine is the only writer of Triggers/Threads/Decisions/Tickets/
    Assignments; every command mutates its aggregates in one transaction; ports
    enqueue external work inside the transaction and adapters perform it after
    commit (afterCommit). Callers get only their role's Pick of the Engine
    (Sources / Main Session / People / Settings / Executor).
  • Effects: a durable side-effect queue (kind/key rows; re-enqueueing a waiting
    key replaces its payload without changing queue order); per-kind handlers
    with their own concurrency and backoff; throwing Later defers without
    counting a failure.
  • Decisions record structured reasons: a code + values (+ per-Trigger id),
    rendered to text for agents and panel from one code table.
  • Persistence: one SQLite file; domain tables per aggregate plus a
    disposition table, an effect table, an outbox receipt table (a message
    id is never queued twice; dropped messages keep when/why), and typed KV.
    Generated columns (open, active, subscribed) index exactly the working
    set a pass must read. Schema version only increases; nothing deletes old
    records yet (named as a known unbounded-growth gap).
  • Reasons, stages, and health have single definitions used by core, panel and
    prompts alike ("one writer per state", "one place per concept").

2. Concept-by-concept mapping to our system

Legend: have = we do this today in substance · partial = shape exists,
weaker or by convention only · lack = no equivalent.

A. Intake, authorization, work acceptance

Their concept (doc) Ours Verdict
Source with read position, own bot identity, self-messages dropped pre-domain (001) Producers (sweeps, new-issue-creator, pr-diff-review, pr-comment-review, fleet monitor, conductor) write packets to per-repo Supabase queues; GitHub is the event surface; watermarks exist per producer (e.g. pr-review-state.json) partial — positions/watermarks exist per producer, no single Source abstraction, no uniform "own output never re-enters" filter
Trigger as immutable unit of audit + idempotence (001) repo-task/v1 packets with dedupe keys (fix/triage/pr families); enqueue revives on duplicate key (migration 0014) partial — dedupe gives idempotent enqueue, but the packet is a work order, not an immutable record of the originating event with its actor
Gate (deterministic) + Assessment (model) as two Eval layers (001, 002) Label hard-stops at claim (held, user/owned, do-not-merge, do-not-auto-edit) + lane judgement during triage kinds partial — the deterministic layer exists as label checks inside claim/revalidation; the judgement layer is the lane itself, not a separate recorded Decision
Decision as a recorded object with structured reasons (001, 007) Triage outcomes recorded as issue comments (agent-note:v1) and queue status; reasons are free text in progress/last_error lack — no Decision record, no reason-code vocabulary; this is exactly what #3424 pieces 4–5 would build
Mandate: immutable grant w/ Policy version, scope, strength, matched rules (001, 002) The packet is the closest analog: scope + timebox + payload, frozen at enqueue partial — packet carries scope but no strength, no rule provenance, no version of the rule set it was admitted under
Strength explicit vs inferred (002) Drew's direct directives vs fleet-inferred work (sweep findings, producer packets) — real distinction, nowhere recorded lack as data; have as practice (Drew escalations short-circuit everything)
Admission table per Source (002) Producer charters in job bodies (what new-issue-creator / pr-diff-review may file, caps per run) partial — rules exist as prose in cron bodies, not as data consulted at intake
Accept modes off / observe / auto (002) Pilot Phase 0 ran a 48h shadow before live cutover (GOAL.md); since then producers run auto permanently partial — we did observe-mode once, at system level, by hand; no per-rule or per-producer mode
Follow-up ownership + hand-back with reason (002, 003) PR shepherd tasks and resume-briefs approximate it: a parked task's follow-up work returns to the same queue item; lanes hand off via handoff snapshots partial — ownership is by queue item, not by conversation thread; hand-backs are prose in comments, not a routed object with a reason code
Revalidation of the grant before resume (002) Lanes revalidate against fresh GitHub state (labels first) on every claim/resume — a strong, enforced habit (§ instruction) partial — we revalidate the work's state rigorously; we do not revalidate the authority (e.g. a label Drew set since, a rule that changed) as a distinct check — in practice labels cover most of it
Eval timeout → requeue ×2 → unavailable + health surfacing (002) Task attempts cap (max_attempts) + lease expiry returning tasks to queued; fleet monitor flags dead-in-queue partial — caps exist; the "terminal undecidable" state and its dedicated surfacing do not (dead-in-queue repair is manual/operator)

B. Queue data model (code#3424 / #3418 territory)

Their concept (doc) Ours Verdict
Ticket defines its own state, independent of Executor (001) Task row holds status; lanes are interchangeable claimers have — this is already our shape, and #3424 keeps it
Assignment separate from Ticket, several over time (001) Claim/lease + attempts on the task row; lane-execution ledger exists (migration-era) partial — attempts counted, but no first-class assignment record with its own lifecycle; #3424 piece 6 (provenance) covers who, not the binding as an object
Derived stage from facts, precedence table, "whom does it wait for" (003, 005) Stored status enum (queued/claimed/parked/blocked/done) + free-text reason lack — #3424 piece 4 adds status_reason; a derived "waiting-on" classification (CI / review / person / budget / external) computed from facts is not in the design yet — adoptable (see §3.3)
Structured Report vocabulary: progress/waiting/ready/blocked/failed/dropped + structured question (001, 003) Terminal verbs complete/park/block + checkpoint text; escalation to Drew is prose in chat partial — verbs map roughly (park≈waiting, block≈blocked), but the question for a person is not a structured field anywhere; escalations are hand-written chat lines
Attention as a first-class object (001) user/escalated label + backlog entries + chat lines lack — no queryable "questions waiting on Drew" set; the morning readout assembles it by hand each cycle
Disposition: every Trigger's fate recorded (001, 007) Sweep logs, backlog files, lane handoff snapshots — per-producer, prose lack — #3424 piece 5 (events) covers task changes, not intake fates (what a producer saw and skipped, and why)
Subscriptions / fan-out to live work (001) Shepherd tasks poll their PRs on park-resume; fleet monitor watches in-progress items hourly partial — polling by schedule instead of subscription; works, costs cycles
Correlation adds context, never routes (001) #3424 links: related kind adds context; claim consumes only derived hard/soft block semantics have (in design) — the newest #3424 comments independently converged on this: kinds + provenance + derived blocking semantics, claim reads semantics only
Typed links with provenance, system-inferred links marked (their Disposition/hand-back reasons, 001/007) #3424 amendment: kind × provenance (direct/inferred/related — explicitly not pinned) × derived effect; inference rules (issue-blocker ⇒ its queue item; PR closing a blocked-on issue joins the chain) have (in design) — theirs is thinner here; our link model is already the more developed one
Append-only history, reconstruct any moment (their disposition + decision tables, 007) #3424 piece 5: events table with before/after (JSONB diff pocket per storage ruling) have (in design)
Actor provenance on every write (007's Mandate basis + Decision reasons) #3424 piece 6: lane, runtime, session, host, pid, ip, originating system have (in design) — ours is more detailed than theirs
Normal-form tables + generated working-set indexes (007 Persistence) #3424 storage ruling: normal form default, JSONB in four sanctioned pockets, graduation rule have (in design) — same instinct; their generated-column trick is the concrete mechanism worth copying (§3.8)
Budget-aware claiming: match work to claimer capacity (— they have worker slots instead, 003) code#3418: required_budget_minutes on park/packet, claim takes claimer's remaining shift budget; external-wait vs capacity-wait split have (ours, in design) — they solve the adjacent problem (slot accounting + human-priority slot), not this one; #3418 is genuinely ours
Park revalidation on a cadence (—) #3424 piece 3: daily re-verification of long parks writing last_checked_at + outcome have (ours, in design) — no analog in their docs; their nearest is Mandate revalidation at resume

C. Execution, sessions, routing (lanes + conductor + router; opencode#1014)

Their concept (doc) Ours Verdict
One session + one directory per work item, prepared by a prepare command (003) Lane shifts claim many tasks sequentially in shared worktrees on the laptop; sessions are per-shift, not per-task lack — deliberately different (§4), but their per-item directory discipline is what our worktree-per-task hygiene approximates by instruction
Worker slots with a reserved +1 human-priority slot (003) Fixed lane counts per queue (code 6 lanes at peak design, opencode/openchamber/nix 1 each); Drew's messages don't preempt a lane mid-shift — they wait for a shift boundary or the main chat acts directly lack — no priority lane for Drew-originated work inside the queue system; the main chat is the priority slot, informally
Background-work slot accounting: turn ending with jobs running keeps the slot, 30-min cap, kill + report (003) Shift budget ~90 min; lanes park instead of waiting (CI, reviews); a task never just stops (§10 anti-evaporation) partial — park-don't-wait is the same instinct; we bound by shift, they bound by per-item background window
Blocked/failed hold: no automatic input delivered while held; transient provider errors retry 3× backoff first (003) Blocked tasks sit until operator/fleet-monitor action; provider-error handling lives in the router (#1014), not the queue partial — split across two systems in ours; their rule "a hold is a state computed from stored Reports/Inputs, so a restart keeps it" is a property our blocked state has via the DB
Stored-work / transactional outbox: store first, execute after commit, per-kind backoff, surface after 3 consecutive failures (003, 007 Effects) Supabase queue + cron/hook triggers + signal chaining; GitHub comments posted directly by lanes partial — the queue itself is durable, but side effects (comments, enqueues, signals) are fire-and-forget from the lane; no outbox, no per-kind failure accounting
Restart recovery note + re-delivery of exactly the untaken inputs (003) Lane handoff snapshots (per lane/queue JSON) + resume briefs on parked tasks; new shift re-derives state from GitHub + snapshot partial — same goal, prose mechanism; theirs is exact because read/unread is tracked per Input; ours re-verifies fresh each claim (stronger against staleness, weaker on continuity)
Pause processing (dispatch/evals/deliveries stop; intake continues; deadlines shift) (003) Individual cron jobs can be paused; quota walls stop dispatch by conductor gate (Meta read is the dispatch gate) partial — no single fleet-wide pause that freezes clocks; our pauses are per-job and time keeps running on parks/leases
Merge governance as prompt text with attribution rule (003) Merge authority is Drew's standing rule: Muse merges verified work itself; CI runs on main only; PRs don't wait for CI (2026-10-29/31 rules) have, inverted — both keep merge policy out of the host's decision logic; the content of the policy deliberately differs (§4)
Router behavior under provider failure (their Executor retry classes, 003) opencode#1014: any-error-class escalating bench, reset-aware holds, balance-shaped known-full, dynamic pull-out on quota error, nearest-first cascade that never kills a session while a candidate remains, pooled-seat launch rule (code#3325) have (in flight, task 5256) — our router doctrine is considerably more developed than theirs; theirs contributes the classification discipline (transient class → retry 3× → hold) as a cross-check, not a replacement

D. Surfacing: panel vs chat escalation + morning readout

Their concept (doc) Ours Verdict
Panel: needs-me-first, health second, per-item history third; healthy = invisible (005) Chat delivery discipline: one compact line for material outcomes only; everything else to logs/backlogs; morning readout + stewardship cycles name stalled/blocked items have as discipline, lack as artifact — the ordering principle is identical (attention first, health second, history on demand); we render it as chat text assembled per cycle, they render it as a standing view over queryable state. #3424's notes/events/attention data is what would let ours be generated instead of written
Stage labels say whom a row waits for (005, 003) Backlog/readout prose names blockers ("BLOCKED: <what's needed>") partial — convention exists, not computable from data today
Actionable-only problems; one-off errors don't surface; counts == list lengths (005) "A failed read never idles a pool"; routine exhaustion not surfaced, sole-door pools and anomalies are (quota doctrine) have — same principle, independently arrived at
Dismissable, expiring attention requests (<24h, latest-only, not-while-queued) (002, 005) Escalations persist until Drew rules or the condition clears; re-asking a recorded decision is banned partial — we have the no-re-ask rule; we lack expiry/dismissal mechanics, so stale asks can linger in backlogs
One structured question at a time to the person (000, 004) Decision surfacing carries substance + options + recommendation (Drew's 2026-10-28 rule); options widgets used for rulings have — our version is richer in content; theirs adds the structured-field plumbing (question travels with the work item, answer returns to it)

E. Prompts / instructions

Their concept (doc) Ours Verdict
Precedence ladder: host-enforced facts > built-ins > matched-rule reqs > team text > outside text as data (004) System rules > Drew directives > instruction files > issue/PR text; injection discipline in fleet instructions have as practice — never written as one ladder our instruction files cite
Policy section regenerated per request, placed last so rule changes don't churn the prompt prefix (004) Instruction files are static per cron definition; quota/router state injected per conductor cycle; cron definitions are truth, edits pushed via cron.update partial — our "policy" (quota state, gates) does ride per-cycle; the placement/caching trick is OpenCode-session-specific but the principle (volatile state last, stable text first) applies to lane prompts
Versioned prompts/settings, base-revision saves, override==default auto-deleted (004, 007) Cron definition files in git + cron.update; instruction files in hidden_files with git history partial — versioned by git, no optimistic-concurrency on edits, no "instruction identical to template gets dropped" hygiene
Router/executor role split: router never decides technically, ≤30-word notes, batched routing calls (004) Conductor dispatches and gates; lanes judge and implement; main chat routes Drew's intent have in shape — our conductor already only dispatches/gates; the word-limit and batching disciplines are not formalized
Router never waits (no sleep / long job waits) (004) Cron shifts are fresh-context and time-boxed; lanes park instead of polling have by architecture — cron model gives us this for free
Few concepts, few settings; behaviour in words is prompt text, not a setting (000) Fleet has accreted many job types and instruction files; label taxonomy 400+ labels partial — worth an explicit audit pass (§3.10)

3. Most adoptable ideas (ranked by value ÷ cost)

Each idea names its source doc, every plausible home, and a one-line cost note.

3.1 Structured question field on the work item ("Attention")

Their Executor asks through a structured field on its Report; the question
travels with the Ticket and the person's answer returns to the same Ticket
(001-domain glossary; 003-execution; 004-prompts "Ask through human_action").
Ours: escalations are chat prose + user/escalated labels; the substance rule
(what/options/recommendation/why) is enforced socially.
Homes: code#3424 (notes schema gains an attention note type with
question/options/recommendation/answer fields — fits the typed-notes piece
directly) · lane instructions (repo-queue-worker-instruction.md,
lane-shift-instruction.md: escalation = write the attention note, then the
chat line renders it) · escalation discipline / morning readout (readout
lists open attention notes instead of re-deriving them).
Cost: small — one note type + fields in a design already in flight; readout
generation is a follow-up, not a prerequisite.

3.2 Accept mode per producer: off / observe / auto

Inferred work starts in observe: positive assessments recorded as
"would accept", nothing starts; flip to auto after reviewing the recorded
Decisions (002-authorization). We ran observe once, system-wide, by hand
(pilot shadow); every new producer since went straight to auto.
Homes: code#3424 (a mode column on producer/queue config is schema-shaped)
· producer job bodies (new-issue-creator, pr-diff-review, pr-comment-review:
new filing rules/kinds start in observe for N runs) · fleet monitor (reports
would-accept counts so the flip decision has data).
Cost: small–medium — a config flag + producers honouring it; the win is a
safe on-ramp for every future producer rule change.

3.3 Derived "waiting-on" stage instead of (only) a stored status

Stage computed from facts by a precedence table — undelivered → person/answer →
person/review → person/blocked-failed → queued → idle → working — and the label
names whom it waits for (003-execution stage table; 005-panel principle 2).
Homes: code#3424 (add a derived waiting-class to the design: inputs are
status + blocker links + park kind + last note type; stored status_reason
stays as the human gloss) · code#3418 (capacity-wait vs external-wait is
exactly two rows of this table — fold them in rather than inventing parallel
vocabulary) · fleet monitor + morning readout (queue health reported in
waiting-on classes; "31 parked" becomes "12 on CI, 9 on review, 4 on Drew,
6 capacity").
Cost: small in the design phase (a view/function over #3424's tables);
medium if retrofitted after implementation — decide it inside #3424 now.

3.4 Decision/reason codes as a shared vocabulary

Decisions and transitions record a code + values from one table; agents,
panel and humans all render from the same codes (007-architecture Model;
001-domain disposition). Our reasons are free text (last_error, progress
blobs) — the failure #3424 exists to fix.
Homes: code#3424 (notes/events carry reason_code beside the free-text
body; seed the code list from our real vocabulary: ci_wait, codex_review,
quota_reset, capacity, blocked_on_task, drew_decision, upstream_pr, …) ·
lane instructions (terminal verbs require a code) · repo-queue.py (validate
codes at the verb, like packet schemas).
Cost: small — a controlled vocabulary list + one column; discipline cost
only if lanes must retrofit old rows (don't — codes apply going forward).

3.5 Follow-up ownership + hand-back, applied to PR shepherding

A follow-up on a work item's own thread is owned by that item's worker, which
either handles it in-scope or hands it back once with a reason; only unowned
messages become new intake (002-authorization; 003-execution). Our analog:
review comments and CI results on a PR with a live shepherd task should route
to that task (as a resume trigger with context), and a shepherd that judges a
comment out-of-scope hands it back as a new triage packet naming why — instead
of today's pattern where pr-comment-review files fresh issues that can collide
with the shepherd's own work.
Homes: lane instructions (shepherd resume protocol) · pr-comment-review
job body (check for a live shepherd/pr task before filing) · code#3424
(hand-back = a link + note with provenance inferred, reason code from 3.4).
Cost: medium — mostly instruction + one producer check; no schema beyond
what #3424 already plans.

3.6 Reserved human-priority capacity in claiming

Worker slots reserve +1 beyond the limit for a person's message or a status
request, and human wakes preempt new launches (003-execution Concurrency).
Our failure shape (2026-11-01): Drew-prioritized work waits behind whatever
the shift already claimed; there is no mechanism for a Drew directive to
preempt inside the queue system.
Homes: code#3418 (claim-side companion: expedite/Drew-originated tasks may
claim against a reserved budget slice — e.g. a lane may exceed its bundle cap
by one for a priority-90 task, or one lane slot per queue is reserved for
expedite until T-30 of the shift) · lane instructions (the reservation rule
lanes can actually execute) · conductor instruction (dispatch gate honours the
reservation when seating sessions).
Cost: small — a claim rule + instruction text; no schema beyond #3418's
required_budget_minutes conversation.

3.7 Stored-work discipline for side effects (mini-outbox)

Side effects are stored in the same transaction as the state change and
executed after commit with per-kind backoff; a kind surfaces as a system
problem only after 3 consecutive failures of one item (003-execution "Stored
work"; 007-architecture Effects). Our lanes post GitHub comments / enqueue
follow-ups / fire signals inline; a crash between the DB verb and the comment
is exactly the claim-evaporation class we repaired on 2026-10-26.
Homes: code#3424 (events table already stores the intent; add an
effects/outbox table for comment-mirroring — note piece 4 already promises
"the system comments notes back automatically", which is an outbox consumer)
· repo-queue.py (verbs enqueue effects; a small drainer in the fleet monitor
or a hook executes them) · fleet monitor (per-kind failure accounting replaces
ad-hoc divergence repair).
Cost: medium — one table + a drainer; but it mechanizes repairs the fleet
monitor currently does by hand every hour.

3.8 Generated working-set columns for queue reads

Their store computes open / active / subscribed as generated columns
with partial indexes so a pass reads only active work (007-architecture
Persistence). Our claim/health queries filter the full tasks table by status
and timestamps on every lane cycle.
Homes: code#3424 (schema design: generated columns or partial indexes for
claimable-now, parked-due, blocked-on-open-task working sets — pairs with the
normal-form ruling already recorded) · supabase migrations chain (lands as
part of the #3424 implementation migrations).
Cost: small — index design inside migrations already being written.

3.9 Prompt-precedence ladder + volatile-state-last, written into fleet instructions

One explicit ladder (host-enforced facts > standing rules > matched task
requirements > instruction text > repo/issue text as data), and prompts
assembled stable-first with volatile state (quota snapshot, gate state) last
(004-prompts). Our lanes already behave this way; writing it down once ends
per-instruction-file reinvention and gives the injection rule a citation.
Homes: lane-shift-instruction.md + repo-queue-worker-instruction.md
(one shared preamble section) · conductor instruction (same preamble) ·
opencode route/session prompts where the router assembles per-session context
(adjacent to #1014's surfaces, not inside its scope).
Cost: small — an editing pass over instruction files we control.

3.10 "Few concepts" audit of our own surface

Their design refuses new concepts: a business need becomes an attribute of an
existing concept or prompt text (000-philosophy; 001-domain rejected-concepts
table is the worked example). Our surface has grown by accretion: 400+ labels,
multiple overlapping job types, per-queue instruction variants.
Homes: goal-level review (label taxonomy file
files/label-taxonomy-2026-10-25.md — prune labels no query uses) ·
stewardship cycle (a standing "concept count" check when a new job/instruction
is proposed: attribute of an existing thing, or genuinely new?) · code#3424
(the design already applies this to links/notes — extend the same test to the
pieces' own vocabulary before implementation packets split).
Cost: small per pass, recurring; the cost of not doing it is the drift
that made tonight's routing incident hard to reason about.


4. What they do that we deliberately do differently — and should keep

  1. Merge authority. Their default: the agent account never enables
    auto-merge, people merge, policy lives in a "Delivery requirements" prompt
    (003-execution). Ours (Drew, 2026-10-24/25, restated since): Muse merges
    verified finished work itself — "if an issue or PR says it needs a human,
    they mean you" — drafts and conflicted PRs included, fix forward. Keep
    ours. It is the throughput decision the whole fleet is built on; their
    model optimizes for a team of human colleagues whose attention and trust
    are the scarce resource, ours for a single operator who has explicitly
    delegated the merge call. (Borrow only their attribution awareness:
    merges are attributable actions, which our provenance piece 6 now records.)

  2. Start narrow / observe-first as the permanent posture. Their
    responsibility section: begin with a short allowed list and record-only
    proactive work; widen only when the record looks right; never produce
    volume (000-philosophy). We already passed that gate deliberately (pilot
    shadow → Drew-approved cutovers, Phase 3 approved 2026-10-26) and Drew's
    standing direction is the opposite failure-mode guard: "fix it means fix
    it now", file the issue in the same pass, merge when verified. Keep our
    posture; adopt observe-mode only as a per-producer on-ramp (3.2), not as a
    fleet-wide temperament.

  3. One work item per session, session per item. Their Executor model is
    one Session + directory per Ticket, resumed across days by subscription
    fan-out (001/003). Our lanes are fresh-context cron shifts claiming bundles
    — chosen 2026-10-26 precisely because long-lived worker contexts compact
    and die mid-bundle ("cron jobs don't compact"). Keep the shift model. Our
    continuity lives in the queue + GitHub + handoff snapshots, not in a
    session's memory — which is also why design(queue): durable task data model — blocker links, park revalidation, status reasons + notes, full event history, actor provenance #3424's notes/events matter more for
    us than their Session-history mechanics would.

  4. Panel as a separate UI artifact. Their panel is a standing view inside
    the DeepSeek Harness (005-panel). Our surface is chat + GitHub + the
    morning readout, and Drew works from his phone. Keep the surface; adopt
    the panel's principles (needs-me-first ordering, waiting-on labels,
    actionable-only problems, counts that equal their lists) as readout
    requirements — 3.1/3.3 are what make them generatable from data instead of
    assembled by hand.

  5. Waiting belongs to Sources; no park timers in the core. They reject
    delayed-Trigger scheduling inside Eval: a condition that needs waiting is
    a Source that checks again itself (001-domain rejected concepts). Our
    park/not_before + scheduled revalidation (design(queue): durable task data model — blocker links, park revalidation, status reasons + notes, full event history, actor provenance #3424 piece 3) puts waiting
    inside the queue deliberately — because our "sources" are cron jobs and
    GitHub state, and a park with a known external instant (quota reset, CI
    completion) is more honest as data than as a poller. Keep ours; design(queue): budget-aware claiming — parks carry a minimum required time budget, claim matches the claimer's remaining shift budget #3418's
    external-wait vs capacity-wait split already encodes the part of their
    objection that was right (a capacity wait is not a time wait).

  6. GitHub as the canonical work surface. Their Sources translate GitHub
    into an internal domain and the Ticket state lives in their store
    (001-domain "What is reusable"). Ours keeps GitHub issues/PRs canonical —
    the queue is a control plane, the discussion and the audit trail people
    read live on the issue — and design(queue): durable task data model — blocker links, park revalidation, status reasons + notes, full event history, actor provenance #3424 piece 4 mirrors notes out to GitHub
    for exactly this reason. Keep ours; it's why a person can audit any fleet
    action from the repo alone.

  7. Escalation content. Their questions are one concrete question, short
    (000/004). Drew's rule requires the substance in the message itself —
    what, options, ramifications, recommendation — because he rules from the
    chat, not from a panel. Keep ours; 3.1 adds their plumbing (the question
    as structured data on the item) underneath our content rule, not instead
    of it.


Prepared for the repo-health fleet's design work (code#3424, code#3418,
opencode#1014, fleet instruction files). Reference only — no GitHub posts made.

Activity

  1. developing-today commented on Nov 1, 2026

    @developing-today
    Contributor
  2. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    Transferred from Slack #alignment at Drew's direction (2026-11-01). Aster (@drewrypope-aster) reviewed the dsh-superagent design package (#3450 / #3424 / #3418) in the thread on Muse's 03:29 CST pass; her replies are below verbatim (formatting converted from Slack mrkdwn to GitHub markdown; wording unchanged). The identical text is posted on all three issues so each record is self-contained.


    Aster's acknowledgment (03:29 CST):

    I’ll review the package against the original dsh docs, focusing on genuine weaknesses, the deliberate differences worth challenging, and possible misreadings. I’ll treat Drew’s sketches as design direction and keep this to review, with findings returned here.


    Aster's review (03:33 CST):

    Reviewed #3450, #3424 and #3418, including their comments, against dsh docs 000–008. My conclusion: the shared architecture is real, but “same path, mostly plumbing to borrow” understates their strongest advantage. Their docs specify ownership and recovery across transitions more precisely. Our proposed schema is richer in some areas, but records alone do not establish those guarantees.

    This is a documentary design review, not a runtime audit of either system. I would distinguish “implemented,” “proposed,” and “verified” rather than count “have (in design)” alongside shipped capabilities.

    Where I would correct the comparison

    • Merge authority: dsh does not categorically require humans to merge. Its Executor can enable auto-merge through another explicitly named account’s CLI. Human merge is the fallback. The real comparison is attribution and readiness safeguards: their defaults require an own-Ticket PR, approvals covering the head, fewer than 200 changed lines, and withdrawing auto-merge before a new revision. Keep delegated merge authority, but compare its safeguards rather than calling it an inversion. 003: Merging
    • Observe-first: they explicitly permit graduating to auto. Our mature-auto posture plus observation for new or materially changed producers is compatible. Their mode is Policy-level; per-producer modes are our adaptation. Explicit requests work in every mode, which matters when defining what “off” means. 002: Accept modes
    • Reserved capacity: their extra slot lets a human message/status request continue an existing Ticket and precedes new launches. It does not interrupt active work or give a newly queued expedited task a full shift. #3418’s proposal is a new scheduling policy, not direct adoption. Raising a bundle cap cannot give a worker with ten minutes left the 120 minutes a task needs. 003: Concurrency
    • Expiration: the 24-hour/latest/undismissed rule applies to unavailable Eval Decisions shown for attention, not all unanswered Attention questions. Do not age out Drew’s pending decision by importing it. 002: Unavailable Decisions
    • Storage and reconstruction: dsh describes aggregate JSON rows with generated working-set columns, not normal-form consensus. Retained Decisions/dispositions also do not establish full historical state reconstruction. #3424’s “resurrect any moment” is a stronger proposed contract with its own proof burden. 007: Persistence
    • Waiting and escalation: they reject Eval scheduling delayed Triggers, not all persisted timers in the core. Queue-native not_before is compatible with that separation. Likewise, one concrete question can include options, consequences and a recommendation. Their questions return through chat too; this is not “panel questions versus substantive chat.” 001: Rejected concepts, 004: Prompts
    Where our design needs stronger contracts

    1. Authorization, execution identity and relationship provenance are different things. Runtime/session/host/pid/IP explains who wrote. A grant reference explains who authorized what scope under which rule/version. A derivation basis explains why a link exists. None substitutes for the others. Add claim-generation/fencing semantics so an expired worker cannot write after its replacement claims the task. Context and inferred links must never silently expand authority.
    2. Durable input ownership and external-effect reconciliation come before more vocabulary. dsh specifies stable source-event IDs, cursor advancement after storage, follow-up ownership/hand-back, consumed-input accounting, and replacement Assignment recovery. Its cookbook also addresses remote success followed by local failure using outbound idempotency. An outbox must handle “GitHub accepted the comment; the drainer crashed before recording success.” Task mutation, event and effect intent should commit together; delivery needs a stable identity and reconciliation, not blind retry. Renewable task dedupe is not immutable event identity. 003: Restart, 008: Cookbook
    3. Attention needs a lifecycle, even if stored as a note type. Give each question identity, an answer binding, and open/resolved/superseded state. Deriving waiting-on from “last note type” is unsafe: a later finding must not hide an unanswered question. Keep all underlying blockers even if one precedence rule chooses the displayed stage. That is what makes a chat readout trustworthy without requiring another UI.
    4. Inferred blockers need satisfaction and retraction rules. An issue, its queue task and a PR claiming to close it are not interchangeable proof of completion. Cancelling the task or closing the PR unmerged must not unblock its dependent. Track the assertions supporting an inference so withdrawing one basis removes only its unsupported consequences, not an independently deliberate link. Pairwise links can support this; no general graph framework is required.
    5. Budget fit needs a starvation story. A maximum timebox is not necessarily the minimum uninterrupted budget. If a task requires 120 minutes but no lane can ever offer that, repeated skipping is not successful scheduling. Preserve the fit predicate under priority overrides, identify impossible fits, and specify whether human-priority work gets a fresh eligible worker, reserved start capacity or checkpointed yielding. Keep external-condition readiness separate from a recheck time: elapsed CI wait does not prove CI passed.
      Pushback on the deliberate differences

    Keep fresh shifts, phone-friendly chat/GitHub, and queue-native waits. But fresh context does not itself guarantee no compaction or no waiting; those require actual runtime bounds. Per-task workspace isolation also does not require a long-lived session.

    I would narrow “GitHub-canonical” to human discussion and code artifacts, then state authority per field. Queue leases, admission decisions, skipped inputs and pending effects are not automatically auditable from the repo because notes are mirrored. Define reconciliation and avoid two competing sources of truth.

    Do not copy dsh’s trust model wholesale: its workers run as the operator OS user, and the docs explicitly say wrappers/directories are not a security boundary. Its live Mandates also survive Policy changes, with notifications rather than automatic revocation. Those are tradeoffs to examine, not safety guarantees to inherit. 006: Isolation

    Five acceptance cases I would put ahead of implementation splitting

    • Cancel the task representing a blocking issue and close its resolving PR unmerged: the dependent remains blocked.
    • Open Q1, append a finding, supersede it with Q2, then receive Q1’s late/duplicate answer: Q2 remains correctly unanswered and work does not resume twice.
    • Present an expedited 120-minute task to a worker with ten minutes left: no cap override claims it; a fresh eligible worker can.
    • Crash after GitHub accepts an effect, then resume the old worker after lease reassignment: reconcile delivery and reject stale ownership writes.
    • Evaluate inferred work in auto, switch to observe before acceptance, then replay the event: no stale acceptance or duplicate execution.
    My recommendation is to retain the overall direction and revise the comparison before using it as design justification. Prioritize authority/ownership, atomic transitions and recovery, then structured attention and blocker semantics. The detailed link model and budget matching remain promising fleet-specific contributions; their value needs to be demonstrated by those failure cases. No implementation or issue changes made.

  3. added
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    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
    on Nov 3, 2026
  4. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 30 (priority/none). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

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

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  7. 8 remaining items

  8. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  9. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  10. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: queue worker (repo-worker-code), lane code-h
    • Session / ID: task 8619
    • Found via: queue claim
    • Task: Handed off to the opencode execution lane per §1b — the laptop claimant launches the bound opencode session for task 8619 (issue analysis: dsh-superagent-prototype vs our fleet — findings and adoptable ideas #3450).
    • Expectation: claimant session drives task 8619 to its terminal state under this queue's worker id
    • Links: n/a
  11. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

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

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor
    • Session / ID: task 8619 (repo-fleet-monitor run 2026-11-05T15:45:47Z)
    • Found via: monitor reconciliation (Duty 1 claim/label divergence repair)
    • Task: Claim evaporated: task 8619 is queued and unclaimed in repo-health-code-pilot, but this issue still carried claimed labels. Labels reset to the truth (queue/queued + status/needs-triage). Checkpoint stage at evaporation: handed_off.
    • Expectation: The next lane claim picks task 8619 up from the queued state and posts a fresh pickup note.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

kind/designA design proposal (design-architect): multi-step, phased, decision-bearingqueue/parkedQueue task is parked (waiting on CI, time, or an event)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first lookstatus/parkedDeliberately paused with a recorded resume conditiontask/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