FACTORY MASTER TODO → EXECUTION GRAPH¶
Dispatch plan. BLU routes; BLU does not execute.
Context¶
The Master TODO (Mountains 17–40) is doctrine prose. It cannot be assigned, claimed, or verified in that form. This plan converts it into live Gas City primitives — Mountain → Convoy → Bead → Rig, plus Pack, Formula, Order, Event, Polecat, Deacon, Policy — reconciled against what already exists.
The research finding inverts the work. The TODO reads as a build list. It is a
wiring list. Gas City ships the substrate (127-path OpenAPI, JSON Schema on every
command, convoys, waits, converge loops, polecat sandboxes, patrol deacons, vendor-agnostic
skill/MCP projection). BluCity-Packs already contains a large share of the named
capabilities as working formulas and orders. gitlab_components already has a release
component catalog. BluCity already holds 3 Mountains and 11 Convoys covering most of
M17–M40. And for nearly every remaining item, an upstream or Drupal contrib project
already owns the hard part — most of it already declared in this estate's composer files.
The dominant action is substitute, reuse, wire — in that order. Net custom-LOC delta for this program must be strongly negative.
OBSERVED STATE¶
Evidence tier: Repository + Infrastructure. Runtime tier degraded (Gate Zero).
City¶
| Fact | Tag |
|---|---|
BluCity ~/Sites/blueflyio/BluCity, API 127.0.0.1:8372, supervisor PID 81860, 30 rigs |
OBSERVED |
| 357 beads — 297 open, 52 in_progress | OBSERVED |
MOUNTAINs: bc-0fr5 bluefly.io Product · bc-kn68 Factory Autonomy · bc-vj9w ContextControl Product |
OBSERVED |
CONVOYs: bc-3nhh A City Health · bc-i41v B Order Autonomy · bc-39zy C Factory Reuse · bc-z6db D CC Operator Surface · bc-2p90 E Provider Portability · bc-68zx BIO-1 · bc-jbsa CC-1 · bc-mwqp Work Record Profile · bc-mnw9 Estate Convergence · bc-escm GitLab Exit · bc-9vir DrupalWorks Directive |
OBSERVED |
bc-ypy2 P0 IN_PROGRESS "AGENTICTOOLS CONSOLIDATION", assignee BLU, branch feature/123-bc-ypy2-consolidation |
OBSERVED |
The substrate that already exists¶
| Primitive | Reality | Tag |
|---|---|---|
| API | Gas City Supervisor API, OpenAPI 3.1.0, 127 paths, 510 schemas at /openapi.json. beads, beads/graph/{root}, convoys, formulas (/validate,/preview,/runs,/source), orders (/check,/feed,/history), events + events/stream, mail, sling, sessions, rigs, packs, providers, /waits+/wait/{id}, /runs/census+/usage, /patches/{agent,provider,rig}, /extmsg/* |
OBSERVED |
| JSON Schema | --json-schema is a global flag on every gc command, emitting draft 2020-12 result/failure schemas |
OBSERVED |
| Formula | TOML v2: description, formula, [requires] formula_compiler=">=2.0.0", [vars.*], [[steps]]. Also YAML kind: Formula. v1 → wisp; v2 → workflow |
OBSERVED |
| Order | orders/<name>.toml — trigger (cooldown/cron/condition/event/manual) + action (formula or exec) |
OBSERVED |
| Policy | kind: Policy, spec.rules[].{name,enforcement,condition}, allow[], routing, targets. Live: core/policies/factory-continuation-directive.yaml |
OBSERVED |
| Pack | pack.toml + doctor/ agents/ commands/ skills/ orders/ formulas/ scripts/. Schema 2 |
OBSERVED |
| Polecat | Ephemeral sandbox git worktree, spawned and nuked by Gas City's bead-dispatch lifecycle — a disposable execution surface, never work authority | OBSERVED |
| Deacon | Continuous patrol via wisps. mol-deacon-patrol = agent lifecycle/health. mol-witness-patrol nudges stuck polecats. mol-refinery-patrol retires polecat worktrees |
OBSERVED |
| Converge | root bead + formula + gate = repeat until gate passes. Controller-driven on wisp_closed |
OBSERVED |
| Harness projection | gc skill → per-vendor sinks <scope-root>/.<vendor>/skills/; gc mcp list --agent/--session; /patches/* |
OBSERVED |
| Doctrine-once | core/pack.toml append_fragments = [reuse-first, work-authority, provenance, delegation, git-lifecycle, hygiene, verification, ownership, commands, how-to-work, working-with-rig-beads, handoff, environment] |
OBSERVED |
Capability the TODO asks for that ALREADY EXISTS¶
| TODO asks for | Already exists | Tag |
|---|---|---|
drupal-estate-inventory |
drupal/core/formulas/drupal-estate-inventory.toml + manual order |
OBSERVED |
drupal-release-verify |
drupal/core/formulas/drupal-release-verification.toml + weekly order |
OBSERVED |
drupal-config-impact |
drupal/core/formulas/drupal-config-sync-verification.toml |
OBSERVED |
| M25 quality gate | drupal/core/formulas/drupal-component-quality-gate.toml |
OBSERVED |
| M34 Operational Receipt | bc-mwqp plus formulas/governed-work-lifecycle.yaml chaining intake→route→reconcile→receipt + orders work-request-intake, blocked-work-route, delivery-reconcile, receipt-on-close |
OBSERVED |
| M20 MR/pipeline flow | delivery/gitlab/formulas/{gitlab-mr-deliver,gitlab-push-mr,gitlab-pipeline-wait,gitlab-branch-disposition,mol-gitlab-mr-triage} + orders gitlab-watch, gitlab-mr-nightly-sweep |
OBSERVED |
| M19 release components | gitlab_components/: components/{deploy-oracle,dev-package,ossa-studio,stamp-release}.yml, release/{npm-public,composer-package,release-gate,semantic-release-automation,smart-version-bump}, packages/semantic-release-config, .releaserc.json, cliff.toml |
OBSERVED |
| M37 CI false-pass | core/formulas/false-green-detection.toml — complete, well-authored |
OBSERVED |
| M36 economics | /runs/census, /usage, gc costs, gc analyze reliability |
OBSERVED |
| "never poll a pipeline" | /waits, /wait/{id}, gitlab-pipeline-wait |
OBSERVED |
| M29 Migration pack | drupal/migration/ exists but is a stub — every dir .gitkeep |
OBSERVED |
| Patrols / Dogs | orders stale-work-patrol, evidence-integrity-patrol, worktree-convergence-patrol, claude-hook-sync-patrol; bd.dog (0–2) |
OBSERVED |
Upstream and contrib already declared in this estate¶
| Package | Occurrences in composer.json / package.json | Tag |
|---|---|---|
phpstan/phpstan |
97 | OBSERVED |
drupal/ai_agents |
32 — more than drupal/ai itself |
OBSERVED |
drupal/eca |
31 | OBSERVED |
drupal/ai |
28 | OBSERVED |
drupal/ai_agents_ossa |
11 — an OSSA↔Drupal agent bridge already exists | OBSERVED |
ai_search 6 · ai_logging 5 · ai_automators 4 · ai_assistant_api 4 · ai_agents_tunnel 4 |
— | OBSERVED |
ai_provider_* × 10 distinct providers (anthropic, openai, litellm, ollama, apple, huggingface, openrouter, mistral, lmstudio, amazeeio) |
— | OBSERVED |
ai_vdb_provider_qdrant 2 · ai_metering 1 · ai_agents_agui 2 · ai_agents_dashboard 3 · ai_eca 2 |
— | OBSERVED |
| Qdrant referenced in 1335 YAML lines across the estate | — | OBSERVED |
Langfuse configured in .agents/agentic-marketplace |
— | OBSERVED |
kb_cache present in 5 separate locations — source authority unresolved |
— | OBSERVED |
BluCity-Docs/ledger/ — 17 subdirs, incl. decision-records and decision-records2; projections/ is empty |
— | OBSERVED |
gc bd provenance → unknown command while bd --help lists it — gc bd shells a different bd |
— | OBSERVED |
mglaman/phpstan-drupal |
16 | OBSERVED |
semantic-release |
12 | OBSERVED |
drupal/ai_context |
9 | OBSERVED |
drupal/migrate_tools |
6 | OBSERVED |
drupal/security_review, drupal/migrate_plus, drupal/group |
4 each | OBSERVED |
mglaman/drupal-check |
1 | OBSERVED |
Drupal.org gitlab_templates CI |
in use by contrib modules across the estate | OBSERVED |
| OpenTelemetry | otel.config.js ×2 |
OBSERVED |
| Renovate | renovate.json ×1 (.agents/upstream-agui only) |
OBSERVED |
drupal/upgrade_status, drupal/rector |
absent | NOT_FOUND |
INFERRED: the Factory's problem is not missing capability. It is that capability is
unwired, unlocked (packs.lock holds only schema = 1), unverified, and in several
places about to be rebuilt when contrib already ships it.
Agents¶
| Fact | Tag |
|---|---|
~/Sites/blueflyio/.agents/agents → blueflyio/agentictools/agents, 142 manifests across @ossa 97, @blu 23, @drupal 17, @openclaw 3, @iac-operator 2 |
OBSERVED |
3 competing registries — registry.yaml (claims "Canonical 34 Agents — DRY: no second registry"), agent-registry.yml, platform-agents-registry.ossa.yaml |
OBSERVED |
2 competing identity files — agent-identities.json (9 doctrine roles, pending-sync, id: TBD) vs service-account-mapping.json (real SA ids, different naming) |
OBSERVED |
| MAYOR / DEACON / WITNESS / REFINERY / POLECAT are upstream Gas City pack roles, evidenced as pools on all 8 rigs of the 2026-07-27 city | OBSERVED |
Root pack.toml: "Gas Town (gastown pack) is NOT imported. Do not re-add." Upstream Gas City packs (core, bd) are imported by leaf packs |
OBSERVED |
Defect: mol-deacon-patrol calls gc agents list --json --active, which does not exist in the installed gc |
OBSERVED |
GATE ZERO — runtime repair (blocks all bead creation)¶
Confirmed from ~/Sites/blueflyio/BluCity/.gc, so not a working-directory artifact.
| # | Blocker | Evidence | Fix owner |
|---|---|---|---|
| Z1 | Dolt schema missing leases |
gc convoy list → Error 1146 (HY000): table not found: leases |
upstream bd migration — do not hand-write DDL |
| Z2 | bd vs linked beads library mismatch |
WARN native_store_unavailable gate=version_compat on city + every rig |
pin versions; config, not code |
| Z3 | 12 rigs missing .beads/metadata.json |
gate=preflight_unavailable (compliance_engine, duadp, gitlab_components, iac, openclaw, amcs-demo, bluefly-io, demo-agentdash, demo-agent-marketplace, contextcontrol-ai, contractplane-ai, ai-agents-ossa, marketplace-blueflyagents) |
bd init per rig |
| Z4 | Controller init failed | Controller: supervisor-managed (PID 81860, init failed) |
gc supervisor logs |
| Z5 | ossa CLI broken |
ERR_MODULE_NOT_FOUND: 'commander' from @bluefly/openstandardagents |
one missing dependency — reinstall, write nothing |
| Z6 | packs.lock empty (schema = 1) |
BluCity-Packs/packs.lock |
gc pack fetch + pin |
| Z7 | mol-deacon-patrol calls a non-existent command |
gc agents list --json --active |
one-line formula fix — a live false green |
Z1–Z4 → beads under bc-3nhh. Z5 → bc-ypy2. Z6–Z7 → bc-39zy.
Nothing else starts until Z1, Z2, Z4 are green. A backlog no agent can claim is not progress.
Diagnostics in order: gc supervisor logs → gc doctor → Dolt schema inspect on
127.0.0.1:3308/hq → bd version vs city-pinned beads version.
UPSTREAM SUBSTITUTION LEDGER¶
The controlling section. Before any Convoy opens a bead, it resolves this table. Where an upstream owner exists, Bluefly writes configuration and a thin adapter — never a reimplementation. Bluefly's legitimate surface reduces to five things: estate fan-out, authorization gates, decision records, receipts, and scope resolution.
| Need | Upstream / contrib owner | Bluefly actually owns | Status |
|---|---|---|---|
| M25 Drupal CI quality gate | Drupal.org gitlab_templates — already in use by contrib in this estate |
a thin component that include:s it and supplies Bluefly vars |
SUBSTITUTE |
| Static analysis, deprecations | phpstan/phpstan (97), mglaman/phpstan-drupal (16), mglaman/drupal-check, Drupal/DrupalPractice sniffs |
ruleset config only | SUBSTITUTE |
| M26 advisory / release detect | composer audit (FriendsOfPHP advisories DB), drupal.org release-history feed, Drupal security advisories |
the estate fan-out, not the detector | SUBSTITUTE |
| M26 update-plan + apply | Renovate (native Composer manager, native GitLab MRs) or violinist.io | the authorization gate on the MR Renovate opens | SUBSTITUTE |
| M26 db-update, config impact | drush updatedb, drush config:status, existing drupal-config-sync-verification |
receipt capture | REUSE |
| M27 custom-code analysis | PHPStan + drupal-check + Rector/drupal-rector + Upgrade Status + phpcs | the KEEP/HARDEN/REPLACE/DELETE decision record | SUBSTITUTE (rector + upgrade_status NOT_FOUND — add as deps, not as code) |
| M28 upgrade | Upgrade Status, Drupal Rector, composer-patches |
estate sequencing | SUBSTITUTE |
| M29 migration | migrate_plus(4) / migrate_tools(6) / migrate_upgrade + core Migrate API |
source-specific mappings only, in the existing stub pack | SUBSTITUTE |
| M30 customer UI | ai_agents_dashboard(3), ai_dashboard(2), ai_agent_ossa_ui_components(3), Views, drupal/eca(31), SDC |
zero custom PHP — config entities only | SUBSTITUTE |
| M31 AGUI | drupal/ai_agents_agui(2) |
view composition config | SUBSTITUTE |
| M32 sovereignty | drupal/group(4) + core entity access + Cedar/ContractPlane |
policy config | SUBSTITUTE |
| M33 context model | drupal/ai_context(9) + ai_search(6) + ai_vdb_provider_qdrant(2) |
scope resolution before model invocation | SUBSTITUTE |
| M24 kb_cache | drupal/ai_context — audit before changing kb_cache |
only what ai_context genuinely lacks | SUBSTITUTE |
| Agent definition in Drupal | ai_agents(32) Config Entities + ai_agents_ossa(11) bridge |
agent configs — no custom agent runtime, no OSSA↔Drupal bridge | SUBSTITUTE |
bc-2p90 provider portability |
ai_provider_{anthropic,openai,litellm,ollama,apple,huggingface,…} |
provider config; litellm as gateway | SUBSTITUTE |
| Model tracing + cost | ai_logging(5), ai_metering(1), ai_agents_ossa_token_efficiency(3), Langfuse, OTel |
retention and thresholds | SUBSTITUTE |
| M18 provenance | npm --provenance, PyPI Trusted Publishers (OIDC), Sigstore/cosign |
nothing | SUBSTITUTE |
| M19 release engine | semantic-release(12) + git-cliff (cliff.toml) + existing release/{npm-public,composer-package,release-gate,semantic-release-automation,smart-version-bump} + packages/semantic-release-config |
only the 4 missing channels: pypi, drupal, container, gascity-pack | REUSE |
| M17 NAS durability | restic / borg / rclone — integrity hashing and restore are solved | the restore-rehearsal order and its receipt | SUBSTITUTE |
| M20 merge trains | GitLab native merge trains + merged-results pipelines | per-project train-safety classification | CONFIG |
| M21 identities | GitLab service accounts + 1Password | one mapping file | CONFIG |
| M22 Duo governance | GitLab Duo MCP registry + tool management | the allowlist and its contracts | CONFIG |
| M37 observability | OpenTelemetry (otel.config.js ×2) + OtterMon + gc events/stream, gc analyze, /runs/census |
dashboards and alert thresholds | SUBSTITUTE |
| M23 Moshi/OMO | upstream projects | classification only; NOT_NEEDED is a valid outcome |
CLASSIFY |
| Gate policy engine | Cedar / ContractPlane (already the policy authority) | the gate's rules as Cedar policy | SUBSTITUTE |
| Z5 | npm i commander |
nothing | SUBSTITUTE |
Rule this table enforces: a Convoy may not open a build bead until it has recorded
SOURCE_OWNER= and CAPABILITY_MATCH= against this ledger. "No upstream exists" is a
claim requiring evidence, not a default.
THE DRUPAL AI ECOSYSTEM — what it owns, and its hard boundary¶
OBSERVED in this estate's composer files. drupal/ai_agents is declared 32× — more than
drupal/ai itself (28×). This is not a greenfield; it is an installed ecosystem, and
nearly all of ContextControl's Mountains are already contrib.
| Layer | Module (× declared) | Mountain it answers | Bluefly owns |
|---|---|---|---|
| Agent definition | ai_agents (32) — agents are Config Entities |
roster, M30 | agent configs, not a runtime |
| OSSA ↔ Drupal bridge | ai_agents_ossa (11), ai_agent_ossa_ui_components (3), ai_agents_ossa_token_efficiency (3) |
how the 9 roles reach Drupal | nothing — the bridge exists |
| Providers | ai_provider_{anthropic,openai,apple,litellm,ollama,huggingface,openrouter,mistral,lmstudio,amazeeio} |
E: Provider Portability bc-2p90 |
provider config; ai_provider_litellm is the gateway |
| Retrieval / memory | ai_search (6) + ai_vdb_provider_qdrant (2) / _postgres (1); Qdrant already the estate vector DB |
M33, M24 | index config only — no custom vector logic |
| Context | ai_context (9) |
M33, M24 | scope resolution before model invocation |
| Tracing | ai_logging (5) |
the tracing question, below | log config + retention |
| Cost | ai_metering (1), ai_agents_ossa_token_efficiency (3) |
M36 Economics | thresholds, not meters |
| Customer UI | ai_agents_dashboard (3), ai_dashboard (2) |
M30 | Views + config |
| AGUI | ai_agents_agui (2) |
M31 | view composition config |
| Automation | ai_eca (2), ai_integration_eca (2), ai_automators (4) |
M26/M30 glue | ECA models, zero PHP |
| Tools / schema | ai_assistant_api (4), ai_schema (1) |
Tool API surface | tool configs |
| Orchestration | ai_agent_orchestra (2), ai_agentic_workflows (2), ai_agents_communication (2), ai_agents_tunnel (4), ai_agents_kagent (1) |
— | see boundary below |
The hard boundary¶
GAS_CITY=SOLE_ORCHESTRATOR is a Factory invariant. ai_agent_orchestra,
ai_agentic_workflows and ai_agents_communication are orchestration modules. Enabling
them as orchestrators violates the invariant and creates a second work graph.
- Gas City owns: durable work (Beads), dispatch, claims, convoys, events, receipts.
ai_agentsowns: in-request Drupal agent execution — what runs inside a page request or a queue item, bounded by that request.- An
ai_agentsagent may be invoked by a Gas City formula step. It may never schedule, claim, or own work. - The orchestration modules are CLASSIFY-only in this plan: establish whether each is (a) disabled, (b) enabled but in-request only, or (c) actually orchestrating. Case (c) is a defect bead, not a feature.
M24 kb_cache, restated: audit ai_context first and keep only what it genuinely
lacks. OBSERVED blocker — kb_cache exists in 5 locations:
Scratch/kb-cache-fix/, BluCity/.gc/worktrees/kb_cache (the sanctioned gc worktree),
WIP/contextcontrol-ai/web/modules/custom/, WIP/bluefly.io/web/modules/custom/,
WIP/contextcontrol-ai/vendor/bluefly/. Source authority is unresolved. Resolving it
is the first bead of convoy H — before a single PHPCS fix.
LEDGER vs CONTEXT — tracking, tracing, cataloging¶
These are two different systems that this estate currently conflates, which is why BluCity-Docs holds 1550 markdown files.
| LEDGER | CONTEXT | |
|---|---|---|
| Answers | What happened? | What is true now? |
| Mutability | Append-only. Never edited. | Current-state. Always supersedable. |
| Authority | Beads + Gas City events + receipts, in Dolt | ContextControl + ai_context |
| Storage | Versioned SQL (Dolt 127.0.0.1:3308/hq) |
Drupal entities + ai_search/Qdrant vectors |
| Retrieval | Query by run / actor / time / bead | Scoped retrieval before model invocation |
| Types | RUN, EVENT, RECEIPT, EVIDENCE, CLAIM, DECISION-as-taken | FACT, POLICY, CONSTRAINT, DECISION, ADR, ASSUMPTION, EXCEPTION, FINDING, PROCEDURE, LESSON, CAPABILITY (M33) |
| Scope | Global, immutable | GLOBAL → ORG → TEAM → PROJECT → SITE → OPERATION → RUN |
| Markdown's role | A projection. Never the record. | Never markdown |
Rules¶
- The Ledger is Dolt.
BluCity-Docs/ledger/is a projection of it. OBSERVED: theprojections/directory is empty, andledger/holds 17 subdirectories includingdecision-records(13 files) anddecision-records2(5) — a duplicate — plus dated one-off dirs (2026-08-02/,fleet-audit-2026-07-22/,drupal-lane-audit-2026-09-14/,parity-check/,townevidence/). The ledger is currently authored by hand into the projection surface. That inversion is the defect. - Context never holds a receipt. The Ledger never holds a current-state claim. A receipt is what happened; a policy is what is true. Filing one as the other is how both rot.
- Evidence lives in the Ledger; Context holds a reference plus validity — never a copy.
- Promotion is gated. A Lesson moves Ledger → Context only through the Capability
gate:
FINDABLE / APPLICABLE / EXECUTABLE / VERIFIABLE. This is M35's flywheel, and it is the only sanctioned path from "we learned something" to "the next run is cheaper." - Do not vectorize the Ledger. It is queried by SQL over structured fields. Only
Context is indexed into
ai_search/Qdrant.
Three tracing planes, one trace id¶
| Plane | What it records | Owner (all upstream) |
|---|---|---|
| Work | claim → in_progress → close, dependencies, leases | Beads / Dolt; bd provenance (append-only provenance log) |
| Orchestration | dispatch, order fire, wisp, run, step, cost | gc events, /events/stream, /runs/census, /usage, gc analyze reliability |
| Model | prompt, response, tokens, latency, cost per call | ai_logging + ai_metering in Drupal; OpenTelemetry (otel.config.js ×2) for the runtime; Langfuse (present in .agents/agentic-marketplace) where LLM-specific tracing is wanted |
RUN from the Operational Receipt (bc-mwqp) is the correlation id across all three.
Nothing new is built here; the three planes are joined on a field they already carry.
OBSERVED defect: gc bd provenance returns unknown command "provenance" while
bd --help lists it — a second facet of Z2 (gc bd shells a different bd than
~/go/bin/bd). Work-plane tracing is therefore unavailable until Z2 is fixed, which
is part of why Gate Zero blocks everything.
Cataloging¶
- Ledger catalog = Dolt schema +
bd query+/runs/census. Queryable, not searched. - Context catalog =
ai_contextentities indexed viaai_searchinto Qdrant, filtered by scope and Group access before retrieval (M32) — so an agent is never handed context it is not authorized to consume. - Capability catalog = packs and CI components, discoverable via
gc formula list,gc skill list,gc mcp list,/packs, and the component catalog.
Three catalogs, three purposes, no overlap. Today all three are partly markdown, which is the condition this convoy ends.
THE FACTORY EXECUTION GATE¶
Do not author a new doctrine document. The mechanism exists in three places; the gate extends them:
- Policy — extend
BluCity-Packs/core/policies/factory-continuation-directive.yaml(kind: Policy,spec.rules[].{name,enforcement,condition}). Gate fields becomeconditionrules;FACTORY_GATE=FAILbecomesenforcement: deny. - Cedar — the deny rules compile to Cedar in the
cedar_policiesrig, which is already the policy authority. No new evaluator. - Fragment — add
factory-execution-gatetocore/pack.tomlappend_fragments. Every agent inheriting core gets it once, by reference.
WORK_AUTHORITY= SOURCE_AUTHORITY= OWNER= RIG=
BEAD= CLAIM= CAPABILITY_MATCH=
SOURCE_OWNER= AUTHORITY= SERVICE_IDENTITY=
POLICY= DEPENDENCIES= EXECUTION_SURFACE=
ACCEPTANCE= VERIFICATION= DELIVERY_PATH= EVIDENCE_PATH=
IS_THE_NEXT_RUN_GETTING_CHEAPER_AND_MORE_REUSABLE=
WHY=
FACTORY_GATE=PASS|FAIL|PARTIAL
SOURCE_OWNERandCAPABILITY_MATCHare where the Upstream Substitution Ledger is enforced mechanically. A build bead whoseSOURCE_OWNERresolves to an upstream project returnsFACTORY_GATE=FAIL.- The reuse clause is a hard gate field, not a comment. A change that cannot name why
the next run is cheaper or more reusable returns
FAIL. It is the machine-checkable form of Net Negative Ownership, answerable because/runs/censusand/usagecarry the numbers. - Enforced at Order dispatch, not by asking an agent to remember it. Read-only discovery is exempt.
- Emits
factory.gate.evaluatedas the first evidence record of every operation — also the header of the Operational Receipt (bc-mwqp). EXECUTION_SURFACEresolves to a polecat; the gate keeps a disposable surface from ever becoming work authority.
This replaces — and deletes — the repeated prose mandates now scattered across prompts, identities, role files, and markdown.
MOUNTAIN → CONVOY MAP¶
3 existing Mountains keep their IDs. 2 new Mountains. 8 new Convoys. 1 forbidden duplicate. 14 of 24 Mountains attach to existing convoys. Every convoy resolves the Substitution Ledger first.
bc-kn68 MOUNTAIN — BLUEFLY FACTORY AUTONOMY¶
| M | Disposition | Rig |
|---|---|---|
| M17 NAS | NEW convoy F: DURABILITY — restic/borg/rclone; Bluefly owns the restore rehearsal. NAS is mirror + receipts, never source | iac |
| M20 Merge trains | EXTEND bc-mnw9 — GitLab native; classify train-safety per project, do not enable blindly |
gitlab_components |
| M21 GitLab agent delivery | EXTEND bc-i41v + bc-ypy2 — webhook → normalizer → Event; audit openstandard-gitlab-agent as the one integration |
gitlab_components |
| M22 Duo / tool governance | NEW convoy G: TOOL GOVERNANCE — Duo MCP registry + allowlist; expose existing capabilities, never a GitLab-only build | gitlab_components |
| M36 Economics | EXTEND bc-kn68 — wire /runs/census + /usage; no new metrics store |
BluCity |
| M37 Observability | EXTEND bc-3nhh — OTel + false-green-detection + events/stream |
BluCity, iac |
| M38 Pack architecture | EXTEND bc-39zy — lock packs.lock (Z6) |
blucity-packs, DrupalWorks |
| M40 Completion program | EXTEND bc-kn68 + bc-0fr5 |
bluefly-io |
bc-vj9w MOUNTAIN — CONTEXTCONTROL PRODUCT¶
| M | Disposition | Rig |
|---|---|---|
| M24 kb_cache | NEW convoy H: KB_CACHE — audit drupal/ai_context first; classify all 482 PHPCS failures by sniff before fixing any; via gc worktree |
contextcontrol-ai |
| M30 / M31 UI + AGUI | EXTEND bc-z6db — Views + ECA + SDC; zero custom PHP |
contextcontrol-ai |
| M32 Sovereignty | NEW convoy I: SOVEREIGNTY — drupal/group + entity access + Cedar; never prompt text or Views filters alone |
contextcontrol-ai, cedar_policies |
| M33 Context model | EXTEND bc-mwqp — compose ai_context, do not build storage |
contextcontrol-ai |
| M34 Operational Receipt | DO NOT CREATE. It is bc-mwqp and governed-work-lifecycle.yaml + 4 live orders. Wire and verify |
— |
NEW MOUNTAIN — DRUPAL OPERATIONS FACTORY (the commercial core)¶
Composes with bc-9vir. Each convoy begins by wiring what exists and adopting the
contrib owner from the ledger.
| M | Convoy | Starting material / substitution |
|---|---|---|
| M25 | D-0: QUALITY FLOOR | drupal-component-quality-gate.toml exists; wrap Drupal.org gitlab_templates — do not author a Drupal CI pipeline |
| M26 | D-1: SECURITY & RELEASE | drupal-estate-inventory, drupal-release-verification, drupal-config-sync-verification exist. Detection = composer audit + release-history feed. Update+apply = Renovate. Bluefly owns only: estate fan-out, the authorization gate, verification of rendered effect, recovery, receipt |
| M27 | D-2: CUSTOM CODE | PHPStan/drupal-check/Rector/Upgrade Status do the analysis. Bluefly owns the KEEP/HARDEN/REPLACE/DELETE decision record |
| M28 | D-3: UPGRADE | Upgrade Status + Rector + composer-patches. Bluefly owns estate sequencing |
| M29 | D-4: MIGRATION | Fill the existing drupal/migration stub with migrate_plus/migrate_tools config. No second pack |
NEW MOUNTAIN — RELEASE & DISTRIBUTION¶
| M | Convoy | Scope after substitution |
|---|---|---|
| M18 + M39 (merged — same inventory) | R-1: RELEASE MATRIX | Classify before publishing. Provenance is npm --provenance / PyPI Trusted Publishers / Sigstore — Bluefly writes none of it |
| M19 | R-2: RELEASE COMPONENTS | npm-public and composer-package exist. Engine is semantic-release + git-cliff. Build only 4: release-pypi, release-drupal, release-container, release-gascity-pack |
Spike (not a Mountain)¶
M23 Moshi/OMO → one research bead under bc-39zy. Classify upstream; no deployment
bead exists until classification returns a Bluefly role.
REUSABLE, COMPONENTIZED CAPABILITY THAT WORKS IN EVERY HARNESS¶
Gas City already solved projection. The job is to author capability in the shape that projects, and to stop authoring it anywhere else.
A capability is a Pack, and only a Pack. One unit, versioned and pinned:
<pack>/
pack.toml schema 2, pinned in packs.lock
formulas/ the method (TOML v2, [vars], [[steps]])
orders/ when it fires (cron | event | condition | cooldown | manual)
skills/ SKILL.md — harness-agnostic prose
commands/ slash-command surface
agents/ roles that compose it
doctor/ its own health checks — the capability proves itself
scripts/ only where a step genuinely needs an executable
Two component catalogs, one discipline. CI work componentizes into
gitlab_components/components/ and release/; agent work componentizes into packs.
Neither may contain a copy of the other's logic, and a leaf .gitlab-ci.yml composes
components — it never reimplements them.
Projection to every harness, all upstream, none of it ours to build:
| Surface | Mechanism |
|---|---|
| Claude Code, Cursor, Codex, OpenClaw, any vendor | gc skill materializes to <scope-root>/.<vendor>/skills/; claude-hook-sync formula + patrol already do this |
| Any MCP client | gc mcp list --agent\|--session |
| Any agentic tool / script / CI | --json-schema on every gc command → draft 2020-12 contracts |
| Any service, any language | 127-path OpenAPI 3.1.0, 510 schemas — generate a client, don't write one |
| GitLab Duo (M22) | Expose the same capability via the Duo MCP registry; never a GitLab-only implementation |
| Per-target divergence | /patches/{agent,provider,rig} instead of forked copies |
Rules the gate enforces:
- Authored once, as a pack or a CI component. Never a
.shin a repo, never a skill copied between packs, never a formula duplicated to make a pack self-contained. - A capability is real only when
FINDABLE / APPLICABLE / EXECUTABLE / VERIFIABLE. A prose lesson is not a capability; a Skill is one projection of one. - Harness-specific need → a patch, not a fork.
packs.lockmust pin every pack (Z6) or none of this is reproducible.- Upstream first for roles too: MAYOR/DEACON/WITNESS/REFINERY/POLECAT are upstream Gas City
— import and configure. Only BLU/HARBORMASTER/DRUPAL/SENTINEL/FOUNDRY/FORGE are Bluefly's.
The gastown pack stays un-imported, per root
pack.toml.
AGENT ROSTER RESOLUTION¶
Attaches to bc-ypy2 (P0, in progress, assignee BLU, branch open). No new bead.
- Collapse 3 registries to 1.
registry.yamlis canonical; deleteagent-registry.ymlandplatform-agents-registry.ossa.yaml; fix the stalerepository:toblueflyio/agentictools/agents. - Reconcile the 2 identity files into one, with real service-account ids only.
- Audit 142 manifests against the claimed 34. Classify
CANONICAL/DUPLICATE/SUPERSEDED/DELETE—code-reviewervscode-quality-reviewer,bluvs@blu/*,drupalvs@drupal/*,dispatchervsdefault-orchestrator. Report `− removed / - added`; net must be negative.
- Repair
ossa(Z5 — one dependency), then generate only the Bluefly-owned roles. Import upstream for MAYOR/DEACON/WITNESS/REFINERY. Roles compose existing pack agents as their toolset and must not re-implementbmad.*/compound-engineering.*/superpowers.*/drupalworks.*. - Provision GitLab service accounts, replacing every
id: TBD. No agent uses Thomas's identity. Tokens via 1Password only (op run --account blueflyiollc --). - Register them as gc agents so
gc slingcan address them.
Until step 6, assignment uses the live roster:
| Doctrine role | Live agent today | Owns |
|---|---|---|
| BLU | this session | routing, mail, orders — never execution |
| MAYOR | core.control-dispatcher (upstream) |
dispatch |
| HARBORMASTER | organization.harbormaster |
cross-rig delivery |
| REFINERY | organization.worker (0–4) (upstream patrol) |
release mechanics, worktree retirement |
| FOUNDRY | agent-docker/* |
images, runtime surfaces |
| DRUPAL | drupalworks.drupal-architect/-auditor/-builder/-migrator |
every Drupal mountain |
| SENTINEL | compound-engineering.ce-security-reviewer |
security |
| WITNESS | compound-engineering.ce-* reviewers (upstream patrol) |
independent verification, nudging stuck polecats |
| FORGE | superpowers.implementer + .finisher |
clean-consumer proof |
| DEACON (patrol) | bd.dog (0–2), gastown.deacon |
agent lifecycle, health, stale leases, worktree lifecycle |
DISPATCH MODEL — how BLU stays free¶
BLU's steady state is an empty context waiting on mail. This is already policy:
factory-continuation-directive.yaml denies BLU source edits, commits, pushes, MR
mutations, merges and branch deletions, and allows exactly READ_*,
CREATE_OR_REFINE_DURABLE_WORK, ASSIGN_OR_ROUTE_BEAD, GC_MAIL,
REQUEST_WITNESS_VERIFICATION, RECONCILE_RECEIPTS. Enforce it; do not restate it.
gc mail inbox / reply → decide and route
gc sling <agent> <bead> → route via the target's sling_query
gc order create → recurring + event-driven dispatch, gate-enforced
gc hook --claim → agents pull routed work atomically
gc converge create → bounded refine-until-gate-passes, controller-driven
gc event emit → the only wake mechanism
/waits, /wait/{id} → block on a condition without burning a session
/extmsg/* → bind external conversations into city mail
Events replace polling — gitlab-pipeline-wait and /waits exist for exactly this.
Normalized set:
pipeline.finished mr.ready mr.conflicted
train.entered train.ejected mr.merged
drupal.advisory.published factory.gate.evaluated
Deacons and dogs patrol deterministically, not with model tokens: stale-lease reclaim
(bd reclaim), polecat/worktree retirement, orphaned Dolt cleanup (gc dolt-cleanup),
registry drift, .beads/metadata.json presence. Orders stale-work-patrol,
evidence-integrity-patrol, worktree-convergence-patrol exist — wire them, and fix Z7 so
the deacon patrol stops silently failing.
DOCUMENTATION — BluCity-Docs¶
Rig blucity-docs holds 1550 markdown files across
ledger/{directives,receipts,evidence,audits,execution-plans,decision-records2,
continual-learning,verification}, Playbooks/, Engineering-Standard/, projections/,
strategy/.
Net markdown count must not increase. Update and merge; delete superseded pages. No new
top-level .md.
| Page | Action |
|---|---|
factory-execution-gate |
Fold into the existing policy doc — do not author a second gate doc |
upstream-substitution-ledger |
The controlling table above — the one genuinely new page, because nothing currently records it |
mountain-convoy-bead-model |
Update existing: primitives are Agent/Bead/Formula/Rig/Pack/Event; roles are not primitives |
capability-as-pack |
Merge into an existing pack/standards page if one covers it |
agent-roster |
Update existing: upstream vs Bluefly-owned, service accounts, OSSA provenance |
operational-receipt |
Fold into bc-mwqp's schema page — do not author a second one |
release-contract |
Update existing: semantic-release + git-cliff + the component catalog |
Doctrine lives here once. Prompts, role files and AGENTS.md reference it; they do not
copy it. Copying canonical doctrine into local memory is prohibited.
EXECUTION WAVES¶
| Wave | Content | Gate to advance |
|---|---|---|
| 0 | Gate Zero: Z1–Z7 | gc convoy list returns; gc doctor clean; a test bead claims and releases |
| 1 | Gate as Policy rule + Cedar + core fragment; Substitution Ledger published; bc-ypy2 consolidation; service accounts |
FACTORY_GATE=PASS on a real operation by a non-Thomas identity, with SOURCE_OWNER resolved |
| 2 | Create 2 Mountains + 8 Convoys; attach the 14 extensions; wire and substitute — do not rewrite | gc graph shows one connected graph, no orphans, no bc-mwqp duplicate, no build bead whose SOURCE_OWNER is upstream |
| 3 | D-1 Security & Release on ESTATE=bluefly.io — DETECT→UNDERSTAND→MATCH→AUTHORIZE→ACT→VERIFY→PROVE→IMPROVE |
All 8 stages PASS with receipts |
| 4 | Run 2, same estate | Reuse up, re-derivation down, cost/outcome down — from /runs/census + /usage |
| 5 | Second estate | Only now is it a proven reusable capability |
Waves 0–2 are plumbing and must not expand. Wave 3 is the product.
VERIFICATION¶
Runtime, not repository — a green file proves nothing (false-green-detection exists
because of this).
cd ~/Sites/blueflyio/BluCity/.gc
# Wave 0 — the claim path works
gc status # controller running, no init failure
gc convoy list # rows, not "table not found: leases"
gc doctor # no native_store_unavailable
gc bd list --limit 0 # full backlog via native store
# Wave 1 — the gate is machine-evaluated, not remembered
gc formula validate factory-execution-gate
gc order check
gc events | grep factory.gate.evaluated
# Wave 2 — one graph, nothing rebuilt
gc graph <mountain-id> # no orphan convoys, no bc-mwqp duplicate
gc bd list --limit 0 | grep -c MOUNTAIN # expect 5
gc formula list # reused formulas, not re-authored ones
# Capability projection — the "every harness" claim
gc skill list --agent <role>
gc mcp list --agent <role>
gc event emit --json-schema
curl -s http://127.0.0.1:8372/openapi.json | jq '.paths | length' # 127
# Ledger vs Context — the three planes join on RUN
gc bd provenance <bead> # work plane (blocked until Z2)
gc events --json | jq '.[].run_id' # orchestration plane
drush ai:logging:list # model plane (ai_logging), same RUN
drush config:status # Context is config entities, not code
# Ownership — the claim this plan is judged on
git diff --shortstat # net custom LOC must be negative
Acceptance for the program: an agent that is not Thomas claims a bead, executes it in a
polecat under FACTORY_GATE=PASS, delivers through GitLab, and WITNESS verifies it
independently — with BLU never leaving the mail loop.
WHAT THIS PLAN REFUSES TO DO¶
- Write a Drupal security scanner, updater, or CI pipeline —
composer audit, Renovate and Drupal.orggitlab_templatesown those - Write deprecation or upgrade analysis — PHPStan, drupal-check, Rector, Upgrade Status own it
- Write a migration engine — migrate_plus / migrate_tools / core Migrate API own it
- Write a release engine, changelog generator, or provenance signer — semantic-release,
git-cliff, npm
--provenance, PyPI Trusted Publishers, Sigstore own those - Write backup, hashing, or restore tooling — restic / borg / rclone own it
- Write telemetry — OpenTelemetry and
/runs/censusown it - Write a policy evaluator — Cedar / ContractPlane own it
- Write custom PHP for ContextControl UI — Views, ECA, SDC,
drupal/group,ai_agents_dashboard,ai_agents_aguiown it - Build an OSSA↔Drupal agent bridge —
ai_agents_ossa(11×) exists - Build an agent runtime, vector storage, provider wrapper, model logger, or token meter —
ai_agents,ai_search+Qdrant,ai_provider_*,ai_logging,ai_meteringown those - Let
ai_agent_orchestra/ai_agentic_workflowsorchestrate — that forks the work graph and breaksGAS_CITY=SOLE_ORCHESTRATOR; classify, don't enable - Vectorize the Ledger, or file a receipt as Context
- Hand-author ledger records into
BluCity-Docs/ledger/— Dolt is the ledger, markdown is a projection - Touch a kb_cache PHPCS failure before its source authority is resolved across the 5 copies
- Re-author
drupal-estate-inventory,drupal-release-verification,drupal-config-sync-verification,drupal-component-quality-gate,release/npm-public,release/composer-package, or thedelivery/gitlabformulas — they exist - Create
bc-mwqpagain as "M34 Operational Receipt" - Build MAYOR/DEACON/WITNESS/REFINERY/POLECAT, or re-add the gastown pack
- Add a 4th agent registry or a 3rd identity file
- Create beads before Wave 0 makes them claimable
- Turn all 24 Mountains into beads — 14 attach to existing convoys
- Open a Migration Factory — M29 fills the existing
drupal/migrationstub - Write a new doctrine
.mdwhere a fragment or Policy rule is the right surface - Deploy Moshi/OMO before classification returns a Bluefly role
- Poll a pipeline from a model session —
/waitsexists
IS_THE_NEXT_RUN_GETTING_CHEAPER_AND_MORE_REUSABLE = YES
WHY = ~28 needs are substituted onto upstream or contrib owners already declared in this
estate, reducing Bluefly's surface to estate fan-out, authorization gates, decision
records, receipts and scope resolution; ~12 named capabilities already exist as
formulas or CI components and are wired rather than written; M19 drops from 7 new
components to 4; 14 of 24 Mountains reuse existing convoys; 142 agent manifests
collapse toward 34 and 3 registries toward 1; policy is evaluated once at dispatch
instead of restated in every prompt and markdown file; capability is authored once as
a Pack or CI component and projected to every harness by upstream mechanisms rather
than re-implemented per tool; the whole ContextControl mountain resolves to installed
drupal/ai contrib (ai_agents 32x, ai_agents_ossa 11x, ai_context, ai_search+Qdrant,
ai_logging, ai_metering, ai_agents_agui) instead of custom PHP; the Ledger stops
being hand-authored markdown and becomes a queryable Dolt record with markdown as a
projection; three tracing planes join on one RUN id already present rather than a new
observability stack; and the gate makes both reuse and SOURCE_OWNER machine-checked
fields backed by /runs/census and /usage rather than claims.