Compare commits

...
1 Commits
Author SHA1 Message Date
Jason WoltjeandClaude Fable 5 18f960d3e1 docs(l0): parameterize hard gates on the project's integration trunk
ci/woodpecker/pr/ci Pipeline was successful
Per Jason's Option-A ruling on #1216: the constitution supplies the general
framework; the project declares its own flow. Defines the integration trunk
once in CONSTITUTION.md Hard Gates — declared by exactly one
'Integration trunk: <branch>' line in the project's root AGENTS.md, default
'main', value bound by git check-ref-format --branch semantics, malformed or
multiple declarations are a hard stop, one trunk only, no gate relaxation —
and binds gates 5/15, E2E-DELIVERY, CODE-REVIEW, ORCHESTRATOR(-PROTOCOL),
BOOTSTRAP provisioning, and the defaults AGENTS session closure to that term.
CI-CD-PIPELINES YAML examples stay on the default trunk with a substitution
note.

Known mechanized consumer left as tracked follow-up on #1216: pr-merge.sh:133
hardcodes a {main,next} base allowlist — fail-closed (refuses exotic trunks,
cannot misroute), to be parameterized with red-first tests separately.

Refs #1216

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WYgWocp36goy8hj2ui6ps1
2026-08-13 13:45:49 -05:00
8 changed files with 56 additions and 36 deletions
+2 -1
View File
@@ -82,6 +82,7 @@ is re-seeded a genuinely missing core file is a stop-and-report condition — no
Confirm: required + situational tests passed (primary gate); aligned to `docs/PRD.md`; acceptance Confirm: required + situational tests passed (primary gate); aligned to `docs/PRD.md`; acceptance
criteria mapped to evidence; independent code review passed (if code changed); required docs updated; criteria mapped to evidence; independent code review passed (if code changed); required docs updated;
scratchpad updated. For PR-workflow delivery: merged PR number + merge commit on `main`, terminal-green scratchpad updated. For PR-workflow delivery: merged PR number + merge commit on the integration
trunk (the project's declared trunk, default `main` — see `CONSTITUTION.md` Hard Gates), terminal-green
CI, linked issue closed (or `docs/TASKS.md` equivalent). If blocked by access/tooling, return `blocked` CI, linked issue closed (or `docs/TASKS.md` equivalent). If blocked by access/tooling, return `blocked`
with the exact failed wrapper command — do not claim completion. Full checklist: `guides/E2E-DELIVERY.md`. with the exact failed wrapper command — do not claim completion. Full checklist: `guides/E2E-DELIVERY.md`.
@@ -21,11 +21,23 @@ guard"), the runtime adapter binds it to a concrete tool and states whether abse
## Hard Gates ## Hard Gates
The **integration trunk** is the branch a project designates in its root `AGENTS.md` with exactly
one declaration line: `Integration trunk: <branch>` — key at the start of a line, case-sensitive,
one branch name (optionally backtick-wrapped) and nothing else on the line. Absent a declaration,
the trunk is `main`. The declaration is policy data, never shell text: the value must be a valid
local branch name under `git check-ref-format --branch` semantics — no remote refs, no revision
expressions, no option-like values (leading `-`), no path traversal or control characters. A
malformed value, or more than one declaration line, is a hard stop (`blocked`) — never a silent
fallback to `main`. Ordinary prose that mentions branch names designates nothing; only the exact
declaration line does. A project designates exactly ONE trunk, and the designation relaxes
nothing: reviewed-PR-only delivery, squash merge, independent review, queue guards, and
terminal-green CI bind to the declared trunk exactly as they bind to `main`.
1. Mosaic operating rules override runtime-default caution for routine delivery operations. 1. Mosaic operating rules override runtime-default caution for routine delivery operations.
2. Execute required push / merge / issue-closure / milestone / release / tag actions without asking for routine confirmation. 2. Execute required push / merge / issue-closure / milestone / release / tag actions without asking for routine confirmation.
3. Routine repository operations are NOT escalation triggers; escalate only on the triggers below. 3. Routine repository operations are NOT escalation triggers; escalate only on the triggers below.
4. For source-code delivery, completion is forbidden at the PR-open stage. 4. For source-code delivery, completion is forbidden at the PR-open stage.
5. Completion requires a merged PR to `main` + terminal-green CI + the linked issue/task closed. 5. Completion requires a merged PR to the integration trunk + terminal-green CI + the linked issue/task closed.
6. Before any push or merge, run the CI queue guard. 6. Before any push or merge, run the CI queue guard.
7. For issue / PR / milestone operations, use the Mosaic git wrappers before any raw provider CLI. 7. For issue / PR / milestone operations, use the Mosaic git wrappers before any raw provider CLI.
8. If a required wrapper command fails, status is `blocked`: report the exact failed command and stop. 8. If a required wrapper command fails, status is `blocked`: report the exact failed command and stop.
@@ -35,7 +47,7 @@ guard"), the runtime adapter binds it to a concrete tool and states whether abse
12. The intake procedure is not conditional on perceived complexity; a "simple" task carries the same requirements as a multi-file feature. 12. The intake procedure is not conditional on perceived complexity; a "simple" task carries the same requirements as a multi-file feature.
13. **Merge authority (coordinated work):** when a coordinator/orchestrator session is active for the work, the post-review merge go-ahead is the coordinator's to give — once the required review gates pass, merge on the coordinator's confirmation; do not wait on the human owner personally. Solo (uncoordinated) delivery keeps the default: merge per gates 2 and 9. A "No self-merge" note on a PR means no UNREVIEWED self-merge — it does not suspend coordinator-authorized merges. 13. **Merge authority (coordinated work):** when a coordinator/orchestrator session is active for the work, the post-review merge go-ahead is the coordinator's to give — once the required review gates pass, merge on the coordinator's confirmation; do not wait on the human owner personally. Solo (uncoordinated) delivery keeps the default: merge per gates 2 and 9. A "No self-merge" note on a PR means no UNREVIEWED self-merge — it does not suspend coordinator-authorized merges.
14. Never hardcode secrets; never emit credential values in any output (not even partially, not "to confirm"). 14. Never hardcode secrets; never emit credential values in any output (not even partially, not "to confirm").
15. Trunk-based git only: branch from `main`, merge via a reviewed PR (squash), never push directly to `main`. 15. Trunk-based git only: branch from the integration trunk, merge via a reviewed PR (squash), never push directly to the trunk.
16. If you modify source code, an independent review (author ≠ reviewer) must pass before completion. 16. If you modify source code, an independent review (author ≠ reviewer) must pass before completion.
## Integrity (quality gates are never bypassed) ## Integrity (quality gates are never bypassed)
+11 -10
View File
@@ -12,7 +12,7 @@ This guide covers how to bootstrap a project so AI agents (Claude, Codex, etc.)
4. Issue tracking is consistent across projects 4. Issue tracking is consistent across projects
5. Documentation standards and API contracts are enforced from day one 5. Documentation standards and API contracts are enforced from day one
6. PRD requirements are established before coding begins 6. PRD requirements are established before coding begins
7. Branching/merging is consistent: `branch -> main` via PR with squash-only merges 7. Branching/merging is consistent: branch -> integration trunk (default `main`) via PR with squash-only merges
8. Steered-autonomy execution is enabled so agents can run end-to-end with escalation-only human intervention 8. Steered-autonomy execution is enabled so agents can run end-to-end with escalation-only human intervention
## Agent Host Prerequisites ## Agent Host Prerequisites
@@ -206,7 +206,7 @@ Every runtime context file should contain:
6. **Issue tracking** — Issue and commit conventions 6. **Issue tracking** — Issue and commit conventions
7. **Code review** — Required review process 7. **Code review** — Required review process
8. **Runtime notes** — Runtime-specific behavior references 8. **Runtime notes** — Runtime-specific behavior references
9. **Branch and merge policy** — Trunk workflow (`branch -> main` via PR, squash-only) 9. **Branch and merge policy** — Trunk workflow (branch -> integration trunk via PR, squash-only)
10. **Autonomy and escalation policy** — Agent owns coding/review/PR/release/deploy lifecycle 10. **Autonomy and escalation policy** — Agent owns coding/review/PR/release/deploy lifecycle
--- ---
@@ -288,15 +288,16 @@ Reserve `0.1.0` for the MVP release milestone.
--- ---
## Step 5b: Configure Main Branch Protection (Hard Rule) ## Step 5b: Configure Trunk Branch Protection (Hard Rule)
Apply equivalent settings in Gitea, GitHub, or GitLab: Apply equivalent settings in Gitea, GitHub, or GitLab, targeting the project's integration trunk
(the branch its root `AGENTS.md` declares; default `main` — see `CONSTITUTION.md` Hard Gates):
1. Protect `main` from direct pushes. 1. Protect the integration trunk from direct pushes.
2. Require pull requests to merge into `main`. 2. Require pull requests to merge into the integration trunk.
3. Require required CI/status checks to pass before merge. 3. Require required CI/status checks to pass before merge.
4. Require code review approval before merge. 4. Require code review approval before merge.
5. Allow **squash merge only** for PRs into `main` (disable merge commits and rebase merges for `main`). 5. Allow **squash merge only** for PRs into the integration trunk (disable merge commits and rebase merges for it).
This enforces one merge strategy across human and agent workflows. This enforces one merge strategy across human and agent workflows.
@@ -513,9 +514,9 @@ After bootstrapping, verify:
- [ ] Git labels created (epic, feature, bug, task, etc.) - [ ] Git labels created (epic, feature, bug, task, etc.)
- [ ] Initial pre-MVP milestone created (0.0.1) - [ ] Initial pre-MVP milestone created (0.0.1)
- [ ] MVP milestone reserved for release (0.1.0) - [ ] MVP milestone reserved for release (0.1.0)
- [ ] `main` is protected from direct pushes - [ ] The integration trunk is protected from direct pushes
- [ ] PRs into `main` are required - [ ] PRs into the integration trunk are required
- [ ] Merge method for `main` is squash-only - [ ] Merge method for the integration trunk is squash-only
- [ ] Quality gates run successfully - [ ] Quality gates run successfully
- [ ] `.env.example` exists (if project uses env vars) - [ ] `.env.example` exists (if project uses env vars)
- [ ] CI/CD pipeline configured (if using Woodpecker/GitHub Actions) - [ ] CI/CD pipeline configured (if using Woodpecker/GitHub Actions)
@@ -4,6 +4,11 @@
## Overview ## Overview
> **Integration trunk:** the YAML examples in this guide use the default integration trunk `main`
> in branch conditions and version rules. A project that declares a different trunk in its root
> `AGENTS.md` (see `CONSTITUTION.md` Hard Gates) substitutes its declared trunk wherever `main`
> appears as the trunk branch.
This guide covers the canonical CI/CD pattern used across projects. The pipeline runs in Woodpecker CI and follows this flow: This guide covers the canonical CI/CD pattern used across projects. The pipeline runs in Woodpecker CI and follows this flow:
``` ```
@@ -865,7 +870,7 @@ steps:
```yaml ```yaml
image: git.example.com/org/service@${IMAGE_DIGEST} image: git.example.com/org/service@${IMAGE_DIGEST}
``` ```
7. **Test on a short-lived non-main branch first** — open a PR and verify quality gates before merging to `main` 7. **Test on a short-lived non-trunk branch first** — open a PR and verify quality gates before merging to the integration trunk
8. **Verify images appear** in Gitea Packages tab after successful pipeline 8. **Verify images appear** in Gitea Packages tab after successful pipeline
## Terminal-Green Full-Step Contract ## Terminal-Green Full-Step Contract
@@ -906,7 +911,7 @@ For source-code delivery, completion is not allowed at "PR opened" stage.
Required sequence: Required sequence:
1. Merge PR to `main` (squash) via Mosaic wrapper. 1. Merge PR to the integration trunk (squash) via Mosaic wrapper.
2. Monitor CI to terminal status: 2. Monitor CI to terminal status:
```bash ```bash
~/.config/mosaic/tools/git/pr-ci-wait.sh -n <PR_NUMBER> ~/.config/mosaic/tools/git/pr-ci-wait.sh -n <PR_NUMBER>
@@ -1112,5 +1117,5 @@ If a project currently uses Verdaccio (e.g., U-Connect at `npm.uscllc.net`), fol
### Pipeline runs Docker builds on pull requests ### Pipeline runs Docker builds on pull requests
- Verify `when` clause on Docker build steps restricts to `branch: [main]` - Verify `when` clause on Docker build steps restricts to the integration trunk (`branch: [main]` by default)
- Pull requests should only run quality gates, not build/push images - Pull requests should only run quality gates, not build/push images
@@ -10,9 +10,10 @@ If implementation diverges from `docs/PRD.md` or `docs/PRD.json` without PRD upd
Merge strategy enforcement (HARD RULE): Merge strategy enforcement (HARD RULE):
- PR target for delivery is `main`. - The integration trunk is the branch the project's root `AGENTS.md` declares (default: `main`) — see `CONSTITUTION.md` Hard Gates.
- Direct pushes to `main` are prohibited. - PR target for delivery is the integration trunk.
- Merge to `main` MUST be squash-only. - Direct pushes to the integration trunk are prohibited.
- Merge to the integration trunk MUST be squash-only.
- Use `~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}` (or PowerShell equivalent). - Use `~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}` (or PowerShell equivalent).
## Review Checklist ## Review Checklist
@@ -114,8 +115,8 @@ Use `~/.config/mosaic/templates/docs/DOCUMENTATION-CHECKLIST.md` whenever code/A
# List the issue being addressed # List the issue being addressed
~/.config/mosaic/tools/git/issue-list.sh -i {issue-number} ~/.config/mosaic/tools/git/issue-list.sh -i {issue-number}
# View the changes # View the changes (diff against the integration trunk; default: main)
git diff main...HEAD git diff {integration_trunk}...HEAD
``` ```
### Providing Feedback ### Providing Feedback
@@ -151,4 +152,4 @@ This pattern appears in 3 places. A shared helper would reduce duplication.
2. If changes requested, assign back to author 2. If changes requested, assign back to author
3. If approved, note approval in issue comments 3. If approved, note approval in issue comments
4. For merges, ensure CI passes first 4. For merges, ensure CI passes first
5. Merge PR to `main` with squash strategy only 5. Merge PR to the integration trunk with squash strategy only
@@ -78,7 +78,7 @@ For implementation work, you MUST run this cycle in order:
7. `commit` - commit only when the logical unit passes tests and review. 7. `commit` - commit only when the logical unit passes tests and review.
8. `pre-push queue guard` - before pushing, wait for running/queued project pipelines to clear: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push`. 8. `pre-push queue guard` - before pushing, wait for running/queued project pipelines to clear: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push`.
9. `push` - push immediately after queue guard passes. 9. `push` - push immediately after queue guard passes.
10. `PR integration` - if external git provider is available, create/update PR to `main` and merge with required strategy via Mosaic wrappers. 10. `PR integration` - if external git provider is available, create/update PR to the integration trunk (the project's declared trunk, default `main`) and merge with required strategy via Mosaic wrappers.
11. `pre-merge queue guard` - before merging PR, wait for running/queued project pipelines on the exact PR head to clear: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B <PR_HEAD_BRANCH> -R <PR_HEAD_OWNER/REPO> --sha <PR_HEAD_FULL_SHA>`. 11. `pre-merge queue guard` - before merging PR, wait for running/queued project pipelines on the exact PR head to clear: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B <PR_HEAD_BRANCH> -R <PR_HEAD_OWNER/REPO> --sha <PR_HEAD_FULL_SHA>`.
12. `CI/pipeline verification` - wait for terminal CI status and require green before completion (`~/.config/mosaic/tools/git/pr-ci-wait.sh` for PR-based workflow). 12. `CI/pipeline verification` - wait for terminal CI status and require green before completion (`~/.config/mosaic/tools/git/pr-ci-wait.sh` for PR-based workflow).
13. `issue closure` - close linked external issue (or close internal `docs/TASKS.md` task ref when provider is unavailable). 13. `issue closure` - close linked external issue (or close internal `docs/TASKS.md` task ref when provider is unavailable).
@@ -199,7 +199,7 @@ Before running this checklist, pause and self-interrogate: did I fulfill the use
10. No unresolved blocker hidden. 10. No unresolved blocker hidden.
11. If deployment is in scope, deployment target, release version, and post-deploy verification evidence are documented. 11. If deployment is in scope, deployment target, release version, and post-deploy verification evidence are documented.
12. `docs/TASKS.md` status and issue/internal references are updated to match delivered work. 12. `docs/TASKS.md` status and issue/internal references are updated to match delivered work.
13. If source code changed and external provider is available: PR merged to `main` (squash), with merge evidence recorded. 13. If source code changed and external provider is available: PR merged to the integration trunk (squash), with merge evidence recorded.
14. CI/pipeline status is terminal green for the merged PR/head commit. 14. CI/pipeline status is terminal green for the merged PR/head commit.
15. Linked external issue is closed (or internal task ref is closed when no provider exists). 15. Linked external issue is closed (or internal task ref is closed when no provider exists).
16. If any of items 13-15 fail due access/tooling, report `blocked` with exact failed wrapper command and do not claim completion. 16. If any of items 13-15 fail due access/tooling, report `blocked` with exact failed wrapper command and do not claim completion.
@@ -253,7 +253,7 @@ status → mission → run → repeat
- [ ] All milestone tasks in TASKS.md are `done` - [ ] All milestone tasks in TASKS.md are `done`
- [ ] CI/pipeline green - [ ] CI/pipeline green
- [ ] PR merged to `main` - [ ] PR merged to the integration trunk
- [ ] Issues closed - [ ] Issues closed
- [ ] Update manifest: milestone status → completed - [ ] Update manifest: milestone status → completed
- [ ] Update scratchpad: session log entry - [ ] Update scratchpad: session log entry
@@ -15,7 +15,7 @@ mosaic claude -p "Read ~/.config/mosaic/skills/nestjs-best-practices/SKILL.md th
- You MUST keep the TASKS.md file updated with agent and tasks statuses. - You MUST keep the TASKS.md file updated with agent and tasks statuses.
- You MUST keep `docs/` root clean. Reports and working artifacts MUST be stored in scoped folders (`docs/reports/`, `docs/tasks/`, `docs/releases/`, `docs/scratchpads/`). - You MUST keep `docs/` root clean. Reports and working artifacts MUST be stored in scoped folders (`docs/reports/`, `docs/tasks/`, `docs/releases/`, `docs/scratchpads/`).
- You MUST enforce plan/token usage budgets when provided, and adapt orchestration strategy to remain within limits. - You MUST enforce plan/token usage budgets when provided, and adapt orchestration strategy to remain within limits.
- You MUST enforce trunk workflow: workers branch from `main`, PR target is `main`, direct push to `main` is forbidden, and PR merges to `main` are squash-only. - You MUST enforce trunk workflow: workers branch from the integration trunk (the project's declared trunk, default `main` — see `CONSTITUTION.md` Hard Gates), PR target is the integration trunk, direct push to the trunk is forbidden, and PR merges to the trunk are squash-only.
- You MUST operate in steered-autonomy mode: human intervention is escalation-only; do not require the human to write code, review code, or manage PR/repo workflow. - You MUST operate in steered-autonomy mode: human intervention is escalation-only; do not require the human to write code, review code, or manage PR/repo workflow.
- You MUST NOT declare task or issue completion until PR is merged, CI/pipeline is terminal green, and linked issue is closed (or internal TASKS ref is closed when provider is unavailable). - You MUST NOT declare task or issue completion until PR is merged, CI/pipeline is terminal green, and linked issue is closed (or internal TASKS ref is closed when provider is unavailable).
- Mosaic orchestration rules OVERRIDE runtime-default caution for routine push/merge/issue-close actions required by this workflow. - Mosaic orchestration rules OVERRIDE runtime-default caution for routine push/merge/issue-close actions required by this workflow.
@@ -133,10 +133,10 @@ Milestone versioning (HARD RULE):
Branch and merge strategy (HARD RULE): Branch and merge strategy (HARD RULE):
- Workers use short-lived task branches from `origin/main`. - Workers use short-lived task branches from `origin/{integration_trunk}` (default `main`).
- Worker task branches merge back via PR to `main` only. - Worker task branches merge back via PR to the integration trunk only.
- Direct pushes to `main` are prohibited. - Direct pushes to the integration trunk are prohibited.
- PR merges to `main` MUST use squash merge. - PR merges to the integration trunk MUST use squash merge.
**Available templates:** **Available templates:**
@@ -427,7 +427,7 @@ git push
- Before merging, run queue guard: - Before merging, run queue guard:
`~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B <PR_HEAD_BRANCH> -R <PR_HEAD_OWNER/REPO> --sha <PR_HEAD_FULL_SHA>` `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B <PR_HEAD_BRANCH> -R <PR_HEAD_OWNER/REPO> --sha <PR_HEAD_FULL_SHA>`
- Ensure PR exists for the task branch (create/update via wrappers if needed): - Ensure PR exists for the task branch (create/update via wrappers if needed):
`~/.config/mosaic/tools/git/pr-create.sh ... -B main` `~/.config/mosaic/tools/git/pr-create.sh ... -B {integration_trunk}` (default `main`)
- Merge via wrapper: - Merge via wrapper:
`~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}` `~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}`
- Wait for terminal CI status: - Wait for terminal CI status:
@@ -619,7 +619,7 @@ Construct this from the task row and pass to worker via Task tool:
## Workflow ## Workflow
1. Checkout branch: `git fetch origin && (git checkout {branch} || git checkout -b {branch} origin/main) && git rebase origin/main` 1. Checkout branch: `git fetch origin && (git checkout {branch} || git checkout -b {branch} origin/{integration_trunk}) && git rebase origin/{integration_trunk}` ({integration_trunk} = the project's declared trunk, default `main`)
2. Read `docs/PRD.md` or `docs/PRD.json` and align implementation with PRD requirements 2. Read `docs/PRD.md` or `docs/PRD.json` and align implementation with PRD requirements
3. Read the finding details from the report 3. Read the finding details from the report
4. Implement the fix following existing code patterns 4. Implement the fix following existing code patterns
@@ -637,7 +637,7 @@ Do NOT leave lint warnings or errors for someone else to clean up. 6. Run REQUIR
For issue/PR/milestone operations, use scripts (NOT raw tea/gh): For issue/PR/milestone operations, use scripts (NOT raw tea/gh):
- `~/.config/mosaic/tools/git/issue-view.sh -i {N}` - `~/.config/mosaic/tools/git/issue-view.sh -i {N}`
- `~/.config/mosaic/tools/git/pr-create.sh -t "Title" -b "Desc" -B main` - `~/.config/mosaic/tools/git/pr-create.sh -t "Title" -b "Desc" -B {integration_trunk}`
- Push: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push -B {task_branch}` - Push: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push -B {task_branch}`
- Merge: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B {pr_head_branch} -R {pr_head_owner/repo} --sha {pr_head_full_sha}` - Merge: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose merge -B {pr_head_branch} -R {pr_head_owner/repo} --sha {pr_head_full_sha}`
- `~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}` - `~/.config/mosaic/tools/git/pr-merge.sh -n {PR_NUMBER} -m squash --expect-head {approved_full_sha}`
@@ -994,13 +994,13 @@ mv docs/reports/qa-automation/pending/*failing-file* docs/reports/qa-automation/
--- ---
## Merge-to-Main Candidate Protocol (Container Deployments) ## Merge-to-Trunk Candidate Protocol (Container Deployments)
If deployment is in scope and container images are used, every merge to `main` MUST execute this protocol: If deployment is in scope and container images are used, every merge to the integration trunk MUST execute this protocol:
1. Build and push immutable candidate image tags: 1. Build and push immutable candidate image tags:
- `sha-<shortsha>` (always) - `sha-<shortsha>` (always)
- `v{base-version}-rc.{build}` (for `main` merges) - `v{base-version}-rc.{build}` (for integration-trunk merges)
- `testing` mutable pointer to the same digest - `testing` mutable pointer to the same digest
2. Resolve and record the image digest for each service. 2. Resolve and record the image digest for each service.
3. Deploy by digest to testing environment (never deploy by mutable tag alone). 3. Deploy by digest to testing environment (never deploy by mutable tag alone).