EP-02 · Visual Specification

Monorepo CI/CD Release Flow

Pipeline architecture for continuous deployment in a monorepo environment, with snapshot-based release promotion and signed tag governance integration.

Version 1.1
Type Visual Specification
Format Pipeline Architecture
Last Updated 2026-05-14
Changelog v1.1 — unified example data across timeline and body; added TL;DR and stable-app explanation
Fig. 1 · Two-Layer Timeline EP-02 · v1.1
================================================================================
  TWO INDEPENDENT LAYERS
================================================================================

  Layer 1 is the dev timeline — apps build at their own pace and the lanes
  never stop. Layer 2 is the release process — it only exists when a
  snapshot is cut.

  Each snapshot is one ticket, one shared release tag, one Azure Release run.

  >> EVERY CONTAINER TRACES BACK VIA COMMIT_HASH (runtime -> source)


================================================================================
  LAYER 1 - DEV - CONTINUOUS - 4 LANES
================================================================================

  SRC: MONOREPO - CONTINUOUSLY-COMMITTED - MAIN

  TIMELINE RUNS LEFT to RIGHT
  EVERY ALPHA DEPLOY WIRES: APP_VERSION + COMMIT_SHA + IMAGE_TAG (server)


  TIME ---------------------------------------------------------------------->
       JAN            FEB            MAR            APR            NOW


  APP1 *---------*-----------*--------------*---------------*
       v2.2.0    v2.3.0      v2.3.1         v2.4.0          v3.0.0
       #22       #27         #31            #35             #41
       a1b2c3    d4e5f6      g7h8i9         abc245          j1k2l3


  APP2 *--------------*---------------*----------*------*
       v1.0.4         v1.0.6          v1.0.7     v1.0.8 v2.0.3
       #8             #13             #17        #19    #22
       m3n4o5         p6q7r8          s9t0u1     v2w3x4 abc245


  APP3 *---*----------*-----*-------------*------------------*
       v0.9.0         v0.9.3     v0.9.5    v1.0.4             v1.0.7
       #11   #14      #19   #21           #24                #27
       y5z6a7         e1f2g3     h4i5j6   abc245             k7l8m9


  APP4 *-----------------------------------------------------------------
       v1.2.0  (stable - no rebuild; same image picked by BOTH snapshots)
       #5
       n0o1p2

                        |                            |
                        |                            |
                    SNAPSHOT 1                   SNAPSHOT 2
                    2026-02-15                   2026-04-30
                    REL-02-15                    REL-04-30
                    commit: any in window        commit: any in window
                    (highest tag: #31)           (highest tag: #41)


================================================================================
  LAYER 2 - RELEASE - TRIGGERED-BY-SNAPSHOT - 2 RUNS
================================================================================

  ENV WIRED ON EVERY HOST
  each deploy (alpha OR beta) writes these env vars:
  COMMIT_HASH, APP_VERSION, DOCKER_TAG (sequential build #)


  ---------------                                ---------------
  RELEASE RUN #1                                 RELEASE RUN #2
  ---------------                                ---------------

  2026-02-15                                     2026-04-30
  REL-02-15                                      REL-04-30

  TICKET                                         TICKET
    REL-2026-02-15                                 REL-2026-04-30

  RELEASE TAG (GIT + DOCKER)                     RELEASE TAG (GIT + DOCKER)
    signed-2026-02-15.1                            signed-2026-04-30.1

  GIT COMMIT (HIGHEST TAG)                       GIT COMMIT (HIGHEST TAG)
    g7h8i9  (tag #31 from app1)                    j1k2l3  (tag #41 from app1)

  TAGGED IMAGES: SAME BYTES                      TAGGED IMAGES: SAME BYTES
    app1:27  -> signed-02-15.1                     app1:41  -> signed-04-30.1
      commit: d4e5f6                                 commit: j1k2l3
      version: v2.3.0                                version: v3.0.0
    app2:13  -> signed-02-15.1                     app2:22  -> signed-04-30.1
      commit: p6q7r8                                 commit: abc245
      version: v1.0.6                                version: v2.0.3
    app3:19  -> signed-02-15.1                     app3:27  -> signed-04-30.1
      commit: e1f2g3                                 commit: k7l8m9
      version: v0.9.3                                version: v1.0.7
    app4:5   -> signed-02-15.1                     app4:5   -> signed-04-30.1
      commit: n0o1p2                                 commit: n0o1p2
      version: v1.2.0                                version: v1.2.0
      (stable - same image)                          (stable - same image)

  MANIFEST: /releases/                           MANIFEST: /releases/
    signed-2026-02-15.1.json                       signed-2026-04-30.1.json

  AZURE RELEASE PIPELINE                         AZURE RELEASE PIPELINE
    triggered: signed-* git tag                    triggered: signed-* git tag
    -> manual approval (C3)                        -> manual approval (C3)
    -> deploy to Beta                              -> deploy to Beta

  BETA DEPLOY: 4 HOSTS LIVE                      BETA DEPLOY: 4 HOSTS LIVE
    COMMIT_HASH=d4e5f6  (app1)                     COMMIT_HASH=j1k2l3  (app1)
    GIT_TAG=signed-2026-02-15.1                    GIT_TAG=signed-2026-04-30.1
    DOCKER_TAG=27                                  DOCKER_TAG=41
    APP_VERSION=v2.3.0                             APP_VERSION=v3.0.0


  IMAGE_TAG column is identical - that's the shared signed release tag
  COMMIT_HASH shows exact Git state for each app's build
  Discovery: query /health or $COMMIT_HASH to trace back to source
TL;DR. Two release modes share one pipeline. Traditional: build new code, sign it, ship. Snapshot (the headline idea): tag whatever's already been running stably in Alpha and promote that exact state to Beta or Production — no rebuild. The "anchor" for a snapshot is the highest sequential Docker build tag currently deployed; that tag's commit becomes the Git target for a signed-* release tag. Beta/Production deploys are gated by manual approval and the C3 Four-Eyes Principle (approver ≠ requester). Every container reports COMMIT_HASH, DOCKER_TAG, and APP_VERSION via /health so the discovery step can be automated.

1. Overview

This document specifies the continuous integration and continuous deployment (CI/CD) pipeline architecture for a monorepo environment containing multiple applications. The pipeline supports both traditional releases (deploying new code) and snapshot releases (promoting existing deployed state), with cryptographic authorization via signed tags.

Key Characteristics

Intended Audience

1.1 How to Read This Document

This is a comprehensive technical specification (~750 lines). Different readers have different needs:

If you're new to the system (30 minutes):

  1. Read Section 1 (Overview) for key characteristics and audience → 5 min
  2. Review Section 2 (Architecture Principles) for core concepts → 10 min
  3. View the ASCII Timeline (hero section above) to visualize the two-layer model → 5 min
  4. Jump to Section 6 (Snapshot Releases) to understand the key differentiator → 15 min

If you're implementing the pipeline (focus on mechanics):

If you're operating the system (day-to-day usage):

If you're troubleshooting:

2. Architecture Principles

2.1 Monorepo Build Model

The pipeline operates on a monorepo where:

  1. All apps share a single Git repository with a unified main branch
  2. Each app/package maintains its own semantic version (v2.3.0, v1.0.6)
  3. Commits to main trigger CI pipeline evaluation to detect changed apps
  4. Only apps with changes (source code or dependencies) are rebuilt

Incremental build strategy:

2.2 Docker Image Tagging Strategy

Each Docker image receives three types of tags:

Tag Type Format Example Purpose
Sequential Plain integers (monorepo-wide) 22, 27, 31, 41 Chronological build order
Semantic Per-app semver v2.3.0, v1.0.6, v0.9.3 Human-readable app version
Signed signed-YYYY-MM-DD.N (date + sequence) signed-2026-02-15.1, signed-2026-04-30.1 Governance/authorization marker

2.3 Environment Variable Contract

On deployment, each app container receives environment variables capturing full traceability. These variables form the contract between the CI/CD pipeline and runtime applications, enabling discovery, debugging, and audit trails.

Lifecycle Table

Variable Set By Set When Consumed By Purpose
COMMIT_HASH CI Pipeline Docker build App /health endpoint, DevOps scripts, monitoring Git traceability - links runtime to source
DOCKER_TAG CI Pipeline Docker build Discovery scripts (release-tagger.js), operations Sequential build number for ordering
GIT_TAG Release Pipeline Deployment Monitoring dashboards, audit logs Identifies release version (signed-*)
APP_VERSION CI Pipeline (from package.json) Docker build UI footer, /health endpoint, support tickets User-facing semantic version
ENVIRONMENT Deployment script Deployment App runtime (feature flags, config selection) Environment-specific behavior
BUILD_DATE CI Pipeline Docker build Support, debugging Temporal correlation
DEPLOY_DATE Release Pipeline Deployment Operations, SLA tracking Deployment timeline

Critical for Snapshot Discovery

The following variables must be exposed via /health endpoint for automated snapshot discovery:

Example Contract

# Git metadata
COMMIT_HASH=d4e5f6789012345678901234567890abcdef0123
GIT_TAG=signed-2026-02-15.1
GIT_BRANCH=main

# Docker metadata
DOCKER_TAG=27
DOCKER_IMAGE=duckbook.azurecr.io/app1:27

# App metadata
APP_VERSION=2.3.0
BUILD_DATE=2026-02-14T12:34:56Z

# Environment context
ENVIRONMENT=beta

Usage scenarios:

3. Pipeline Stages

3.1 Continuous Integration (CI)

Continuous Integration Pipeline

1
Detect Changes
git diff HEAD^ HEAD · Parse changed paths · Check dependency graph
2
Run Tests & Security Scans
Unit + integration tests · Mend.io in block mode
3
Build Docker Images
Assign build number (27) · Apply app version (v2.3.0) · Inject COMMIT_HASH, DOCKER_TAG
4
Push to Registry
duckbook.azurecr.io/app1:27 · duckbook.azurecr.io/app1:v2.3.0

Trigger: Commit to main branch

3.2 Continuous Deployment (CD) - Alpha Environment

Continuous Deployment (Alpha)

1
Pull Latest Images
By sequential tag (27, 28...)
2
Deploy to Hosts
Azure Web Apps / AKS · Set env vars · Wait for /health OK

Characteristics:

3.3 Release Pipeline - Beta/Production

Release Pipeline (Beta/Production)

1
Manual Approval Gate
Four-Eyes Principle (C3) · Approver ≠ Requester
2
Pull Images by signed-* tag
duckbook.azurecr.io/app1:signed-2026-02-15.1
3
Deploy to Target Environment
Beta or Production · Based on tag pattern
4
Update Ledger
/governance/ledger.md · Record commit, approver, timestamp

Trigger: Detection of signed-* tag in Git repository

4. Environment Deployment Matrix

4.1 Pipeline Trigger Patterns

Event CI Pipeline CD Pipeline (Alpha) Release Pipeline (Beta/Prod)
Commit to main ✅ Build all changes ✅ Auto-deploy ❌ No trigger
Create rc-v* tag ✅ Build + security scan ❌ No deploy ❌ No trigger
Create signed-* tag ❌ No build ❌ No deploy ✅ Trigger + manual approval
Manual trigger ⚠️ Optional rebuild ⚠️ Optional redeploy ✅ Standard release workflow
Dependency update ✅ Rebuild affected apps ✅ Auto-deploy ❌ No trigger

Legend: ✅ = Automatic trigger · ❌ = No action · ⚠️ = Available via manual trigger only

4.2 Environment Characteristics

Alpha (Dev)

  • Deployment: Automatic on commit
  • Tags: Sequential (22, 27, 31, 41...)
  • Approval: None
  • Frequency: Continuous (daily)
  • Rollback: Automatic
  • Access: Dev team

Beta (Staging)

  • Deployment: Manual (signed tags)
  • Tags: signed-2026-02-15.1
  • Approval: Manual (C3)
  • Frequency: Weekly/monthly
  • Rollback: Manual with approval
  • Access: Dev + IT + stakeholders

Production

  • Deployment: Manual (signed tags)
  • Tags: signed-2026-04-30.1
  • Approval: Manual (C3)
  • Frequency: Quarterly or on-demand
  • Rollback: Manual with approval
  • Access: IT ops + executives

5. Docker Tag Lifecycle

5.1 Tag Progression Example

Commit App Sequential Semantic Signed Tag Environment
a1b2c3 app1 22 v2.2.0 - Alpha
d4e5f6 app1 27 v2.3.0 - Alpha
g7h8i9 app1 31 v2.3.1 signed-2026-02-15.1 Beta
abc245 app2 35 v2.0.3 - Alpha
j1k2l3 app1 41 v3.0.0 signed-2026-04-30.1 Production

5.2 Tag Timeline Visualization

Commit Timeline (main branch)
a1b2c3
Build #22 (app1)
22
v2.2.0
d4e5f6
Build #27 (app1)
27
v2.3.0
g7h8i9
Build #31 (app1)
31
v2.3.1
signed-2026-02-15.1
→ Beta
j1k2l3
Build #41 (app1)
41
v3.0.0
signed-2026-04-30.1
→ Production

6. Snapshot-Based Releases

6.1 Conceptual Model

What is a snapshot release?

A snapshot release promotes existing deployed apps (already running in Alpha) to Beta/Production WITHOUT rebuilding code. Instead of deploying new commits, we "snapshot" the current state and tag it for promotion.

Why snapshot releases exist:

Key difference from traditional releases:

Aspect Traditional Release Snapshot Release
Trigger NEW code committed EXISTING deployment stable
Process Commit → Build → Deploy Discover → Tag → Promote
Risk Deploying untested code Deploying pre-validated code
Timing Coupled to dev completion Decoupled from dev work
Example "Deploy feature X that merged today" "Promote whatever's in Alpha to Beta"

Visual model:

Traditional:  [New Code] → CI Build → Alpha → Manual Tag → Beta
Snapshot:     [Alpha State] → Discovery → Manual Tag → Beta
                    ↑
              (Already deployed,
               already tested)

Stable apps: same bytes, new tag

A monorepo typically contains apps that change rarely — internal tools, settled services, libraries that haven't needed a fix in months. In the hero timeline, app4 (v1.2.0, build #5) is one of these: it hasn't been rebuilt since its initial deploy, but it must still ship as part of every signed release. Snapshot releases handle this naturally — we apply the new signed-* Docker tag to the existing app4:5 image. No rebuild, no version bump; the bytes that have been running in Alpha for months are the same bytes that ship to Beta and Production. Traditional release flows would force a rebuild here just to attach a new tag; snapshot flows don't.

6.2 Discovery Workflow: Highest Tag Logic

When creating a snapshot release, we need to determine the Git commit that represents the current Alpha state. Since multiple apps may have been built from different commits, we use the highest Docker tag as the anchor point.

Definition: "Highest Tag"

Highest tag = max(DOCKER_TAG) across all deployed apps in target environment

Discovery Algorithm

1. Query /health endpoint for each app in Alpha
2. Extract DOCKER_TAG from each response
3. Identify highest_tag = max(DOCKER_TAG)
4. Find commit_hash for the app with highest_tag
5. Use commit_hash as Git tag target for signed-* release tag

Example: Highest Tag Selection

Scenario: Four apps deployed in Alpha (includes app4, a stable app with no recent rebuilds)

App COMMIT_HASH DOCKER_TAG APP_VERSION Deployed At
app1 g7h8i9 31 v2.3.1 2026-02-10 ← HIGHEST
app2 p6q7r8 13 v1.0.6 2026-01-20
app3 e1f2g3 19 v0.9.3 2026-02-05
app4 n0o1p2 5 v1.2.0 2025-08-15 (stable; no rebuild)

Result:

Insight: The commit g7h8i9 (tag 31) is an immutable snapshot of the monorepo that includes the current source for every app — including app4, which hasn't been rebuilt in months. We tag the existing app4 image (build #5) with the same signed-* tag; no rebuild is required because its bytes haven't changed.

Edge Cases

Case 1: App not rebuilt in months (the "stable app" case)

app1: tag 27  (rebuilt 2 weeks ago)
app4: tag 5   (rebuilt 9 months ago - stable, no changes)
app3: tag 19  (rebuilt yesterday)

Outcome: Highest tag = 27 (app1). The commit for tag 27 includes all code, including app4's unchanged state from 9 months ago. The existing app4:5 image is tagged with the new signed-* alias — no rebuild.

Case 2: Multiple apps with same highest tag

Commit abc245 changed app1 AND app2:
  app1: tag 34
  app2: tag 35  ← Both from same commit

Outcome: Either tag 34 or 35 can be used — they point to the same commit (abc245).

Case 3: App deleted from monorepo

app1: tag 41
app2: tag 38
app3: REMOVED (no longer exists)

Outcome: Highest tag = 41. Old app3 Docker images remain in registry but are not deployed.

Discovery Methods

Apps expose version information through multiple channels:

Method Access Pattern Example Output Use Case
Environment Vars echo $COMMIT_HASH g7h8i9d4e5f6 Direct server access
Health Endpoint GET /health {"commit":"g7h8i9","tag":31} Automated discovery (primary)
UI Footer Visual inspection v2.3.1 (g7h8i9) #31 Manual verification
Container Metadata docker inspect <image> Labels: commit=g7h8i9, tag=31 Registry queries
Azure Portal View environment vars COMMIT_HASH=g7h8i9, DOCKER_TAG=31 IT operations

Health endpoint response example:

{
  "status": "healthy",
  "version": {
    "app": "2.3.1",
    "commit": "g7h8i9d4e5f6",
    "commitShort": "g7h8i9d",
    "tag": "signed-2026-02-15.1",
    "branch": "main"
  },
  "docker": {
    "image": "duckbook.azurecr.io/app1:31",
    "tag": "31",
    "registry": "duckbook.azurecr.io"
  },
  "build": {
    "number": 31,
    "date": "2026-02-10T12:34:56Z"
  },
  "environment": "beta",
  "deployedAt": "2026-02-15T15:20:10Z"
}

6.3 Operational Workflow

This section describes the step-by-step procedure for creating and deploying a snapshot release.

Step-by-Step Flowchart

┌─────────────────────────────────────────────────────────────────┐
│  PHASE 1: READINESS ASSESSMENT (Manual - PM/DevOps)             │
└─────────────────────────────────────────────────────────────────┘
                               ↓
          [PM determines Alpha is stable and ready]
                               ↓
          [DevOps queries deployed state in Alpha]
                               ↓
┌─────────────────────────────────────────────────────────────────┐
│  PHASE 2: DISCOVERY (Automated - release-tagger.js)             │
└─────────────────────────────────────────────────────────────────┘
                               ↓
    $ node scripts/release-tagger.js --discover --env alpha
                               ↓
    Query /health on all apps → Extract DOCKER_TAG
                               ↓
    Find max(DOCKER_TAG) → Identify commit_hash
                               ↓
    Output:
      app1: commit g7h8i9, tag 31  ← HIGHEST
      app2: commit p6q7r8, tag 13
      app3: commit e1f2g3, tag 19
      app4: commit n0o1p2, tag 5   (stable, no rebuild)

      Release candidate: commit g7h8i9
                               ↓
┌─────────────────────────────────────────────────────────────────┐
│  PHASE 3: APPROVAL GATE (Manual - C3 Handshake)                 │
└─────────────────────────────────────────────────────────────────┘
                               ↓
    [Create release ticket: REL-2026-02-15]
                               ↓
    [Requester documents readiness evidence]
                               ↓
    [Approver reviews (approver ≠ requester)]
                               ↓
    [Approver grants authorization]
                               ↓
┌─────────────────────────────────────────────────────────────────┐
│  PHASE 4: DUAL TAGGING (Automated - release-tagger.js)          │
└─────────────────────────────────────────────────────────────────┘
                               ↓
    $ git tag signed-2026-02-15.1 g7h8i9
    $ git push origin signed-2026-02-15.1
                               ↓
    $ node scripts/release-tagger.js --tag signed-2026-02-15.1 --auto
                               ↓
    Tags applied to Docker images:
      duckbook.azurecr.io/app1:31 → signed-2026-02-15.1
      duckbook.azurecr.io/app2:13 → signed-2026-02-15.1
      duckbook.azurecr.io/app3:19 → signed-2026-02-15.1
      duckbook.azurecr.io/app4:5  → signed-2026-02-15.1  (stable)
                               ↓
┌─────────────────────────────────────────────────────────────────┐
│  PHASE 5: PIPELINE DEPLOYMENT (Automated - Azure Pipelines)     │
└─────────────────────────────────────────────────────────────────┘
                               ↓
    Azure Pipeline detects signed-* Git tag
                               ↓
    Pull Docker images by signed tag
                               ↓
    Deploy to Beta environment
                               ↓
    Update /governance/ledger.md
                               ↓
┌─────────────────────────────────────────────────────────────────┐
│  DEPLOYED: Beta/Production                                       │
│  All apps now running signed-2026-02-15.1                        │
└─────────────────────────────────────────────────────────────────┘

Automation Script Example

The /scripts/release-tagger.js tool automates discovery and tagging:

# ═══════════════════════════════════════════════════════════
#  SNAPSHOT RELEASE EXAMPLE
# ═══════════════════════════════════════════════════════════

# Step 1: Discover current deployed state
node scripts/release-tagger.js --discover --env alpha

# Output:
# app1: commit g7h8i9, docker tag 31  ← HIGHEST
# app2: commit p6q7r8, docker tag 13
# app3: commit e1f2g3, docker tag 19
# app4: commit n0o1p2, docker tag 5   (stable, no rebuild)
#
# Release candidate: commit g7h8i9 (tag 31)

# Step 2: Create Git tag (manual - requires authorization)
git tag signed-2026-02-15.1 g7h8i9
git push origin signed-2026-02-15.1

# Step 3: Tag Docker images (automated)
node scripts/release-tagger.js --tag signed-2026-02-15.1 --auto

# This command tags:
# • duckbook.azurecr.io/app1:31 → signed-2026-02-15.1
# • duckbook.azurecr.io/app2:13 → signed-2026-02-15.1
# • duckbook.azurecr.io/app3:19 → signed-2026-02-15.1
# • duckbook.azurecr.io/app4:5  → signed-2026-02-15.1  (existing image; bytes unchanged)

# Step 4: Pipeline auto-triggers on signed-* tag
# Azure Pipeline → Manual Approval (C3) → Deploy to Beta

Human + Automation Handoffs

Phase Actor Type Tool/Action
Readiness Assessment PM/DevOps Manual Visual inspection, testing, stakeholder consensus
Discovery Automation Automated release-tagger.js --discover
Approval Gate Approver Manual C3 handshake, ticket review
Dual Tagging (Git) DevOps Manual git tag signed-*
Dual Tagging (Docker) Automation Automated release-tagger.js --tag
Pipeline Deployment Automation Automated Azure Pipelines
Manual Approval (C3) Approver Manual Azure Pipeline approval gate
Ledger Update Automation Automated Pipeline script

6.4 Governance & Rules

Snapshot releases follow the same governance framework as traditional releases, integrated with the SDLC-PLAYBOOK authorization model.

Authorization Requirements

C3 Signed Handshake (Four-Eyes Principle):

  1. Approver identity ≠ Requester identity - Enforced programmatically by Azure Pipeline
  2. Security scan results = "Green" - Mend.io scans from original builds must have passed
  3. Functional validation completed - Evidence of Alpha testing (demo, walkthrough, logs)
  4. Bet Record linkage - Release ticket references business justification

Evidence Chain

Artifacts created for each snapshot release:

Artifact Location Content Purpose
Release manifest /releases/signed-2026-02-15.1.json Commit-to-tag mapping for all apps Traceability
Ledger entry /governance/ledger.md Approver identity, timestamp, ticket ID Audit trail
Git tag Repository signed-2026-02-15.1 → commit g7h8i9 Source control anchor
Docker tags Container registry app1:31 → signed-2026-02-15.1 (all apps) Deployment artifact
Pipeline logs Azure DevOps Deployment steps, approval records Operational record

Evidence chain flow:

Snapshot workflow:
  Deployment State → Discovery → Ticket (REL-2026-02-15) → C3 Approval →
  signed-* Git tag → Docker tags → Manifest → Ledger Entry → Deployment

Comparison to traditional workflow:

Traditional workflow:
  Bet Record → Commits → rc-* tag → Build → Pipeline Logs → 
  signed-* tag → Ledger Entry → Deployment

Integration with SDLC-PLAYBOOK

Complete Operational Guide: See SDLC-PLAYBOOK Appendix A for complete operational guide including manifest format, ledger templates, and evidence chain validation.

7. Roles and Responsibilities

7.1 Development Team

7.2 IT Operations

7.3 Authorization Gates

Every production release must pass through the C3 Signed Handshake (Four-Eyes Principle):

  1. Approver identity ≠ Requester identity
  2. Security scan results = "Green" (Mend.io block mode passed)
  3. Functional validation completed (demo or walkthrough)
  4. Bet Record exists and is linked in commit message or manifest

8. Operational Notes

8.1 Manual Release Triggers

Release pipeline triggers are intentionally manual. This design enforces:

  1. Evidence-backed deployments - Every release must have authorization artifact
  2. Deliberate promotion - Production changes are conscious decisions
  3. Governance compliance - Manual gate ensures C3 Signed Handshake is verified
  4. Blast radius control - Prevents cascading failures from auto-promoting broken builds

8.2 Evidence Chain Integration

The CI/CD pipeline integrates with the SDLC-PLAYBOOK governance framework:

Traditional workflow:

Bet Record → Commits → rc-* tag → Pipeline Logs → signed-* tag → Ledger Entry

Snapshot workflow:

Deployment State → Discovery → signed-* tag → Manifest → Ledger Entry

Appendix: Glossary

Term Definition
Sequential Tag An incrementing build number (22, 33, 44...) assigned by CI pipeline to each Docker image build. Shared across all apps in monorepo.
Semantic Tag A per-app version tag following semver (v2.3.0, v1.0.6) representing the app's release version.
Signed Tag A signed-* tag (e.g., signed-2026-02-15.1) representing authorized release approval.
Snapshot Release A release created by tagging the current deployed state across all apps, rather than deploying new code.
Dual Tagging Applying the same signed-* tag to both Git repository (commit) and Docker images in container registry.
Discovery Phase Querying deployed apps to determine their current commit hashes and Docker tags before creating a snapshot release.
Highest Tag In monorepo, the Docker image with the highest sequential tag number, indicating the most recent build.
C3 Handshake Four-Eyes Principle: production promotion requires approval from an identity other than the requester.
Monorepo Single Git repository containing multiple apps/packages with unified version control and shared dependencies.
Evidence Chain Traceable linkage from business requirement → code → security scan → approval → deployment.
Related Documents:
SDLC-PLAYBOOK - Governance framework and authorization protocols
SDLC-PLAYBOOK Appendix A - Snapshot release operational guide
/scripts/release-tagger.js - Snapshot automation tool
/releases/README.md - Release manifest documentation
/governance/ledger.md - Production release history