refactor(skills): mirror groombook sdlc structure, split devops skill
- sdlc: trim to application-repo scope with Phase 1-5 pipeline; engineer self-merges all branches with per-branch prerequisites; move infra, Flux, tofu, and operator-install content out - devops: new skill mirroring groombook/org/skills/devops — owns cartsnitch/infra, Flux GitOps, OpenTofu controller, cluster topology, Flux Image Tag Automation denied policy - safety: add Gitea-origin board-approval gate, board-approval scope section, and adapterConfig.env read-before-write rule - coding-standards: replace "no agent merges their own PR" with the reviews-required-then-engineer-may-merge rule consistent with sdlc - CLAUDE.md: update skill index, branch & merge policy, and SDLC phase summary to reflect engineer-self-merge and the new devops skill Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,8 +5,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
## Repository Purpose
|
## Repository Purpose
|
||||||
|
|
||||||
This is the **CartSnitch org-level governance repository** — it contains operational policies and skill definitions for AI agents that develop and maintain the CartSnitch e-commerce platform. It is **not an application codebase**; there is nothing to build or test here. All policy lives in `skills/`:
|
This is the **CartSnitch org-level governance repository** — it contains operational policies and skill definitions for AI agents that develop and maintain the CartSnitch e-commerce platform. It is **not an application codebase**; there is nothing to build or test here. All policy lives in `skills/`:
|
||||||
- `skills/sdlc/` — Software development lifecycle, branch strategy, deployment via Flux GitOps, infrastructure layout
|
- `skills/sdlc/` — Application code lifecycle: branch strategy, SDLC phases 1-5, Stage 1 CI image build, auth framework, application-tool policy, delegation tier
|
||||||
- `skills/safety/` — Non-negotiable rules: secret handling, SealedSecrets workflow, kubectl scope limits, destructive-action gating
|
- `skills/devops/` — Infrastructure lifecycle on `cartsnitch/infra`: Flux GitOps reconciliation, OpenTofu controller, cluster topology, operator install
|
||||||
|
- `skills/safety/` — Non-negotiable rules: secret handling, SealedSecrets workflow, kubectl scope limits, destructive-action gating, Gitea-origin board-approval gate
|
||||||
- `skills/coding-standards/` — Engineering quality bar, priority ordering, test requirements, task decomposition template
|
- `skills/coding-standards/` — Engineering quality bar, priority ordering, test requirements, task decomposition template
|
||||||
|
|
||||||
## Safety (Non-Negotiable)
|
## Safety (Non-Negotiable)
|
||||||
@@ -60,8 +61,11 @@ If a task has `originKind: "gitea"`, do not begin work — create a board approv
|
|||||||
|
|
||||||
## Branch & Merge Policy
|
## Branch & Merge Policy
|
||||||
|
|
||||||
- Engineers target `dev` only — never `uat` or `main` directly
|
- Engineers target `dev` first — never `uat` or `main` directly
|
||||||
- No self-merge: CTO merges `dev` and `uat` PRs; CEO merges `main` PR
|
- Engineer merges all three branches; prerequisites differ:
|
||||||
|
- `dev`: CI passes
|
||||||
|
- `uat`: QA (Checkout Charlie) code review approval
|
||||||
|
- `main`: UAT validation (Deal Dottie), security review (Stockboy Steve), CEO (Coupon Carl) code review approval
|
||||||
- All PRs include `cc @cpfarhood` at the bottom (visibility, not review)
|
- All PRs include `cc @cpfarhood` at the bottom (visibility, not review)
|
||||||
- Flux Image Tag Automation is **denied** — image updates must be intentional PRs to `cartsnitch/infra`
|
- Flux Image Tag Automation is **denied** — image updates must be intentional PRs to `cartsnitch/infra`
|
||||||
|
|
||||||
@@ -99,11 +103,13 @@ Hold a high bar. PRs with obvious mistakes, missing tests, hardcoded values, or
|
|||||||
|
|
||||||
## SDLC Phase Summary
|
## SDLC Phase Summary
|
||||||
|
|
||||||
1. **Dev** — Engineer → PR → QA (Checkout Charlie `9b6012d0-0406-417e-bb22-78266a6e7f77`) → CTO (Savannah Savings `6ec1a5a9-113c-430b-90e6-260d60d79e1d`) → CTO merges
|
1. **Phase 1 — Dev**: Engineer → PR vs `dev` → CI pass → Engineer self-merges → auto-deploy to Dev (`dev.cartsnitch.com`)
|
||||||
2. **UAT** — CTO opens `dev→uat` PR → deploys → Deal Dottie (`161fb3bb-0332-4381-b67d-7c4b92a91133`) regression → Stockboy Steve (`d59d4b24-3cc3-4616-a23a-2b4776a489ca`) security review
|
2. **Phase 2 — UAT promotion**: Engineer opens `dev→uat` PR → CI pass → QA (Checkout Charlie `9b6012d0-0406-417e-bb22-78266a6e7f77`) code review → Engineer merges → auto-deploy to UAT (`uat.cartsnitch.com`)
|
||||||
3. **Production** — CEO (Coupon Carl `cd91facf-8f4c-4cbd-b8d8-b48da5b50727`) reviews and merges `uat→main` → auto-deploy via Flux
|
3. **Phase 3 — UAT testing & security**: Deal Dottie (`161fb3bb-0332-4381-b67d-7c4b92a91133`) full regression → Stockboy Steve (`d59d4b24-3cc3-4616-a23a-2b4776a489ca`) security code review
|
||||||
|
4. **Phase 4 — Production promotion**: Engineer opens `uat→main` PR → CI pass → CEO (Coupon Carl `cd91facf-8f4c-4cbd-b8d8-b48da5b50727`) code review → Engineer merges → CI builds & tags image
|
||||||
|
5. **Phase 5 — Production deployment**: Engineer opens PR against `cartsnitch/infra` updating the overlay image tag → from here the `devops` skill owns review, merge, and Flux reconciliation to `cartsnitch.com`
|
||||||
|
|
||||||
If any phase fails, work returns to the engineer (CTO cascades).
|
If any phase fails, work returns to the engineer. CTO (Savannah Savings `6ec1a5a9-113c-430b-90e6-260d60d79e1d`) is the escalation target for re-distribution and disputes.
|
||||||
|
|
||||||
## Agent Roster
|
## Agent Roster
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ When making technical decisions, prioritize in this order:
|
|||||||
## Pull request discipline
|
## Pull request discipline
|
||||||
|
|
||||||
* All changes go through a PR. **Never push directly to `dev`, `uat`, or `main`.**
|
* All changes go through a PR. **Never push directly to `dev`, `uat`, or `main`.**
|
||||||
* No agent merges their own PR.
|
* Never merge a PR without the reviews required by the `sdlc` (or `devops`) skill for that branch. The engineer who opened the PR may click merge once those prerequisites are satisfied.
|
||||||
* Always include `cc @cpfarhood` at the bottom of the PR body for visibility (never as a reviewer).
|
* Always include `cc @cpfarhood` at the bottom of the PR body for visibility (never as a reviewer).
|
||||||
* Engineers always target `dev` — never `uat` or `main` directly.
|
* Engineers always target `dev` — never `uat` or `main` directly.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
name: devops
|
||||||
|
description: >
|
||||||
|
Infrastructure lifecycle for CartSnitch. Governs work on the
|
||||||
|
cartsnitch/infra repo: single-branch main strategy, the infra PR review
|
||||||
|
pipeline, Flux GitOps reconciliation, OpenTofu controller workflow,
|
||||||
|
cluster topology, and the Flux image-automation policy. For application
|
||||||
|
code, see the sdlc skill.
|
||||||
|
---
|
||||||
|
|
||||||
|
# DevOps Practices
|
||||||
|
|
||||||
|
This skill governs work on **`cartsnitch/infra`**. For application code lifecycle, see the `sdlc` skill. For PR/test discipline and the `cc @cpfarhood` visibility rule, see `coding-standards`. For non-negotiable safety rules (no direct `tofu`, no `kubectl apply` to production, SealedSecrets), see `safety`.
|
||||||
|
|
||||||
|
## Gitea authentication
|
||||||
|
|
||||||
|
Use the `GITEA_TOKEN` environment variable for all Gitea operations — it is already set in the agent environment. Use the **`tea`** CLI for all Gitea/Git operations (e.g., `tea issue list`, `tea pr create`). Gitea is the primary source of truth.
|
||||||
|
|
||||||
|
## Branch strategy
|
||||||
|
|
||||||
|
`cartsnitch/infra` uses a single long-lived branch: **`main`**. Engineers target `main` directly via feature branches named `<agent-name>/<short-description>`.
|
||||||
|
|
||||||
|
## Pipeline
|
||||||
|
|
||||||
|
1. **Engineer** branches from `main`, writes code.
|
||||||
|
2. **Engineer** opens a PR against `main`.
|
||||||
|
3. **CI** fail → back to **Engineer**.
|
||||||
|
4. **CI** pass → **QA (Checkout Charlie `9b6012d0-0406-417e-bb22-78266a6e7f77`)** performs code review.
|
||||||
|
5. **QA** rejected → back to **Engineer**.
|
||||||
|
6. **QA** approved → **CTO (Savannah Savings `6ec1a5a9-113c-430b-90e6-260d60d79e1d`)** performs code review.
|
||||||
|
7. **CTO** rejected → back to **Engineer**.
|
||||||
|
8. **CTO** approved → **Engineer** merges PR → **Flux** reconciles automatically.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tea pr create --base main --title "..." --body "... cc @cpfarhood"
|
||||||
|
```
|
||||||
|
|
||||||
|
Gitea branch protection requires CI checks to pass. See `coding-standards` for the no-self-merge contract and the `cc @cpfarhood` rule.
|
||||||
|
|
||||||
|
## Infrastructure topology
|
||||||
|
|
||||||
|
* **Production:** namespace `cartsnitch`, FQDN `cartsnitch.com`
|
||||||
|
* **UAT:** namespace `cartsnitch-uat`, FQDN `uat.cartsnitch.com`
|
||||||
|
* **Dev:** namespace `cartsnitch-dev`, FQDN `dev.cartsnitch.com`
|
||||||
|
* **Cluster:** Kubernetes — cluster-wide read; read/write on `cartsnitch-dev` and `cartsnitch-uat`; read-only on `cartsnitch` (production).
|
||||||
|
* **Gateways:** `istio-external` (public) and `istio-internal` (internal) in `gateway-system`.
|
||||||
|
* **Container registry:** `git.farh.net/cartsnitch/<service>` only.
|
||||||
|
|
||||||
|
## GitOps (Flux)
|
||||||
|
|
||||||
|
Flux watches `cartsnitch/infra` as the **target** GitRepository — it is **not** a Flux bootstrap/cluster repo and must never be treated as one.
|
||||||
|
|
||||||
|
Reconciles Kustomize overlays:
|
||||||
|
- `apps/overlays/dev` → `cartsnitch-dev`
|
||||||
|
- `apps/overlays/uat` → `cartsnitch-uat`
|
||||||
|
- `apps/overlays/prod` → `cartsnitch`
|
||||||
|
|
||||||
|
Images currently use `:latest` with `imagePullPolicy: Always`; pin to a CalVer tag in the infra overlay when stabilizing a release.
|
||||||
|
|
||||||
|
**Policy — Flux Image Tag Automation is DENIED.** Do NOT use `ImageRepository`, `ImagePolicy`, or `ImageUpdateAutomation` Flux resources. Image tag updates must be made intentionally via a PR to `cartsnitch/infra` — typically as the final step of the `sdlc` application pipeline (Phase 5).
|
||||||
|
|
||||||
|
**To force a rollout without a manifest change:**
|
||||||
|
```bash
|
||||||
|
kubectl rollout restart deployment/<name> -n <namespace>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Infrastructure as Code
|
||||||
|
|
||||||
|
Terraform (OpenTofu) is deployed via the **Flux OpenTofu Controller** in a GitOps fashion. Submit Terraform configurations via a PR to `cartsnitch/infra` — the tofu controller reconciles them on merge. See `safety` for the prohibition on running `tofu` directly and on `kubectl apply` against production.
|
||||||
|
|
||||||
|
## Infra-only tools
|
||||||
|
|
||||||
|
These are the operators and controllers the infra repo installs and manages. Alternatives are policy violations:
|
||||||
|
|
||||||
|
* **GitOps:** Flux CD (managed externally; reconciles `cartsnitch/infra`).
|
||||||
|
* **IaC:** Flux OpenTofu Controller.
|
||||||
|
* **Secret management:** Bitnami Sealed Secrets Controller — encrypt with `kubeseal`, commit `SealedSecret` resources to `cartsnitch/infra`. No plain Kubernetes secrets.
|
||||||
|
* **Database operator:** CloudNativePG (Postgres).
|
||||||
|
* **Cache / pub-sub operator:** DragonflyDB.
|
||||||
|
|
||||||
|
For application-level tool policy (Renovate, Playwright, registry, CalVer) see `coding-standards` and `sdlc`.
|
||||||
+63
-5
@@ -3,8 +3,8 @@ name: safety
|
|||||||
description: >
|
description: >
|
||||||
Non-negotiable safety rules for all CartSnitch agents. Covers secret
|
Non-negotiable safety rules for all CartSnitch agents. Covers secret
|
||||||
handling, destructive-action gating, the SealedSecrets workflow, kubectl
|
handling, destructive-action gating, the SealedSecrets workflow, kubectl
|
||||||
scope limits, and the escalation protocol when an action's safety is
|
scope limits, the Gitea-origin board-approval gate, and the escalation
|
||||||
uncertain.
|
protocol when an action's safety is uncertain.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Safety
|
# Safety
|
||||||
@@ -13,7 +13,7 @@ The following rules apply to every CartSnitch agent without exception.
|
|||||||
|
|
||||||
## Non-negotiable rules
|
## Non-negotiable rules
|
||||||
|
|
||||||
* **Never exfiltrate secrets or private data.** This includes API keys, tokens, PEM files, database credentials, kubeconfig contents, and any value sourced from a secret reference in your adapter config. Never log, comment, or return these values in any output — including PR descriptions, Paperclip / GitHub issue comments, discussions, and chat responses.
|
* **Never exfiltrate secrets or private data.** This includes API keys, tokens, PEM files, database credentials, kubeconfig contents, and any value sourced from a secret reference in your adapter config. Never log, comment, or return these values in any output — including PR descriptions, Paperclip / Gitea issue comments, discussions, and chat responses.
|
||||||
|
|
||||||
* **Seek board approval before destructive actions.** "Destructive" means: deleting resources, dropping tables, wiping namespaces, force-pushing branches, resetting git history, removing secrets, or any operation that cannot be undone without restoring from backup. Use `request_board_approval` and set the source issue to `blocked` until approved.
|
* **Seek board approval before destructive actions.** "Destructive" means: deleting resources, dropping tables, wiping namespaces, force-pushing branches, resetting git history, removing secrets, or any operation that cannot be undone without restoring from backup. Use `request_board_approval` and set the source issue to `blocked` until approved.
|
||||||
|
|
||||||
@@ -23,10 +23,68 @@ The following rules apply to every CartSnitch agent without exception.
|
|||||||
|
|
||||||
* **Never `kubectl create secret` in production.** All secrets — at every environment — go through SealedSecrets, encrypted with `kubeseal`, committed as `SealedSecret` resources to `cartsnitch/infra`.
|
* **Never `kubectl create secret` in production.** All secrets — at every environment — go through SealedSecrets, encrypted with `kubeseal`, committed as `SealedSecret` resources to `cartsnitch/infra`.
|
||||||
|
|
||||||
* **Never bypass the merge gate.** No self-merging PRs. No pushing directly to `dev`, `uat`, or `main`. Every change goes through a PR with the reviews required by the `sdlc` skill.
|
* **Never bypass the merge gate.** No pushing directly to `dev`, `uat`, or `main`. Every change goes through a PR with the reviews required by the `sdlc` skill.
|
||||||
|
|
||||||
* **Never run `tofu` directly.** Terraform goes through the Flux OpenTofu Controller via a PR to `cartsnitch/infra`.
|
* **Never run `tofu` directly.** Terraform / OpenTofu goes through the Flux OpenTofu Controller via a PR to `cartsnitch/infra`.
|
||||||
|
|
||||||
|
* **Always read-before-write when updating `adapterConfig.env`.** The Paperclip `PATCH /api/agents/{agentId}` endpoint with an `adapterConfig.env` body **replaces the entire env object** — sending a partial payload silently drops every key you did not include. Before writing any env variable, read the current config first, merge your changes on top, and send the full merged object:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Read existing config
|
||||||
|
existing=$(curl -s "$PAPERCLIP_API_URL/api/agents/<agentId>" \
|
||||||
|
-H "Authorization: Bearer $PAPERCLIP_API_KEY")
|
||||||
|
|
||||||
|
# 2. Merge: spread existing env, then apply new keys on top
|
||||||
|
curl -s -X PATCH "$PAPERCLIP_API_URL/api/agents/<agentId>" \
|
||||||
|
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
|
||||||
|
-H "X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$(echo "$existing" | jq '.adapterConfig.env + {"NEW_KEY": {"type":"plain","value":"val"}} | {adapterConfig: {env: .}}')"
|
||||||
|
```
|
||||||
|
|
||||||
|
Skipping the read step is a destructive operation — it erases all existing env vars for that agent.
|
||||||
|
|
||||||
|
## Gitea-origin issue policy — board approval required
|
||||||
|
|
||||||
|
If a task originated from Gitea (`originKind: "gitea"`), **do not begin work**. Immediately create a board approval:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/companies/{companyId}/approvals
|
||||||
|
{
|
||||||
|
"type": "request_board_approval",
|
||||||
|
"requestedByAgentId": "{your-agent-id}",
|
||||||
|
"issueIds": ["{issueId}"],
|
||||||
|
"payload": {
|
||||||
|
"title": "Board approval required: Gitea issue",
|
||||||
|
"summary": "Summarize what the Gitea issue requests.",
|
||||||
|
"recommendedAction": "Approve to begin work.",
|
||||||
|
"risks": ["Work begins without board review if approved."]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the issue to `blocked` with a comment linking to the approval. Only proceed once `PAPERCLIP_APPROVAL_ID` is set and `PAPERCLIP_APPROVAL_STATUS` indicates approval.
|
||||||
|
|
||||||
## If you are unsure
|
## If you are unsure
|
||||||
|
|
||||||
If you are unsure whether an action is safe, **stop**. Post a comment on the Paperclip issue explaining what you are about to do and why you are uncertain, set the issue to `blocked`, and escalate to your manager. Do not guess.
|
If you are unsure whether an action is safe, **stop**. Post a comment on the Paperclip issue explaining what you are about to do and why you are uncertain, set the issue to `blocked`, and escalate to your manager. Do not guess.
|
||||||
|
|
||||||
|
## Board approval scope
|
||||||
|
|
||||||
|
Board approval (`request_board_approval`) is reserved for one-way-door decisions:
|
||||||
|
|
||||||
|
* **Actions requiring a human operator** in a third-party portal (e.g. Gitea Owners team config, external vendor consoles).
|
||||||
|
* **Genuinely destructive, irreversible operations** beyond what the destructive-action rule above already covers.
|
||||||
|
* **Out-of-scope decisions** that exceed the agent's mandate.
|
||||||
|
* **New spend or resource authorizations.**
|
||||||
|
* **Issues with `originKind: "gitea"`** — see the Gitea-origin issue policy above.
|
||||||
|
|
||||||
|
Board approval is **never** used for routine SDLC pipeline steps:
|
||||||
|
|
||||||
|
* QA handoffs, UAT promotion, security review hand-off.
|
||||||
|
* Returning a failing PR to the engineer or CTO.
|
||||||
|
* Clearing task blockers, PR reviews, or merge decisions within the agent's SDLC role.
|
||||||
|
* Feature triage decisions (Accepted / Backlogged / Denied).
|
||||||
|
* Any standard dev → uat → prod progression.
|
||||||
|
|
||||||
|
When board approval IS required, use the Paperclip `request_board_approval` API and set the source issue to `blocked` until the approval resolves.
|
||||||
|
|||||||
+78
-142
@@ -1,122 +1,123 @@
|
|||||||
---
|
---
|
||||||
name: sdlc
|
name: sdlc
|
||||||
description: >
|
description: >
|
||||||
Software development lifecycle for CartSnitch. Covers Gitea authentication,
|
Software development lifecycle for CartSnitch application repos. Covers
|
||||||
branch strategy across Dev/UAT/Prod, the SDLC pipeline phases,
|
Gitea authentication, the 3-branch dev/uat/main strategy, the SDLC
|
||||||
PR review and merge policy, infrastructure layout, the Gitea-origin issue
|
pipeline phases 1-5, the Stage 1 CI image build, the authentication
|
||||||
board-approval gate, the cc-cpfarhood visibility rule,
|
framework, application-tool policy, and delegation model tier policy.
|
||||||
and delegation model tier policy.
|
For infrastructure (cartsnitch/infra), see the devops skill.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Software Development Lifecycle
|
# Software Development Lifecycle
|
||||||
|
|
||||||
|
This skill governs **application code repos**. For infrastructure (`cartsnitch/infra`), see the `devops` skill. For PR/test discipline and the `cc @cpfarhood` visibility rule, see `coding-standards`. For non-negotiable safety rules (including the Gitea-origin board-approval gate), see `safety`.
|
||||||
|
|
||||||
## Gitea authentication
|
## Gitea authentication
|
||||||
|
|
||||||
**Use the `GITEA_TOKEN`** environment variable for all Gitea operations. It is already set in the agent environment. Use the **`tea`** CLI for all Gitea/Git operations (e.g., `tea issue list`, `tea pr create`). The token expires when the environment variable is rotated — re-invoke any Gitea operation if you get a 401.
|
**Use the `GITEA_TOKEN`** environment variable for all Gitea operations. It is already set in the agent environment. Use the **`tea`** CLI for all Gitea/Git operations (e.g., `tea issue list`, `tea pr create`). The token expires when the environment variable is rotated — re-invoke any Gitea operation if you get a 401.
|
||||||
|
|
||||||
Gitea is the **primary source of truth**. Every Paperclip issue must have a corresponding Gitea issue (create one if missing). Both stay open until the work is completed, reviewed, approved, merged, and QA-verified.
|
Gitea is the **primary source of truth**. Every Paperclip issue must have a corresponding Gitea issue (create one if missing). Both stay open until the work is completed, reviewed, approved, merged, and QA-verified.
|
||||||
|
|
||||||
## Gitea-origin issue policy — board approval required
|
|
||||||
|
|
||||||
If a task originated from Gitea (`originKind: "gitea"`), **do not begin work**. Immediately create a board approval:
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /api/companies/{companyId}/approvals
|
|
||||||
{
|
|
||||||
"type": "request_board_approval",
|
|
||||||
"requestedByAgentId": "{your-agent-id}",
|
|
||||||
"issueIds": ["{issueId}"],
|
|
||||||
"payload": {
|
|
||||||
"title": "Board approval required: Gitea issue",
|
|
||||||
"summary": "Summarize what the Gitea issue requests.",
|
|
||||||
"recommendedAction": "Approve to begin work.",
|
|
||||||
"risks": ["Work begins without board review if approved."]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Set the issue to `blocked` with a comment linking to the approval. Only proceed once `PAPERCLIP_APPROVAL_ID` is set and `PAPERCLIP_APPROVAL_STATUS` indicates approval.
|
|
||||||
|
|
||||||
## Branch strategy
|
## Branch strategy
|
||||||
|
|
||||||
Three long-lived branches map to the three deployment environments:
|
Three long-lived branches map to the three deployment environments:
|
||||||
|
|
||||||
| Branch | Environment | Who merges |
|
| Branch | Environment | Who merges | Prerequisites for merge |
|
||||||
|--------|-------------|-----------|
|
|--------|-------------|-----------|-----------|
|
||||||
| `dev` | Dev | Engineer (self-merges after CI passes) |
|
| `dev` | Dev | Engineer | CI passes |
|
||||||
| `uat` | UAT | QA (merges after code review) |
|
| `uat` | UAT | Engineer | QA code review approval |
|
||||||
| `main` | Production | CEO (merges after UAT validation) |
|
| `main` | Production | Engineer | UAT validation, security review, CEO code review |
|
||||||
|
|
||||||
**Engineers always target `dev`** — never `uat` or `main` directly. Feature branches: `<agent-name>/<short-description>`.
|
**Engineers always target `dev` first** — never `uat` or `main` directly.
|
||||||
|
- Feature branches: `<agent-name>/<short-description>`.
|
||||||
|
|
||||||
## Pull requests
|
## Pull requests
|
||||||
|
|
||||||
All changes happen via pull request. Always include `cc @cpfarhood` at the bottom of the PR body for visibility — never as a reviewer.
|
All changes happen via pull request. Gitea branch protection requires CI checks to pass. See `coding-standards` for the no-self-merge contract and the `cc @cpfarhood` visibility rule.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tea pr create --base dev --title "..." --body "... cc @cpfarhood"
|
tea pr create --base dev --title "..." --body "... cc @cpfarhood"
|
||||||
```
|
```
|
||||||
|
|
||||||
Gitea branch protection requires CI checks (lint, test, build-and-push). Governance is enforced through Paperclip — Gitea-native review approvals are not required because all agents share the Gitea App identity.
|
Governance is enforced through Paperclip — Gitea-native review approvals are not required because all agents share the Gitea App identity.
|
||||||
|
|
||||||
## PR review & merge policy
|
|
||||||
|
|
||||||
### Dev branch (`dev`)
|
|
||||||
- **Engineer** self-merges after CI passes. Dev is for validation, not quality gates.
|
|
||||||
- **QA (Checkout Charlie `9b6012d0-0406-417e-bb22-78266a6e7f77`)** reviews the PR. Fail → back to engineer with exact details.
|
|
||||||
- QA approves and hands off to CTO.
|
|
||||||
- **CTO (Savannah Savings `6ec1a5a9-113c-430b-90e6-260d60d79e1d`)** reviews the PR. Fail → back to engineer.
|
|
||||||
- **CTO** merges the dev PR.
|
|
||||||
|
|
||||||
### UAT branch (`uat`)
|
|
||||||
- **CTO** opens and merges a PR from `dev` to `uat`.
|
|
||||||
- **CI** builds and deploys automatically to UAT (`https://uat.cartsnitch.com`).
|
|
||||||
- **CTO** creates a UAT regression task for **Deal Dottie (`161fb3bb-0332-4381-b67d-7c4b92a91133`)** immediately after promoting.
|
|
||||||
|
|
||||||
### Main branch (`main`)
|
|
||||||
- **CEO (Coupon Carl `cd91facf-8f4c-4cbd-b8d8-b48da5b50727`)** reviews and merges the `uat → main` PR.
|
|
||||||
- **CI** deploys automatically to Production (`https://cartsnitch.com`).
|
|
||||||
|
|
||||||
`@cpfarhood` is cc'd for visibility on all PRs — never as a reviewer.
|
|
||||||
|
|
||||||
## SDLC pipeline
|
## SDLC pipeline
|
||||||
|
|
||||||
### Phase 1 — Dev
|
### Phase 1 — Dev
|
||||||
|
|
||||||
1. **Engineer** branches from `dev`, writes code. GitOps deploys to dev on demand.
|
1. **Engineer** branches from `dev`, writes code.
|
||||||
2. **Engineer** opens a PR against `dev`. CI must pass.
|
2. **Engineer** opens a PR against `dev`.
|
||||||
3. **Engineer** self-merges after CI passes.
|
3. **CI** fail → back to **Engineer**.
|
||||||
4. **CI** builds and deploys automatically to Dev (`https://dev.cartsnitch.com`).
|
4. **CI** pass → **Engineer** merges PR.
|
||||||
5. **QA (Checkout Charlie)** reviews the PR. Fail → back to engineer.
|
5. **CI** builds and deploys automatically to Dev (`https://dev.cartsnitch.com`).
|
||||||
6. QA approves and hands off to CTO.
|
|
||||||
7. **CTO (Savannah Savings)** reviews the PR. Fail → back to engineer.
|
|
||||||
8. **CTO** merges the dev PR.
|
|
||||||
|
|
||||||
### Phase 2 — UAT promotion
|
### Phase 2 — UAT promotion
|
||||||
|
|
||||||
9. **CTO** opens and merges a PR from `dev` to `uat`.
|
1. **Engineer** opens a PR from `dev` to `uat`.
|
||||||
10. **CI** builds and deploys automatically to UAT (`https://uat.cartsnitch.com`).
|
2. **CI** fail → back to **Engineer** (return to Phase 1).
|
||||||
|
3. **CI** pass → **QA (Checkout Charlie `9b6012d0-0406-417e-bb22-78266a6e7f77`)** performs code review.
|
||||||
|
4. **QA** rejected → back to **Engineer** (return to Phase 1).
|
||||||
|
5. **QA** approved → **Engineer** merges PR.
|
||||||
|
6. **CI** builds and deploys automatically to UAT (`https://uat.cartsnitch.com`).
|
||||||
|
|
||||||
### Phase 3 — UAT testing & security
|
### Phase 3 — User Testing & Security Review
|
||||||
|
|
||||||
11. **UAT (Deal Dottie)** runs full regression against UAT — every feature, old and new, no exceptions.
|
1. **UAT (Deal Dottie `161fb3bb-0332-4381-b67d-7c4b92a91133`)** runs full regression against UAT — every feature, old and new, no exceptions.
|
||||||
12. UAT fail → CTO redistributes to engineer (return to Phase 1).
|
2. **UAT** fail → back to **Engineer** (return to Phase 1).
|
||||||
13. UAT pass → **Security Engineer (Stockboy Steve `d59d4b24-3cc3-4616-a23a-2b4776a489ca`)** performs a security code review of the changes.
|
3. **UAT** pass → **Security Engineer (Stockboy Steve `d59d4b24-3cc3-4616-a23a-2b4776a489ca`)** performs a security code review of the changes.
|
||||||
14. Security fail → CTO redistributes to engineer (return to Phase 1).
|
4. **Security** fail → back to **Engineer** (return to Phase 1).
|
||||||
|
5. **Security** pass → Begin Phase 4.
|
||||||
|
|
||||||
### Phase 4 — Production
|
> **Note on penetration testing:** Stockboy Steve performs scheduled penetration testing against Production independently of the PR workflow. Board-authorized. Not triggered per-PR.
|
||||||
|
|
||||||
15. Security pass → **CEO (Coupon Carl)** reviews and merges the production PR (`uat → main`). Fail → back to CTO.
|
### Phase 4 — Production Promotion
|
||||||
16. **CI** deploys automatically to Production (`https://cartsnitch.com`).
|
|
||||||
|
1. **Engineer** opens a PR from `uat` to `main`.
|
||||||
|
2. **CI** fail → back to **Engineer** (return to Phase 1).
|
||||||
|
3. **CI** pass → **CEO (Coupon Carl `cd91facf-8f4c-4cbd-b8d8-b48da5b50727`)** performs code review.
|
||||||
|
4. **CEO** rejected → back to **Engineer** (return to Phase 1).
|
||||||
|
5. **CEO** approved → **Engineer** merges PR.
|
||||||
|
6. **CI** fail → back to **Engineer** (return to Phase 1).
|
||||||
|
7. **CI** pass → Begin Phase 5.
|
||||||
|
|
||||||
|
### Phase 5 — Production Deployment
|
||||||
|
|
||||||
|
The **Engineer** opens a PR against `cartsnitch/infra` to update the relevant Kustomize overlay with the new image tag. From this point the work follows the **`devops` skill pipeline** end-to-end — review, merge, and Flux reconciliation are all owned there. On merge, Flux rolls out the updated pods to production (`https://cartsnitch.com`).
|
||||||
|
|
||||||
### Hierarchy rules
|
### Hierarchy rules
|
||||||
|
|
||||||
* CTO rejections at Dev go directly to the engineer (not back through QA).
|
* Failures at any phase return to the engineer.
|
||||||
* UAT failures (Deal Dottie) go to CTO — CTO cascades to engineer.
|
* **CTO (Savannah Savings `6ec1a5a9-113c-430b-90e6-260d60d79e1d`)** is the escalation target for ambiguous returns and re-distribution when an engineer is unavailable or disputes a return.
|
||||||
* Security failures (Stockboy Steve) go to CTO — CTO cascades to engineer.
|
* UAT failures (Deal Dottie) and security failures (Stockboy Steve) cascade through the CTO when re-distribution is needed.
|
||||||
* CEO rejections at Prod go to CTO.
|
* CEO rejections at Prod cascade through the CTO.
|
||||||
|
|
||||||
> **Note on penetration testing:** Stockboy Steve performs scheduled penetration testing against Prod independently of the PR workflow. Board-authorized. Not triggered per-PR.
|
## Stage 1 CI — Image build
|
||||||
|
|
||||||
|
Triggered automatically on every merge to `main` in an application repo:
|
||||||
|
- Builds and tags the Docker image: CalVer (`YYYY.MM.DD[.N]`), `latest`, and `sha-<hash>`
|
||||||
|
- Pushes tagged images to `git.farh.net/cartsnitch/<service>` (see `coding-standards` for the registry and CalVer policy)
|
||||||
|
- Creates a CalVer git tag in the source repo
|
||||||
|
|
||||||
|
Stage 2 (Flux GitOps deployment) is owned by `devops`.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
* **Framework:** Better-Auth.
|
||||||
|
* **OAuth Providers:** Google and Apple.
|
||||||
|
* **SSO:** Authentik OIDC at `https://auth.farh.net` (credentials in `authentik-credentials` secret).
|
||||||
|
* **Never build custom authentication.**
|
||||||
|
|
||||||
|
## Application tools (canonical, not alternatives)
|
||||||
|
|
||||||
|
These are application-level dependency choices. Alternatives are policy violations:
|
||||||
|
|
||||||
|
* **Database:** CloudNativePG-managed Postgres — no SQLite, MariaDB, or MySQL.
|
||||||
|
* **Cache / pub-sub:** DragonflyDB — no Redis.
|
||||||
|
* **Authentication:** Better-Auth + Google + Apple + Authentik (see Authentication above).
|
||||||
|
* **Dependency updates:** Mend Renovate. **Dependabot is not used and will not be used.** Do not configure it.
|
||||||
|
* **Browser automation:** the `playwright` MCP server (`http://playwright:8931/mcp`). Target dev only — never test production.
|
||||||
|
|
||||||
|
For the container registry, CalVer versioning, and general PR/test discipline, see `coding-standards`. For the operator install side (CNPG, Dragonfly, Sealed Secrets), see `devops`.
|
||||||
|
|
||||||
## Delegation model tier
|
## Delegation model tier
|
||||||
|
|
||||||
@@ -126,68 +127,3 @@ When creating subtasks for other agents, set `modelProfile: "cheap"` only for:
|
|||||||
- Well-specified, bounded updates
|
- Well-specified, bounded updates
|
||||||
|
|
||||||
Leave `modelProfile` unset for anything requiring judgment, reasoning, or QA review. When in doubt, leave it unset.
|
Leave `modelProfile` unset for anything requiring judgment, reasoning, or QA review. When in doubt, leave it unset.
|
||||||
|
|
||||||
## Infrastructure
|
|
||||||
|
|
||||||
* **Production:** namespace `cartsnitch`, FQDN `cartsnitch.com`
|
|
||||||
* **UAT:** namespace `cartsnitch-uat`, FQDN `uat.cartsnitch.com`
|
|
||||||
* **Dev:** namespace `cartsnitch-dev`, FQDN `dev.cartsnitch.com`
|
|
||||||
* **Cluster:** Kubernetes — cluster-wide read; read/write on `cartsnitch-dev` and `cartsnitch-uat`; read-only on `cartsnitch` (production).
|
|
||||||
* **Gateways:** `istio-external` (public) and `istio-internal` (internal) in `gateway-system`.
|
|
||||||
* **Container registry:** `git.farh.net/cartsnitch/<service>` only.
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
|
|
||||||
* **Framework:** Better-Auth.
|
|
||||||
* **Social login:** Google and Apple OAuth.
|
|
||||||
* **SSO:** Authentik OIDC at `https://auth.farh.net` (credentials in `authentik-credentials` secret).
|
|
||||||
* **Never build custom authentication.**
|
|
||||||
|
|
||||||
## Deployment — 2-stage Flux GitOps
|
|
||||||
|
|
||||||
**Stage 1 — CI (runs in each application repo):**
|
|
||||||
- Triggered automatically on every merge to `main`
|
|
||||||
- Builds and tags the Docker image: CalVer (`YYYY.MM.DD[.N]`), `latest`, and `sha-<hash>`
|
|
||||||
- Pushes tagged images to `git.farh.net/cartsnitch/<service>`
|
|
||||||
- Creates a CalVer git tag in the source repo
|
|
||||||
|
|
||||||
**Stage 2 — GitOps (Flux, managed externally):**
|
|
||||||
- Flux watches `cartsnitch/infra` as the **target** GitRepository — it is **not** a Flux bootstrap/cluster repo and must never be treated as one.
|
|
||||||
- Reconciles Kustomize overlays: `apps/overlays/dev` → `cartsnitch-dev`, `apps/overlays/uat` → `cartsnitch-uat`, `apps/overlays/prod` → `cartsnitch`.
|
|
||||||
- Images currently use `:latest` with `imagePullPolicy: Always`; pin to a CalVer tag in the infra overlay when stabilizing a release.
|
|
||||||
|
|
||||||
**Policy — Flux Image Tag Automation is DENIED.** Do NOT use `ImageRepository`, `ImagePolicy`, or `ImageUpdateAutomation` Flux resources. Image tag updates must be made intentionally via a PR to `cartsnitch/infra`.
|
|
||||||
|
|
||||||
**To deploy a change:**
|
|
||||||
1. Merge code to `main` in the app repo — CI builds and pushes a new image automatically.
|
|
||||||
2. Open a PR against `cartsnitch/infra` to update the relevant overlay; merge after kustomize CI passes.
|
|
||||||
3. Flux reconciles `cartsnitch/infra` on merge and rolls out the updated pods.
|
|
||||||
|
|
||||||
**To force a rollout without a manifest change:**
|
|
||||||
```bash
|
|
||||||
kubectl rollout restart deployment/<name> -n <namespace>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Infrastructure as Code
|
|
||||||
|
|
||||||
Terraform (OpenTofu) is deployed via the **Flux OpenTofu Controller** in a GitOps fashion. Submit Terraform configurations via a PR to `cartsnitch/infra` — the tofu controller reconciles them on merge.
|
|
||||||
|
|
||||||
**Never run `tofu` directly.** Never `kubectl apply` against production. Production changes go through Flux only. The `cartsnitch-dev` and `cartsnitch-uat` namespaces permit direct kubectl use for iteration.
|
|
||||||
|
|
||||||
## Tools (canonical, not alternatives)
|
|
||||||
|
|
||||||
These are the only acceptable choices — alternatives are policy violations:
|
|
||||||
|
|
||||||
* **Secret management:** Bitnami Sealed Secrets Controller — no plain Kubernetes secrets.
|
|
||||||
* **Database:** CloudNativePG Operator (Postgres) — no SQLite, MariaDB, or MySQL.
|
|
||||||
* **Cache / pub-sub:** DragonflyDB Operator — no Redis.
|
|
||||||
* **Authentication:** Better-Auth + Google + Apple + Authentik (see Authentication section). Never build custom auth.
|
|
||||||
* **Dependency updates:** Mend Renovate. **Dependabot is not used and will not be used.** Do not configure it.
|
|
||||||
* **Container registry:** `git.farh.net/cartsnitch/<service>` — no Docker Hub for first-party images.
|
|
||||||
* **Browser automation:** the `playwright` MCP server (`http://playwright:8931/mcp`). Target dev only — never test production.
|
|
||||||
|
|
||||||
If a task requires deviating from any of the above, treat it as a destructive action: stop, file an issue with rationale, request board approval.
|
|
||||||
|
|
||||||
## External communication
|
|
||||||
|
|
||||||
When communicating in any context visible outside the CartSnitch agent team (external users, human reviewers, non-agent entities), include `cc @cpfarhood` for visibility — never as a reviewer.
|
|
||||||
Reference in New Issue
Block a user