Skip to content

Enforce dev→prod version discipline: prod can never be ahead, dev must precede prod #21

Description

@MyAlterLego

Goal

Every Triarch deploy must follow dev → prod. Two invariants the pipeline must enforce:

  1. Prod can never be a higher version than dev. If dev_version >= attempted_prod_version is false, the prod deploy is blocked.
  2. The exact version going to prod must have been successfully deployed to dev first. No bypassing dev "just this once," regardless of who is asking — including Mike.

Current state

There is no enforcement. As of 2026-05-14:

  • projects.current_version in triarch.dev is a single field — no separation of dev vs prod
  • latest_dev_at / latest_prod_at timestamps exist on projects but nothing checks order
  • Deploy workflows in shared-workflows fire on push: [main, release/**, hotfix/**] and immediately deploy to whatever Firebase target the workflow targets
  • A direct push to main or hotfix/** deploys to prod without a prior dev step

Proposed enforcement

1. Schema: separate dev and prod version per project

```sql
ALTER TABLE projects
ADD COLUMN dev_version TEXT,
ADD COLUMN prod_version TEXT,
ADD COLUMN dev_version_deployed_at TIMESTAMPTZ,
ADD COLUMN prod_version_deployed_at TIMESTAMPTZ;
-- Drop current_version after migrating callers
```

Populated by shared-workflows' notify step after a successful deploy to each env.

2. Pre-prod-deploy gate (new reusable workflow)

Add .github/workflows/gate-prod-version.yml in shared-workflows:

```yaml
inputs:
project_key: string # e.g. "triarchsecurity-admin"
target_version: string # e.g. "v3.54.0"

jobs:
gate:
steps:
- Fetch project's dev_version + prod_version from triarch.dev API
- Assert target_version <= dev_version (semver compare)
- Assert target_version > prod_version
- Assert dev_version_deployed_at >= 5 minutes ago AND the dev release for this exact version is recorded
- Fail loudly with a Slack notification if any assertion fails
```

3. Wire into each project's CI/CD

Each project's .github/workflows/*.yml for prod deploys gets:

```yaml

  • uses: triarchsecurity/shared-workflows/.github/workflows/gate-prod-version.yml@v8
    with:
    project_key: triarchsecurity-admin
    target_version: ${{ needs.version.outputs.version }}
    ```

The gate runs before the deploy step. Fails the job if invariants are violated.

4. Branch policy

  • main always deploys to dev (not prod). The current "push to main deploys to prod" pattern flips.
  • release/** and hotfix/** branches deploy to prod, but only after passing the gate
  • Direct prod deploys via workflow_dispatch still go through the gate — no manual bypass
  • --no-verify and [skip ci] ignored by the gate workflow

5. Audit + alerting

  • Every gate check writes an audit log entry to triarch.dev (action: "deploy_gate_check" with target_version, dev_version, prod_version, result)
  • A failed gate posts to the project's Slack channel + the central deploy-audit channel
  • Daily brief surfaces any gate failure in the last 24h

Acceptance

  • New schema columns populated on every successful deploy
  • Gate workflow exists in shared-workflows
  • All 6 deployable projects (admin, portal, dev-portal, tmi, darksouls, truthtreason) use the gate on prod deploys
  • A test deploy attempting prod-without-dev fails the gate and surfaces the failure clearly
  • A test deploy attempting prod with version ≤ current prod fails the gate
  • Mike (or anyone) cannot bypass — no --force or [skip gate] option

Context

Mike's explicit ask 2026-05-14:

"I need to be sure that both the production and development versions are clear for each project, and that the ci-cd pipeline enforces that process... that prod can never be a higher version than dev, and that deployments MUST go to dev before going to prod, regardless of how many corners I want to cut myself."

The "regardless of how many corners I want to cut myself" is intentional — no escape hatch.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions