STD-DRUPAL-004: Producer / Consumer Repository Ownership¶
Status: Active Authority: Bluefly Engineering — Drupal Architecture Date: 2026-10-10
0. Estate Rule (Canonical Language)¶
PRODUCER REPO OWNS SOURCE.
CONSUMER SITE OWNS COMPOSITION.
WEB TREE IS NOT AUTHORITY.
NO ORPHANED SOURCE CHANGES.
These four statements are binding across the entire Bluefly Drupal estate.
1. Scope¶
This standard applies to every Bluefly-owned Drupal package type:
| Package type | Ownership model |
|---|---|
| Custom module | Own canonical repository |
| Custom theme | Own canonical repository |
| Recipe | Own canonical repository |
| Site template | Own canonical repository |
| DDEV add-on | Own canonical repository |
| Canvas/SDC producer | Own canonical repository |
| Private extension | Own canonical repository |
| Other Drupal package | Own canonical repository |
A Drupal site (bluefly.io, contextcontrol-ai, etc.) is a consumer.
It assembles producer packages through Composer. It does not own their source.
2. Producer vs Consumer Responsibilities¶
2.1 Producer repo owns¶
PHP source
Twig templates
JavaScript
CSS / SCSS
SDC component definitions (.component.yml, .twig, scoped assets)
Module / theme metadata (.info.yml, .libraries.yml, .services.yml)
Services and plugins
Tests (PHPUnit, Nightwatch, Kernel, etc.)
Package-level CI (.gitlab-ci.yml or CI component inclusion)
Recipe definitions
Site-template definitions
2.2 Consumer site may own¶
composer.json
composer.lock
config/sync/
Site-specific Canvas page composition (canvas_page entities)
Site-specific content and configuration
settings.php / settings.local.php
DDEV consumer configuration (.ddev/)
Deployment configuration (docker-compose, Terraform, Cloudflare)
Site-specific integration configuration
2.3 The distinction¶
COMPONENT DEFINITION → PRODUCER
PAGE COMPOSITION → CONSUMER
A producer defines a reusable SDC component (cc-hero, bluefly-button).
A consumer places that component on a Canvas page with specific prop values.
3. Filesystem Location Does Not Define Authority¶
A writable file under web/ is never evidence of ownership.
Repository and package ownership defines authority.
3.1 Embedded .git does not grant authoring authority¶
A package checkout located under a consumer site at:
web/modules/custom/<package>/
web/themes/custom/<package>/
may be any of:
- Composer source-install projection
- Embedded producer checkout (local cache)
- Runtime clone
Regardless of whether it contains its own .git directory, it is classified as:
CONSUMER_RUNTIME_PROJECTION
READ_ONLY_FOR_AGENT_AUTHORING
until proven to be a Gas City governed worktree of the producer Rig.
3.2 Rule¶
EMBEDDED .git ≠ DEVELOPMENT AUTHORIZATION
An embedded .git proves the path is a separate repository.
It does not prove the path is an approved development worktree.
4. Required Pre-Edit Gate¶
Before any agent edits Drupal producer source, the agent must determine:
WHAT_PACKAGE=
WHAT_PROJECT_TYPE= (module | theme | recipe | site-template | ddev-addon | other)
WHAT_GITLAB_REPO=
WHAT_RIG=
WHAT_BEAD=
IS_GOVERNED_WORKTREE= YES | NO
If IS_GOVERNED_WORKTREE is not YES:
DO_NOT_EDIT
The agent must instead:
- Identify the producer repository
- Obtain or create a governed worktree for the producer Rig
- Branch from current
release/v0.1.x - Perform edits in the governed worktree
- Follow the delivery flow (§5)
5. Required Delivery Flow¶
The canonical producer-to-consumer lifecycle:
Bead
→ Producer Rig
→ Governed producer worktree
→ Feature branch from release/v0.1.x
→ Implementation
→ Producer tests
→ Commit (approved identity only)
→ Push
→ Producer MR → release/v0.1.x
→ CI (PASS required)
→ WITNESS (PASS required)
→ Merge
→ Consumer site: composer update <package>
→ Consumer: composer.lock updated
→ Consumer MR → release/v0.1.x
→ CI (PASS required)
→ Visual/runtime verification
→ WITNESS (PASS required)
→ Merge
The following is explicitly prohibited:
ANTI-PATTERN:
edit installed copy under web/
→ site looks correct locally
→ producer repo unchanged
→ next composer install destroys the change
6. Orphaned Source Changes¶
6.1 Definition¶
An orphaned source change is a legitimate producer-source modification found only inside a consumer/runtime checkout — never committed to the producer repository.
6.2 Recovery procedure¶
1. Preserve the exact diff
2. Identify the owning producer repository
3. Identify the existing Bead (or create one if none exists)
4. Recover the diff into a governed producer worktree
5. Deliver a producer MR through the standard flow (§5)
6. Merge the producer change
7. Update the consumer via Composer
8. Clean the consumer projection
6.3 Rules¶
- Never delete valid unique work merely to make the consumer repository clean.
- Never use committed
.patchfiles as a substitute for recovering source into its producer repository. - Target:
ORPHANED_PRODUCER_CHANGES=0
7. Prohibited Git Operations¶
Agents must not use the following as generic recovery or development techniques inside consumer sites:
git add -f web/modules/custom/...
git add -f web/themes/custom/...
git clean -fd (without per-path classification first)
git commit --no-verify
git clean requires every affected untracked path to be classified as:
owned by this repo, owned by a producer, or generated artifact — before removal.
8. Configuration Safety¶
Before every Drupal config import or export:
ddev drush cst
Record the result. Do not blanket export configuration.
CST_BEFORE=
CONFIG_DIRECTION= (import | export)
CST_AFTER=
LATEST_CONFIG_IN_GIT=YES
9. Gas City Alignment¶
This standard reinforces the execution model:
| Concern | Authority |
|---|---|
| Orchestration / work | Gas City |
| Durable work tracking | Beads |
| Project execution scope | Rig |
| Source / MR / CI / release | GitLab |
| Execution surface | DDEV (local) / Oracle (production) |
Drupal sites do not become work authorities, schedulers, or Bead stores.
10. Bluefly Estate Examples¶
10.1 Correct ownership map¶
| Package | Producer repository (GitLab) |
|---|---|
bluefly_theme |
blueflyio/agent-platform/drupal/themes/bluefly_theme |
contextcontrol_theme |
blueflyio/agent-platform/drupal/themes/contextcontrol_theme |
contractplane_client |
blueflyio/agent-platform/drupal/private/contractplane_client |
source_connector |
blueflyio/agent-platform/drupal/private/source_connector |
recipe_blucity |
blueflyio/agent-platform/drupal/recipes/recipe_blucity |
agentic_canvas |
blueflyio/agent-platform/drupal/themes/agentic_canvas |
10.2 Correct workflow¶
# Producer: fix a bug in bluefly_theme
bead → bluefly_theme rig → governed worktree
→ git checkout -b fix/<bead>-description
→ edit src/tokens.css
→ npm run build
→ git commit
→ git push
→ MR to release/v0.1.x
→ CI PASS → WITNESS PASS → merge
# Consumer: pull the fix into bluefly.io
→ composer update drupal/bluefly_theme
→ git add composer.lock
→ git commit
→ MR to release/v0.1.x
→ CI PASS → ddev drush cr → visual verify → merge
10.3 Incorrect workflow (PROHIBITED)¶
# WRONG: editing the installed copy
cd bluefly.io/web/themes/custom/bluefly_theme
vim src/tokens.css ← VIOLATION: consumer projection
git add -f src/tokens.css ← VIOLATION: force-adding producer source to consumer repo
git commit ← VIOLATION: wrong repository
# Producer repo is unchanged; next composer install destroys the edit
11. Cross-References¶
- STD-DRUPAL-002 (Composition & Theme Governance Doctrine): Establishes
DRUPAL_SITES_ARE_CONSUMERS=YESandEDIT_ACTIVE_WEB_FOLDER=NO. This standard (004) provides the detailed enforcement model. - STD-DRUPAL-003 (Custom Module Decomposition Contract): Governs what custom modules may contain. This standard governs where they are authored.
- STD-WORK-001 (Durable Work Governance): Worktree isolation, one lane = one bead.
- STD-AUTH-001 (Authority Precedence): Authority chain for standards decisions.