275 lines
15 KiB
Markdown
275 lines
15 KiB
Markdown
|
|
# Work Orchestration Architecture — Draft for Discussion
|
|||
|
|
|
|||
|
|
> Draft v0.1 — 2026-07-19. Synthesis of
|
|||
|
|
> `2026-07-19-work-orchestration-infrastructure-survey.md` (internal) and
|
|||
|
|
> `2026-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-consistency` grows 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:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
- 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); workplan
|
|||
|
|
`proposed/ready/active/blocked/backlog/finished/archived`; intake item
|
|||
|
|
`open → vetted → routed → closed(promoted|declined|absorbed)` ⟨new,
|
|||
|
|
replaces both suggestion stages and queue-item ad-hoc states⟩; decision
|
|||
|
|
`prepared → resolved(approved|rejected|revised|deferred)`; engagement
|
|||
|
|
`queued → 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 `progress`
|
|||
|
|
without an evidence link; a sales engagement cannot enter `prepared`
|
|||
|
|
without 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).
|
|||
|
|
- `lane` is 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-core `ActivityDefinition`s 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_event` meters,
|
|||
|
|
`budget-breached` tag + 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)
|
|||
|
|
|
|||
|
|
1. **Canonize** (docs only): work-record umbrella + type registry +
|
|||
|
|
autonomy-lanes standard + intake lifecycle → canon standards v0.1;
|
|||
|
|
extend `workplan-terminology-fleet` rather than fork it.
|
|||
|
|
2. **Schema + CI**: YAML schemas per kind; Forgejo CI check; binky-control
|
|||
|
|
is the pilot (its queues become schema-valid without renaming ids).
|
|||
|
|
3. **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).
|
|||
|
|
4. **Views**: generated `[auto]` sections replace hand-maintained queue
|
|||
|
|
tails; hub owns needed_by clocks via NATS → activity-core.
|
|||
|
|
5. **Tags + metrics**: derived-tag computation and the four flow metrics in
|
|||
|
|
state-hub first, surfaced in core-hub dashboards as the contract lands.
|
|||
|
|
6. **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
|
|||
|
|
|
|||
|
|
1. **Naming**: "work record" vs. "work item" as umbrella; "intake item" vs.
|
|||
|
|
keeping "suggestion" fleet-wide; German-friendly alternatives?
|
|||
|
|
2. **Where intake blocks live**: per-repo `queues/intake.md` vs. today's
|
|||
|
|
thematic live documents (AutopilotWorkQueue as a *view* argues for
|
|||
|
|
separating authored records from generated views into distinct files).
|
|||
|
|
3. **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.
|
|||
|
|
4. **WSJF adoption**: reuse the 2026-06-04 calibration or start simpler
|
|||
|
|
(lane + priority + age) and let kaizen metrics justify WSJF later?
|
|||
|
|
5. **issue-core's long-term role**: claim interface only (proposed here),
|
|||
|
|
or should issues become file-backed work records too?
|
|||
|
|
6. **Suggestion table reuse vs. new intake entity** in state-hub — schema
|
|||
|
|
archaeology needed before stage 3.
|
|||
|
|
7. **Budget envelope placement**: frontmatter on workplans vs. a separate
|
|||
|
|
`budgets.yaml` per 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.*
|