Trigger: binky-control automation queues (AWQ/DEC/OH) emerged as an unindexed parallel work-item ontology (AWQ-010 reintegration case). Three artefacts: - research/2026-07-19-work-orchestration-infrastructure-survey.md — inventory of the ADR-001/005 backbone, state models, task-flow engine, hub generations, execution stack, and the >=9 live work-item species - research/2026-07-19-work-orchestration-best-practices.md — external 2025/26 practice: GitOps reconciliation, risk-tiered HITL, flow metrics/WIP, lean budget guardrails; anti-patterns to skip - research/WorkOrchestrationArchitectureDraft.md — v0.1 proposal: unified work-record ontology, type registry + UUIDv7/canonical-name layering, lanes to fleet canon, policy/derived tags, queues as generated views, staged migration; open questions for discussion Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
15 KiB
Work Orchestration Architecture — Draft for Discussion
Draft v0.1 — 2026-07-19. Synthesis of
2026-07-19-work-orchestration-infrastructure-survey.md(internal) and2026-07-19-work-orchestration-best-practices.md(external). Trigger: reconciling the binky-control automation queues with the suggestion/task/workplan backbone (AWQ-010 case). Status: proposal — nothing here is canon until ratified; terminology extensions are marked ⟨new⟩ and would land as a canon standard v0.1 after discussion.
0. Thesis
The queues were not a mistake — they were a market signal. Intake through a one-YAML-block append beat the hub suggestion flow because its friction was an order of magnitude lower, and it carried routing information (lanes) the backbone lacks. The error was ontological, not practical: the queue items became a second, unindexed species of work item.
The reconciliation is therefore not "move queues into the hub" but: make the backbone cheap enough at intake that the queue pattern becomes a schema-valid, hub-indexed instance of it — and make every future species impossible to create outside the reconciliation loop without tripping an alarm.
One sentence: everything with an ID is a work record, every work record is a repo file, every repo file is indexed, and every list anyone works from is a derived view.
1. The unified ontology
1.1 Work record ⟨new umbrella term⟩
A work record is any identified, lifecycle-bearing coordination artefact. All existing species become kinds of work record:
work record
├── intake item ⟨new⟩ — spark: idea, mail finding, observation, request
│ (absorbs: AWQ items, hub suggestions, "actionable" mail-triage rows)
├── task — smallest executable unit (canon lifecycle)
│ (absorbs: workplan tasks, adhoc tasks, issue-core issues-as-interface)
├── workplan — structured, dependency-bearing body of work
├── decision — approval package + resolution
│ (absorbs: DEC items; hub decision records become the index)
├── engagement ⟨new⟩ — scheduled external interaction
│ (absorbs: OH items — office-hour/command-day bookings)
└── register entry — risk, technical debt, capability request, CCR,
interface change (existing species, unchanged
semantics, brought under the same conventions)
Every work record, regardless of kind, carries the same conventional spine (aspect 4 — one framework, many demands):
| Field | Convention |
|---|---|
id |
canonical name per type registry (§1.3) |
uuid |
UUIDv7, hub-assigned at first index, written back to the file (like state_hub_*_id today) |
kind |
from the closed kind list above |
lane |
green/blue/yellow/orange/red (§2) |
status |
abstract canon lifecycle for its kind (§1.4) |
owner |
repo-anchored owner (agent identity or human) |
repo |
owning repo (ADR-001/ADR-005 anchor) |
tags |
policy + derived tags (§3) |
created/updated |
dates; UUIDv7 provides fine-grained internal time |
Kind-specific fields (budget, evidence, deadline_pressure, attention_cost, …) extend the spine; they never replace it.
1.2 File-first, one reconciliation loop (aspect 3)
- Every work record originates in a repo file: workplans as today; intake
items, decisions, engagements as YAML blocks inside per-repo registry
documents (
queues/…or the existing live documents — location is convention, the schema is what matters). - Forgejo CI validates schemas on push (yaml-block schema per kind — the GitOps "validate before apply" rule).
fix-consistencygrows checks per kind (as C-06 does for workplans): registers new records, writes UUIDs back, syncs status from file to hub. The hub stays a read model; runtime operations data (logs, metrics, run histories, token events) is the sanctioned exception and lives only in hub/activity-core/monitoring stores.- Derived views (§4) are generated from the hub, never hand-maintained:
the "Completed" tail of AutopilotWorkQueue.md, daily-brief queue summaries
etc. become materialized view output (ADR-003 pattern), clearly marked
[auto].
1.3 Type registry and layered identity (aspect 5)
A single canon file (canon/standards/work-record-types_v0.1.md + machine
copy work-record-types.yaml) registers every id scheme:
- code: WP # {PREFIX}-WP-NNNN workplan
- code: T # {WP-ID}-TNN task
- code: IN # {PREFIX}-IN-NNNN intake item ⟨new; AWQ-* grandfathered⟩
- code: DEC # {PREFIX}-DEC-YYYY-NNN decision
- code: ENG # {PREFIX}-ENG-YYYY-NNN engagement ⟨OH-* grandfathered⟩
- code: RISK, TD, CAP, CCR, ADR … register entries (existing)
- UUIDv7 is primary for bookkeeping, relations, dependencies, history — stable across renames, migrations, and terminology transitions (the workstream→workplan migration cost is the proof this matters).
- Canonical names are primary for humans and agents in UI/CLI/API output, prose, and commits; UUIDs inspectable on demand. This is already practiced for WP/T — the registry universalizes it.
- Grandfathering rule (from the terminology standard): existing ids (AWQ-, OH-) are never renamed; the registry maps legacy prefixes to kinds and the legacy-meter discipline governs retirement of the schemes, not the records.
1.4 Abstract states + flow profiles (aspect 4)
- The abstract lifecycles stay minimal and canon-fixed: task
wait/todo/progress/done/cancel(InfoTechCanon); workplanproposed/ready/active/blocked/backlog/finished/archived; intake itemopen → vetted → routed → closed(promoted|declined|absorbed)⟨new, replaces both suggestion stages and queue-item ad-hoc states⟩; decisionprepared → resolved(approved|rejected|revised|deferred); engagementqueued → prepared → done. - Different work kinds (development, ops, compliance, billing, sales…)
get their demands met by flow profiles on the existing task-flow
engine: named workstation definitions whose entry/exit assertions encode
the kind-specific gates (e.g. a compliance task cannot exit
progresswithout an evidence link; a sales engagement cannot enterpreparedwithout prepared_material). Profiles are YAML in repos → same reconciliation loop. States stay abstract; rigor lives in assertions.
2. Lanes become fleet canon (aspects 1, 6, 7)
Promote binky-control's AutonomyPolicy lane model to
canon/standards/autonomy-lanes_v0.1.md, unchanged in substance:
- Green (safe autonomous) · Blue (reversible, logged) · Yellow (deferred approval) · Orange (time-window approval) · Red (human-only).
laneis a mandatory field on every work record and on every agent manifest; the harness already enforces lane-scoped tool profiles — this closes the loop from item to execution permission.- Human attention is modeled as a WIP-limited workstation: the founder attention budget (minutes/day, max decisions/day) is a lane capacity; Yellow routes to the decision queue view, Orange to the engagement view, both subject to that capacity. External research is unanimous that risk-tiered gating is the only scalable human-oversight pattern.
- Time-boxing (
needed_by,fallback_if_no_response) is hub-owned: the hub (not a human reading a file) raises the escalation when a window lapses — via the existing NATS → activity-core delegation.
3. Policy tags, not states (aspect 6)
Two tag classes, both in the tags field, never in status:
- Derived tags — computed by hub/activity-core from data, read-only in
files:
stalled(work-item age over threshold — the flow-metrics form),stale(reviewed against older repo state),overdue-decision,budget-breached,orphaned(no goal/workplan link). - Policy tags — assigned by agents/humans under tagging policies:
automatable,needs-human,unclear-implementation,red-adjacent(touches a Red boundary),compliance-relevant. Tagging policies are YAML rules (activity-coreActivityDefinitions may auto-apply them on events) — auditable and evolvable without schema migrations.
Tags drive the optimization loop: automatable feeds the autopilot view;
needs-human + lane feeds attention routing; stalled+unclear feeds the
kaizen coach. This is how "what should be automated next" becomes a query
instead of a discovery.
4. Queues are views (the reconciliation itself)
The three binky queues are retained as products, redefined as views:
| Today | Becomes |
|---|---|
| AutopilotWorkQueue.md (hand-edited) | Autopilot view: kind=intake∨task, lane∈{green,blue}, status∈{open,todo}, tag=automatable, WSJF-ordered; "never empty" becomes a monitored invariant with an alert, not a plea |
| DecisionQueue.md open section | Decision view: kind=decision, status=prepared, ordered by needed_by; resolved log is generated |
| OfficeHourQueue.md | Engagement view: kind=engagement, batched per command day; runbook generation stays (officehour/) |
Mechanics: records are authored in files (cheap intake preserved — one YAML
block, schema-checked); fix-consistency indexes them; view documents are
regenerated [auto] sections. Pull protocol becomes a status transition
(todo → progress with owner) instead of a prose note — which makes claims
visible fleet-wide and collision-free (issue-core remains the claim
interface for harness runtime; the record is the truth).
Promotion (the AWQ-010 lesson) becomes a first-class transition:
intake.routed → workplan|task|decision|engagement with back-links
(promoted_to/origin), performable by one CLI/MCP call that writes both
files and re-syncs — never a manual transcription again.
5. Visibility, tenancy, scale (aspect 2)
- state-hub remains the dev-coordination read model (localhost, file-first, fix-consistency).
- core-hub is the production visibility layer: dashboards, flow metrics (WIP, cycle time, item age, throughput — all computable from UUIDv7 + status transitions), cross-domain rollups, operator console. The work record spine becomes part of the core-hub contract/IR so Gen-3 ingests ADR-001 artefacts natively (its workplan-coordination spec already commits to this).
- Tenancy: repo → domain → tenant, derived from repo classification (never a parallel spine). agent-harness is already multi-tenant with per-tenant credential lanes (ops-warden/OpenBao); dashboards get tenant/domain scoping from the same derivation. Separation is by classification + credential lanes; centralization is by shared runtime (harness, activity-core, hubs) — efficient utilization with clean blast radii.
- Budgets as guardrail envelopes (aspect 1): per-run token budgets
(harness manifests, enforced today) roll up to per-workplan and per-lane
envelopes recorded on the work record;
record_token_eventmeters,budget-breachedtag + escalation on breach. Complex-project risk control = dependency edges (existing) + lane gates + budget envelopes + flow metrics, all on one spine.
6. Opinionated by construction (aspect 7)
- The registry is closed. An id pattern not in the type registry fails CI and fix-consistency (the "sidetrack detector" — a warning that names the reintegration cost explicitly). New kinds are added by canon PR, which is deliberately cheap (one YAML entry + one schema) so the legitimate path is easier than the workaround — the core lesson of the queues.
- AGENTS.md generation (state-hub templates) teaches the conventions in every repo; the guidance and the enforcement come from the same source.
- Intake friction budget: creating an intake item must never cost more than the AWQ pattern did (append one block). If a future workaround appears anyway, the postmortem question is fixed: which friction did we fail to remove?
7. Migration path (staged, history-preserving)
- Canonize (docs only): work-record umbrella + type registry +
autonomy-lanes standard + intake lifecycle → canon standards v0.1;
extend
workplan-terminology-fleetrather than fork it. - Schema + CI: YAML schemas per kind; Forgejo CI check; binky-control is the pilot (its queues become schema-valid without renaming ids).
- Index: fix-consistency checks for intake/decision/engagement kinds (C-2x series); hub tables reuse existing entities where they fit (suggestions table ⇢ intake items — suggestions gain file artefacts, resolving their own ADR-001 tension; decisions already dual-exist, the check just automates the mirroring both ways).
- Views: generated
[auto]sections replace hand-maintained queue tails; hub owns needed_by clocks via NATS → activity-core. - Tags + metrics: derived-tag computation and the four flow metrics in state-hub first, surfaced in core-hub dashboards as the contract lands.
- Retire legacy singularities per legacy-meter discipline (e.g. the hub-first suggestion create path) only after zero measured use.
Each stage is independently valuable; stopping after any stage leaves the system consistent (no big-bang).
8. Open questions for discussion
- Naming: "work record" vs. "work item" as umbrella; "intake item" vs. keeping "suggestion" fleet-wide; German-friendly alternatives?
- Where intake blocks live: per-repo
queues/intake.mdvs. today's thematic live documents (AutopilotWorkQueue as a view argues for separating authored records from generated views into distinct files). - Engagements as their own kind vs. decisions-with-a-time-window — the Orange lane is behaviorally distinct (batching), which argues for the separate kind, but the spine could carry it as a decision subtype.
- WSJF adoption: reuse the 2026-06-04 calibration or start simpler (lane + priority + age) and let kaizen metrics justify WSJF later?
- issue-core's long-term role: claim interface only (proposed here), or should issues become file-backed work records too?
- Suggestion table reuse vs. new intake entity in state-hub — schema archaeology needed before stage 3.
- Budget envelope placement: frontmatter on workplans vs. a separate
budgets.yamlper repo (compliance kinds may want the latter).
Prepared from live fleet data (AWQ-010 reintegration, DEC-2026-003/004 dual bookkeeping, BINKY-WP-0002 slug drift) and the two research artefacts alongside this file. Next step after discussion: canon standard drafts + a CUST workplan for stage 1–2.