Engineering Policy · Governance

SDLC Playbook: The Agentic Shape Up

A framework for high-velocity R&D through intent-based governance — trunk-based development, Shape Up cadence, and Platform-as-Evidence.

Version 2.0
Strategy Trunk-Based + Shape Up
Governance Platform-as-Evidence
Last revised 2026-05-13
Approved by CIO & Product Manager
Status Active

§ 1.Core Philosophy #

This framework sets our standard for high-velocity R&D through intent-based governance. We use Trunk-Based Development on main to keep integration and learning continuous. Delivery follows the Basecamp Shape Up cadence: 6-week work cycles followed by 2-week cool-downs. Governance is anchored by Signed Tags — the primary, immutable evidence of both technical peer review and functional validation.

Fig. 1 · Shape-Up Cadence
Build Cycle 6 weeks · fixed appetite
Cool-down 2 weeks
W1W2W3W4W5W6W7W8

§ 2.The Artifact Library #Evidence as Code

The audit trail lives in the repository and in automated pipeline logs, so every release is cryptographically linked to its authorization.

Artifact Location Purpose
Bet Record /governance/bets/*.md The authorized "Pitch" defining appetite, problem, and boundaries.
Pipeline logs — (automated) The automated, immutable record of Mend.io security scans and deployment steps.
Release Ledger /governance/ledger.md The history of production releases, capturing commit hashes, authors, approvers, and validation links.
Signed Tags signed-* Cryptographic evidence of authorization and functional sign-off. Examples: signed-v1.4.0, signed-2025-q1

§ 2.1Traceability Contract #

Every production release must satisfy a deterministic evidence chain.

Traditional workflow (new code deployment):

Bet Record Commit(s) rc- tag Pipeline Logs signed- tag Ledger Entry

Snapshot workflow (promoting deployed state):

Deployment State Discovery signed- tag Manifest Ledger Entry

See Appendix A for snapshot-based releases.

Linkage rules

Enforcement. CI rejects rc- tags whose commit lacks a Bet Record ID, and signed- tags missing any required reference. Broken chains never reach production — they fail at the gate, not in review.

§ 2.2Revocation #

A signed- tag is immutable, but its trust is not. If post-release analysis invalidates an authorization, the Approver appends a Revocation Entry to the Release Ledger citing the original tag, the reason, and the remediating signed- tag (if any). The original tag remains in history as evidence of what was authorized; the Ledger is the source of truth for what is currently trusted.


§ 3.The Triple-Guardrail Controls #

C1Independent Verification #

Mend.io runs in block mode within the pipeline for every rc- tag. This gate stops vulnerable code from progressing to sign-off.

C2Agent Config Shield #

The .agent-config.json file (which defines model versions and system prompts) is protected by CODEOWNERS and branch protection. Any change requires a review signature from an identity outside the developer group.

C3The Signed Handshake #Four-Eyes Principle

Production promotion requires a signed- tag from an identity other than the requester.

Player-Coach ProtocolIf the CIO contributes code, approval authority passes to the Product Manager to preserve independence.

§ 3.1Control Responsibility Matrix #

Control Area System (Agent / Pipeline) Human Responsibility Override Authority
Code generation AI Agent proposes commits Developer validates intent and correctness; commits under their identity Developer (always)
Security validation Mend.io scan in block mode Approver confirms results in pipeline log None — gate cannot be bypassed
Functional validation Developer demonstrates behavior; Approver confirms against Bet Record Approver
Release authorization Approver applies signed- tag Approver ≠ requester (C3)
Agent config integrity Pipeline enforces CODEOWNERS on .agent-config.json Independent signer approves changes Non-developer identity only

Principle. Machines validate consistency and policy. Humans validate intent and correctness. The Agent never signs.


§ 4.The "Professional Handshake" SOP #Formally: Release Authorization Protocol

A three-step procedure that converts a commit on main into a release-grade, signed artifact.

1 · Candidate
The Candidate
rc-v*

A developer tags a commit on main to signal technical readiness. This triggers the automated Mend.io scan.

2 · Signature
The Signature
two-stage verification

Phase ASecurity. Approver confirms Mend.io results are "Green" in the pipeline logs.

Phase BFunctional. Developer runs a functional review; Approver confirms the code meets the Bet Record.

3 · Tag-as-Review
Tag-as-Review
signed-v*

The Approver pushes the signed- tag. This serves as a non-repudiable signature confirming the artifact meets all requirements.

§ 4.1Cool-down Protocol #Hotfix Path

Urgent patches bypass the 6-week rhythm but retain the same controls:

  1. Branch from main, tag rc-hotfix-v* — triggers C1 (Mend.io scan).
  2. Apply the C3 Signed Handshake — the Approver signs signed-hotfix-v*.
  3. Record in the Release Ledger with a "Hotfix" justification and a link to the incident or vulnerability that motivated it.

The Appetite is not extended. Hotfix work consumes cool-down capacity.


§ 5.FAQ: Governance & Methodology #

Q.1Why Trunk-Based Development instead of Pull Requests (PRs)?

TBD minimizes integration latency by promoting small, frequent commits to main with continuous automated validation. We shift the governance control point from the PR to two stronger anchors: automated pipeline gates (security, build, tests) and cryptographic attestation of authorization via Signed Tags. PRs are a review surface; Signed Tags are an authorization artifact. We prioritize deterministic, auditable promotion over asynchronous review workflows — the review still happens, it just doesn't gate the merge.

Q.2How is peer review satisfied without a PR?

Through the Signed Handshake. A signed- tag is a formal approval from a second identity after they have reviewed the code's functional output and the machine's security scans.

Q.3What happens if an urgent security patch is needed mid-cycle?

See § 4.1 — the Cool-down Protocol. Hotfix work passes the same C1 scan and C3 Signed Handshake as normal releases; it does not extend the Appetite.

Q.4Who is accountable if the AI Agent makes a mistake?

Accountability stays with the human team. The C1 Mend.io scan is our automated judge, and the C3 human signature is our final gate. The Agent is a tool; the Signer is the owner.

Q.5How do we prevent "Management Override" when the CIO is also coding?

Via the Player-Coach Protocol. The system rejects any signed- tag where the Tagger is also the Author of the commits. If the CIO writes code, the Product Manager must serve as the Approver.

Q.6What happens to unfinished work at the end of 6 weeks?

The Circuit Breaker kicks in: incomplete projects are archived. This prevents "Zombie Projects" and ensures the team only ships what is fully validated.


§ 6.Glossary #

Term Definition
Appetite The fixed time budget (6 weeks) we are willing to spend.
Shadow Tickets Automated traceability placeholders mapping commits to business requirements.
Circuit Breaker A hard stop at 6 weeks that preserves the integrity of the team's Appetite.
Revocation Entry A Ledger record that withdraws trust from a previously signed- tag without rewriting history.
Snapshot Release A release created by tagging the current deployed state across all apps, rather than deploying new code. Uses the commit with the highest Docker tag.
Sequential Tag A Docker image tag using incrementing build numbers (e.g., 22, 33, 44) assigned by the CI pipeline for each build.
Dual Tagging The process of applying the same signed-* tag to both the Git repository (commit) and Docker images in the container registry.
Discovery Phase The process of querying deployed apps to determine their current commit hashes and Docker tags before creating a release.

APPENDIX Snapshot-Based Release Workflow #

Purpose: This appendix describes how to create production releases by snapshotting the current deployed state, rather than deploying new code. This approach is ideal when the dev/alpha environment is stable and ready for promotion.

A.1Understanding the Monorepo Release Model #

In our monorepo setup:

Key principle: Because this is a monorepo, all apps deployed at or before commit X will have Docker tags ≤ the tag of the app built from commit X.

A.2Discovery Phase: Finding What's Deployed #

Before creating a release, you must discover the current deployment state.

For Product Managers (Non-Technical)

Check the UI footer on each app, or use the discovery script:

node scripts/release-tagger.js --discover

For Developers

Option 1: Query health endpoints (if implemented):

curl https://app1.yourcompany.com/health
curl https://app2.yourcompany.com/health
curl https://app3.yourcompany.com/health

Option 2: Check environment variables on the host

Option 3: Use automated discovery script

Example Discovery Output

Querying apps...
✓ app1: commit 43jdfd342, docker tag 33
✓ app2: commit 3289h3292, docker tag 44  ← HIGHEST
✓ app3: commit v04343432, docker tag 22

Latest commit identified: 3289h3292 (docker tag 44)

The commit with the highest Docker tag is your release candidate.

A.3Creating a Signed Release #

Once you've identified the latest commit, follow these steps:

Step 1: Verify the Commit in Git

# Ensure the commit exists on main branch
git log --oneline | grep 3289h3292

# Verify it's on main
git branch --contains 3289h3292

Step 2: Choose Your Tag Format

The signed-* prefix is required. Choose a suffix based on your release cadence:

Format Pattern Example Use Case
Semantic signed-v<M>.<m>.<p> signed-v1.4.0 Incremental feature releases with version tracking
Quarterly signed-<YYYY>-q<N> signed-2025-q1 Business milestone releases (quarterly planning)
Date-based signed-<YYYY>-<MM>-<DD> signed-2025-05-14 Ad-hoc releases (demos, client deliveries)
Hotfix signed-hotfix-v<M>.<m>.<p> signed-hotfix-v1.3.2 Emergency patches with version increment

Naming rules:

Step 3: Tag Git Repository

# Example: Quarterly release
git tag -a signed-2025-q1 3289h3292 -m "Q1 2025 Release | Apps: 22,33,44"
git push origin signed-2025-q1

# Example: Semantic version
git tag -a signed-v1.4.0 3289h3292 -m "Release v1.4.0 | All apps snapshot"
git push origin signed-v1.4.0

Step 4: Tag Docker Images (Dual Tagging)

You must tag all deployed Docker images with the same signed-* tag.

Automated approach (recommended):

# Use the release tagger script
node scripts/release-tagger.js --tag signed-2025-q1 --docker-tags 22,33,44

# Or auto-discover and tag
node scripts/release-tagger.js --tag signed-2025-q1 --auto

The script will:

Step 5: Trigger Release Pipeline

The Azure Release Pipeline should be configured to trigger on signed-* tags. This pipeline includes a manual approval gate (C3 control).

Logical flow:

  1. Pipeline detects new signed-* tag in Git
  2. Pipeline reads the tag to identify which Docker images to pull (from registry)
  3. Manual Approval Gate — Approver reviews release manifest, ledger entry, and changes
  4. After approval, pipeline pulls Docker images by signed-* tag
  5. Pipeline deploys to beta or production environment

A.4Visual Workflow Diagram #

┌──────────────────────────────────────────────────────────────────┐
│  SNAPSHOT-BASED RELEASE: From Deployment to Production           │
└──────────────────────────────────────────────────────────────────┘

[Apps Running in Alpha Environment]
┌──────────────────────────────────────────────────┐
│ app1: /health → { commit: "43jdfd342", tag: 33 } │
│ app2: /health → { commit: "3289h3292", tag: 44 } │ ← HIGHEST TAG
│ app3: /health → { commit: "v04343432", tag: 22 } │
└──────────────────────────────────────────────────┘
                     ↓
         [Discovery: Query Apps]
         node scripts/release-tagger.js --discover
                     ↓
         Latest commit: 3289h3292 (docker tag 44)
                     ↓
         ┌─────────────────────────────────┐
         │  Dual Tagging Process           │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Git: Tag Commit                │
         │  git tag signed-2025-q1         │
         │  → commit 3289h3292              │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Docker: Tag Images             │
         │  duckbook.azurecr.io            │
         │  Tag 22,33,44 → signed-2025-q1  │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Release Manifest Created       │
         │  /releases/signed-2025-q1.json  │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Ledger Entry Added             │
         │  /governance/ledger.md          │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Azure Release Pipeline         │
         │  Triggered by: signed-2025-q1   │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Manual Approval Gate (C3)      │
         │  Approver: PM or CIO            │
         │  Reviews manifest & changes     │
         └─────────────────────────────────┘
                     ↓
         ┌─────────────────────────────────┐
         │  Deploy to Beta/Production      │
         │  Pull images: signed-2025-q1    │
         └─────────────────────────────────┘

Evidence Chain: 
Deployment State → Discovery → Git Tag → Docker Tags 
→ Manifest → Ledger → Pipeline → Approval → Production

A.5Integration with Existing Controls #

Snapshot releases comply with the Triple-Guardrail controls:

Control How It's Satisfied
C1 · Independent Verification Mend.io scans already passed for all builds during dev pipeline. No new code is deployed, only existing verified images.
C2 · Agent Config Shield No .agent-config.json changes occur in snapshot releases (only tagging existing artifacts).
C3 · Signed Handshake Pipeline manual approval gate enforces the Four-Eyes Principle. Approver must be different identity than the requester who created the signed-* tag.

A.6Troubleshooting Common Issues #

Problem Solution
"Can't find commit hash on app" 1. Check UI footer
2. Query /health endpoint (if implemented)
3. Check environment variables on host
"Apps show different commit hashes" This is expected in a monorepo. Not every app rebuilds on every commit. Use the highest Docker tag to identify the latest commit across all apps.
"Which commit should I tag?" Tag the commit associated with the highest Docker tag number. This commit represents the latest state across all deployed apps.
"Docker tag command fails" Run az acr login --name duckbook to authenticate with Azure Container Registry.
"Which tag format should I use?" Use semantic (signed-v1.4.0) for technical version tracking, or date-based (signed-2025-q1) for business milestone releases.
"Pipeline doesn't trigger" Verify the tag uses the signed-* prefix. Check Azure Pipeline trigger configuration.

A.7Example: Complete Release Flow #

Here's a complete example of creating a quarterly release:

# ────────────────────────────────────────────────────
# STEP 1: Discover current deployment
# ────────────────────────────────────────────────────
$ node scripts/release-tagger.js --discover

Querying apps...
✓ app1: commit 43jdfd342, docker tag 33
✓ app2: commit 3289h3292, docker tag 44  ← HIGHEST
✓ app3: commit v04343432, docker tag 22

Latest commit identified: 3289h3292 (docker tag 44)

# ────────────────────────────────────────────────────
# STEP 2: Verify commit in git
# ────────────────────────────────────────────────────
$ git log --oneline | grep 3289h3292
3289h3292 feat: add streaming data feed bet:market-data

$ git branch --contains 3289h3292
* main

# ────────────────────────────────────────────────────
# STEP 3: Create Git tag
# ────────────────────────────────────────────────────
$ git tag -a signed-2025-q1 3289h3292 -m "Q1 2025 Release | Apps: 22,33,44"
$ git push origin signed-2025-q1

# ────────────────────────────────────────────────────
# STEP 4: Tag Docker images (automated)
# ────────────────────────────────────────────────────
$ node scripts/release-tagger.js --tag signed-2025-q1 --auto

Connecting to duckbook.azurecr.io...
✓ Tagged duckbook.azurecr.io/app1:33 → signed-2025-q1
✓ Tagged duckbook.azurecr.io/app2:44 → signed-2025-q1
✓ Tagged duckbook.azurecr.io/app3:22 → signed-2025-q1

Release manifest saved to: /releases/signed-2025-q1.json
✓ Appended entry to /governance/ledger.md

# ────────────────────────────────────────────────────
# STEP 5: Trigger Release Pipeline & Verify
# ────────────────────────────────────────────────────
# Navigate to Azure DevOps → Pipelines → "Release Pipeline"
# [Manual Approval Gate] → Approver reviews and approves
# After approval → Deploy to Beta/Production

A.8Quick Reference Card #

# ═══════════════════════════════════════════════════
# DISCOVERY
# ═══════════════════════════════════════════════════

# Find what's deployed
node scripts/release-tagger.js --discover

# Check health endpoint (if implemented)
curl https://app1.company.com/health

# ═══════════════════════════════════════════════════
# GIT TAGGING
# ═══════════════════════════════════════════════════

# Tag the commit with highest Docker tag
git tag -a signed-<NAME> <COMMIT_HASH> -m "<DESCRIPTION>"
git push origin signed-<NAME>

# Examples:
git tag -a signed-v1.4.0 abc123 -m "Release v1.4.0"
git tag -a signed-2025-q1 abc123 -m "Q1 2025 Release"

# ═══════════════════════════════════════════════════
# DOCKER TAGGING
# ═══════════════════════════════════════════════════

# Automated (recommended)
node scripts/release-tagger.js --tag signed-<NAME> --auto

# Manual
az acr login --name duckbook
docker tag duckbook.azurecr.io/<app>:<BUILD> duckbook.azurecr.io/<app>:signed-<NAME>
docker push duckbook.azurecr.io/<app>:signed-<NAME>

# ═══════════════════════════════════════════════════
# VERIFICATION
# ═══════════════════════════════════════════════════

# List signed tags
git tag -l "signed-*" | sort -V

# View changes in release
git log <PREV_SIGNED>..<NEW_SIGNED> --oneline

# Check manifest
cat /releases/signed-<NAME>.json

# Check ledger
tail /governance/ledger.md