Skip to content

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_agents owns: in-request Drupal agent execution — what runs inside a page request or a queue item, bounded by that request.
  • An ai_agents agent 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

  1. The Ledger is Dolt. BluCity-Docs/ledger/ is a projection of it. OBSERVED: the projections/ directory is empty, and ledger/ holds 17 subdirectories including decision-records (13 files) and decision-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.
  2. 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.
  3. Evidence lives in the Ledger; Context holds a reference plus validity — never a copy.
  4. 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."
  5. 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_context entities indexed via ai_search into 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:

  1. Policy — extend BluCity-Packs/core/policies/factory-continuation-directive.yaml (kind: Policy, spec.rules[].{name,enforcement,condition}). Gate fields become condition rules; FACTORY_GATE=FAIL becomes enforcement: deny.
  2. Cedar — the deny rules compile to Cedar in the cedar_policies rig, which is already the policy authority. No new evaluator.
  3. Fragment — add factory-execution-gate to core/pack.toml append_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_OWNER and CAPABILITY_MATCH are where the Upstream Substitution Ledger is enforced mechanically. A build bead whose SOURCE_OWNER resolves to an upstream project returns FACTORY_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/census and /usage carry the numbers.
  • Enforced at Order dispatch, not by asking an agent to remember it. Read-only discovery is exempt.
  • Emits factory.gate.evaluated as the first evidence record of every operation — also the header of the Operational Receipt (bc-mwqp).
  • EXECUTION_SURFACE resolves 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 .sh in 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.lock must 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.

  1. Collapse 3 registries to 1. registry.yaml is canonical; delete agent-registry.yml and platform-agents-registry.ossa.yaml; fix the stale repository: to blueflyio/agentictools/agents.
  2. Reconcile the 2 identity files into one, with real service-account ids only.
  3. Audit 142 manifests against the claimed 34. Classify CANONICAL / DUPLICATE / SUPERSEDED / DELETE — code-reviewer vs code-quality-reviewer, blu vs @blu/*, drupal vs @drupal/*, dispatcher vs default-orchestrator. Report `− removed /
  4. added`; net must be negative.
  5. 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-implement bmad.* / compound-engineering.* / superpowers.* / drupalworks.*.
  6. Provision GitLab service accounts, replacing every id: TBD. No agent uses Thomas's identity. Tokens via 1Password only (op run --account blueflyiollc --).
  7. Register them as gc agents so gc sling can 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.org gitlab_templates own 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/census own 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_agui own 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_metering own those
  • Let ai_agent_orchestra / ai_agentic_workflows orchestrate — that forks the work graph and breaks GAS_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 the delivery/gitlab formulas — they exist
  • Create bc-mwqp again 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/migration stub
  • Write a new doctrine .md where 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 — /waits exists
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.