# Scalegion — Autonomous Agent System & Repository Architecture

This document serves as the authoritative guide for AI coding agents working on the Scalegion platform.

---

## 0. READ FIRST — Rules for every change (DO / DON'T)

> **Every agent and every human reads this section before changing anything.** These rules
> exist because each one was broken at least once and cost users something real. When a task
> conflicts with a rule, **do not do the task** — mark it `unresolved` and say which rule it hits.
> The critical rules are also enforced by `scripts/guardrails.cjs`, which runs inside `npm test`:
> a change that breaks one fails verification. **Never delete, skip, weaken or "fix" a guardrail
> test to make it pass** — fix the code instead.
> The DevAgent worker adds a **tamper lock** (`agent-worker/run_task.sh`, step 6a) that the agent
> cannot edit: a session is discarded, never merged, if it touches `AGENTS.md`, `GEMINI.md`,
> `CLAUDE.md`, `.agent/`, `scripts/guardrails.cjs` or `run_task.sh`, changes the `test` script,
> unhooks the guardrails, or fails a trusted copy of the guardrails taken from `main`.
> Those files change only by a human.

### 0.1 How to change code

- **DO** make the smallest change that resolves the task. Edit the lines that need changing.
- **DON'T** rewrite or regenerate whole files. `features/SocialHubView.tsx` was once cut from
  11,900 to 9,400 lines in one task; the Calendar, Gallery, Analytics, Video Studio entry point,
  campaign list and the weekly-batch off switch all disappeared with it.
- **DON'T** remove a feature, control, handler or screen unless the task explicitly asks for that
  removal. If code looks unused, leave it and mention it in your report.
- **DO** read the header comment of every file you edit, and the comment above every function you
  change. They record why the code is the way it is. Keep them; update them if you change behaviour.
- **DON'T** delete explanatory comments. They are the project's memory.
- **DO** run `npm test` and fix every failure your change causes. TypeScript must not gain errors
  (`npx tsc --noEmit -p .` — the count may not go up).
- **DON'T** commit build output, screenshots, temp files or `tmp/` (a 1 MB `tmp/screenshot.png`
  was committed once).

### 0.2 Security — never weaken these

- **DON'T** put any secret in code: API keys, passwords, tokens, DB credentials. Read them from
  `process.env`. A new OpenAI key was once hard-coded into three files and pushed to GitHub.
- **DON'T** add `|| "sk-…"`-style fallbacks for keys. A missing key must fail loudly or degrade.
- **DO** keep the ACCESS GATE in `backoffice/server.js` (search `ACCESS GATE`): every `/api/agent/*`,
  `/api/tasks*`, `/api/projects/:id/tasks*`, admin, internal, money-spending and email route needs a
  signed-in session, the worker's `SCALEGION_AGENT_TOKEN`, or a real project token.
- **DON'T** make a route public "to fix a 401". Find out who should be calling it and authenticate them.
- **DON'T** accept `verify_cmd`, `repo_url`, `github_repo`, `target_branch` or `auto_deploy` from a
  task body or metadata. The worker runs `verify_cmd` with `eval` next to the GitHub token.
- **DON'T** treat a token starting `scl_` or `bztk_` as a user. Project tokens are only valid when
  they match a real project (`isRealProjectToken`).
- **DO** check that the caller owns the project for every route that reads or writes project data
  (`assertProjectOwner`). Scope every query by tenant.
- **DON'T** run shell commands built from strings that contain user or database values. Use
  `execFile`/`spawn` with an argument array.
- **DO** keep `publicIntakeLimit` (rate limit) and the duplicate check on the public feedback/error
  routes. One smoke test once created ~27,000 tasks a day through them.
- **DON'T** post synthetic or smoke-test traffic to production intake routes.

### 0.3 Automation — nothing surprises the user

- **DO** give anything that runs on its own an off switch, a visible last-run, and a cadence —
  from the first version.
- **DON'T** remove an off switch. The Social Hub weekly batch can publish to live channels every
  Monday; its enable toggle, draft/schedule choice and last-run line must always be on screen.
- **DON'T** let anything spend money (image or video generation) or publish to a live channel
  without the user having switched it on. Defaults are draft, never publish.
- **DO** make every scheduled job write a status a human can read (and a failure, honestly).
- **DON'T** change what a stored schedule means. A cron of `8 0 * * *` is 00:08, never 08:00.
  Store times in UTC, show them in the viewer's local time, and never shift a user's chosen time.

### 0.4 Honesty — never invent

- **DON'T** show a number, trend, time or state that was not measured. If it cannot be known,
  show nothing and say why. (A hard-coded "+5%" once filled the dashboard with fake badges.)
- **DON'T** fill a missing time with a default ("9 AM") and present it as real.
- **DO** give every empty state three parts: the fact, the likely cause, the next action.
  Facebook returns no analytics; Instagram nothing past ~30 days — say which.
- **DO** report every async action's outcome: loading, success and failure are all visible states.
  Reload before announcing success.
- **DO** make an error say what to do next.

### 0.5 Interface — product, not admin panel

- **DO** write every word for the people who use it: mainly the **United States, the UK and
  Israel**, then the rest of the world. Keep it simple enough for anyone (KISS): short sentences,
  everyday words, one idea per label. US spelling (color, organize), but only words a UK or
  Israeli reader (often English as a second language) also knows instantly.
- **DON'T** use idioms or slang ("tick off", "touch base") or unexplained jargon and acronyms
  (MCP, CMS, SEO, KPI, MRR, "orchestrate", "deliverables"). Say what it does instead.
- **DO** write dates with the month as a word ("Oct 18, 4:45 PM"). Never `10/18` or `18/10` —
  the same digits mean different days in the US and in the UK/Israel.
- **DON'T** leave dead controls: a button, checkbox or link that cannot succeed must not render.
- **DO** label every number with what it counts and over what period.
- **DO** use the visual language: `rounded-2xl` cards, `border-slate-200`, `shadow-sm`.
  Colour has one job each: **Scalegion orange (`accent-600`) = the main action** on a screen
  (one per area); **green (`brand-600`) = approve / it is live** (Approve, Post now, Posted,
  Connected, On); blue scheduled, amber draft, rose failed and destructive. Secondary buttons are
  white with a slate border. No indigo or purple buttons. `tabular-nums` for numbers. Anything
  destructive is rose and asks for confirmation first.
- **DO** use the type system: `font-sans` (Geist) for text, `font-display` (Bricolage
  Grotesque) for headings (h1-h3 get it automatically), `font-mono` (Geist Mono) for code-like
  labels. Nothing smaller than 10.5px; 12.5px (`text-xs`) is the normal small size.
- **DO** lazy-load heavy libraries (charts) behind their own chunk.
- **DON'T** put a CSS `transform` in the `fade-in` keyframes (it breaks every fixed modal), use
  `overflow-x: hidden` on `body` (use `clip`), or build Tailwind class names from variables.
- **DON'T** reintroduce `cdn.tailwindcss.com`.

### 0.6 Social Hub — features that must stay reachable

Each of these existed and was relied on. Removing one breaks a customer workflow. Some are
currently missing after a redesign and are being restored — **do not remove what remains, and do
not build on top of their absence**:

| Must stay | Why |
|---|---|
| Weekly batch: enable toggle, draft/schedule mode, last run, "write the week now" | The only way to stop automatic posting |
| A list of ALL campaigns with edit, pause and delete (with confirm) | Customers run several campaigns |
| Video Studio entry point and "New video" | Otherwise video cannot be reached |
| Publish-now confirmation dialog | Publishing is irreversible |
| Channel health / reconnect banner | A dead channel silently drops posts |
| Analytics explanations (Facebook none, Instagram 30 days, provider delay) | Honesty rule |
| "Going out next" grouped by `scheduledFor` in local time | Posts must show on the day they publish |

### 0.7 Video and image engines — invariants

- **Video (`backoffice/services/videoShorts/`)**: renders run one per job in the API process
  (max `SHORTS_CONCURRENCY`, default 2, with a memory guard). A render interrupted by a restart is
  re-queued, never failed. Motion renders are SDR H.264 (`hdrMode: 'force-sdr'`) — never let one HDR
  clip switch a render to HEVC. Stock clips are trimmed before rendering. A motion failure falls back
  to the classic look and says so on the render record.
- **Stock footage/photos**: Pexels only (Coverr is not licensed for our use). Matching requires the
  scene's subject; the Gemini judge may reject everything, and then the scene uses a headline card.
  Keep creator credits on the record.
- **Post images**: real photography first (`realPhotoFor`), AI generation only when nothing fits.
  Every logo goes through `fitLogo` + `logoLayers` (trimmed, sized by optical area, plate only
  when it would vanish). **Never size a logo by width or height alone.** No random ornaments.
- **Post copy (`backoffice/copyStructure.js` + `COPY_QUALITY_BAR`)**: every post is HOOK → VALUE →
  CLOSE. The first line is the hook, on its own line, short enough to show before "see more", and
  the post must pay it off. The close is one deliberate line (save, soft CTA, follow, a real
  question, one action, share), rotated per post. **A close may only use what the brand gave us:
  never invent a link, discount, deadline, or a promised future post.** The image headline pairs
  with the first line and never repeats it.
- **Costs**: anything that calls a paid model logs its real cost. Never log a guessed flat price.

### 0.8 Operations

- **DON'T** run jobs, scraping or agents on Vercel.
- **DON'T** load whole tables into memory or into one response. The portfolio once sent 300k
  tasks (182 MB); it now sends the latest per project with exact totals.
- **DON'T** mass-commit line-ending churn (`git diff --ignore-all-space` shows real changes).
- **Migrations** are plain JS in `backoffice/migrations/`, numbered, add-only, idempotent.

---

## 1. Multi-Backend 3-Instance Architecture

Scalegion decouples social operations, marketing scheduling, and autonomous code development across three dedicated backend instances:

```
┌────────────────────────────────────────────────────────┐
│             FRONTEND UI (Vercel CD)                    │
│  - React 19 + TypeScript + Vite                        │
│  - Real-time Dashboards, Task Kanban, Social Hub       │
└───────────────────────────┬────────────────────────────┘
                            │
       ┌────────────────────┼────────────────────┐
       ▼                    ▼                    ▼
┌──────────────┐   ┌─────────────────┐   ┌───────────────────────────┐
│  INSTANCE 1  │   │   INSTANCE 2    │   │        INSTANCE 3         │
│  SOCIAL HUB  │   │ BACKOFFICE &    │   │    AUTONOMOUS AGENT-      │
│  PUBLISHING  │   │ SCHEDULER API   │   │     DEVELOPER WORKER      │
│              │   │ api.scalegion.com │   │        2.29.4.203         │
│ (Postiz SaaS/│   │ 168.119.53.183  │   │  (8GB ARM64 Hetzner Host) │
│  Self-hosted)│   │  /backoffice/   │   │      /agent-worker/       │
└──────────────┘   └────────┬────────┘   └─────────────┬─────────────┘
                            │                          │
                            │ Task Queue & Issues API  │
                            └──────────────────────────┘
```

### The 3 Dedicated Backend Roles:

1. **Instance 1: Social Hub Instance (Postiz / Publishing)**
   - Dedicated service for social network integrations (X/Twitter, LinkedIn, Instagram, Facebook, TikTok, YouTube).
   - Manages OAuth channel bindings, rate-limited content dispatch, and network-specific asset transformations.

2. **Instance 2: Backoffice Scheduler & Ideation Hub (`api.scalegion.com` / `168.119.53.183`)**
   - Express monolith (`server.js`) + MySQL + `node-cron`.
   - Ideation Pipeline (Harvester -> Classifier -> LLM) & weekly content batch engine.
   - Central Task Queue, APM Error Ingestion (`/api/track-error`), and Agent Dispatch API (`/api/agent/issues`).
   - Executive Memory ("Business Brain" per project).
   - Deploy script: `./deploy_backoffice.sh` (or `./deploy_backoffice_api.sh`).

3. **Instance 3: Autonomous Agent-Developer Worker (`2.29.4.203`)**
   - Dedicated Hetzner 8GB host (`aarch64` Ampere Altra).
   - Base OS: 8GB NVMe Swap + Docker Engine + VM memory tunings.
   - Project-Dedicated Persistent Sandboxes: `/opt/agent-runner/workspaces/<project-slug>`.
   - Single-Flight Project-Affinity Queue Daemon (`worker_daemon.js`).
   - Headless Antigravity CLI Execution Engine.
   - cgroup resource limits (1.8 CPU / 3.5GB RAM).
   - Fast Git Scrub & Automated GitHub / Bitbucket PR Delivery.
   - Deploy script: `./deploy_agent_worker.sh` (or `./agent-worker/deploy_worker.sh`).

---

## 2. Directory Structure & Separation of Concerns

* **`backoffice/`** — The Control Plane and Marketing API.
  * `server.js` — API gateway for projects, social posts, tasks, and executive memory.
  * `ideation/` — Trend scraping, news classification, and post brief assembly.
  * `services/` — Connectors for GA4, GSC, Ahrefs, Stripe, Meta Ads, Postiz, and Video pipelines.
  * `migrations/` — Plain JavaScript sequential database migrations.
  * `apply_schema_sql.py` — Database schema migrator (formerly `run.py`).
  * `test_db_connection.js` — Quick database connectivity test.

* **`agent-worker/`** — The Dedicated Autonomous Code Development Worker.
  * `Dockerfile` — Base container image (`devagent-base:latest`) equipped with Node.js, Python, Git, `gh`, and Antigravity runner.
  * `setup_worker_host.sh` — Bootstraps swap, sysctl memory tunings, and directories on the Hetzner worker.
  * `run_task.sh` — Runs tasks inside isolated Docker containers with cgroup caps, base branch detection, soft git scrub, verification loop, and `gh pr create` (GitHub) or Bitbucket REST API pull requests.
  * `worker_daemon.js` — Single-flight, project-affinity polling coordinator.
  * `deploy_worker.sh` — Deployment script syncing `agent-worker/` to the worker instance.

* **`features/` & `components/`** — Client-side React application.
  * `features/TasksView.tsx` — Operational task board and APM error manager.
  * `features/SocialHubView.tsx` — Automated marketing campaigns, weekly batch calendar.
  * `features/ProjectSettingsView.tsx` — GitHub and Bitbucket repository integration and project settings.
  * `components/AgentChat.tsx` — Business agent chat that learns and persists executive memory.

---

## 3. Worker Execution Conventions & Guardrails

1. **Never Push Directly to `main` (in PR Mode):**
   Automated development tasks execute on an isolated branch (`agent/<task_id>`) and either auto-deploy to the target branch upon passing verification or open a Pull Request (via GitHub CLI `gh pr create` or Bitbucket REST API).
2. **Preserve Warm Dependencies:**
   Between tasks, clean the workspace using:
   ```bash
   git clean -fd -e node_modules -e .venv -e target -e .cache
   ```
   Never delete dependency trees between tasks within the same project.
3. **Dynamic Verification:**
   Verify code changes using the repository's native verification command (`npm test`, `npm run build`, or `pytest`).
4. **Project Affinity:**
   The worker daemon drains all pending tasks for Project A before switching context to Project B to maximize AST and build cache hits.
5. **Inactivity Hibernation:**
   Containers idle for > 30 minutes are automatically stopped to reclaim host RAM while preserving volume state on disk.
6. **Pre-Cost Quota Estimation Guardrail:**
   Before claiming batch dev tasks, the worker daemon queries `/api/projects/:id/check-quota` with the estimated task cost ($0.15–$0.40). If the project is at or over its plan quota, the worker refuses to claim the task and flags it for human review.

---

## 4. Script & Utility Index

| New Script | Previous Name | Description |
|---|---|---|
| `deploy_backoffice.sh` / `deploy_backoffice_api.sh` | `deploy_backoffice.sh` | Deploys Control Plane / Social Hub / Ideation API to Hetzner VPS (`168.119.53.183`). |
| `deploy_agent_worker.sh` | *New* | Deploys the Development Agent Worker to the dedicated Hetzner worker host. |
| `query_projects_db.py` | `run_db_query.py` | Queries `projects` table in production MySQL database. |
| `query_recent_tasks.sh` | `run_db_query.sh` | Queries recent `tasks` in production MySQL database. |
| `ssh_query_vps_tasks.exp` | `testdb.exp` | Queries database tasks remotely on the API VPS. |
| `ssh_run_script_on_vps.exp` | `do_ssh.exp` | Copies and runs a diagnostic Python script on the API VPS. |
| `backoffice/apply_schema_sql.py` | `backoffice/run.py` | Applies `schema.sql` to the MySQL database. |
| `backoffice/test_db_connection.js` | `backoffice/testdb.js` | Verifies MySQL connection from the backoffice. |

---

## 5. Executive Memory ("Business Brain")

Scalegion maintains a persistent memory store (`project_memories` table) for each business tenant:
* **Memory Types:** `ICP`, `Objective`, `Product`, `Vertical`, `Other`.
* **Endpoints:** `GET /api/projects/:id/memories`, `POST /api/projects/:id/memories`, `DELETE /api/projects/:id/memories/:memoryId`.
* **Prompt Injection:** Hydrated into every AI agent context under `EXECUTIVE MEMORY / WHO WE ARE:` to ensure hyper-tailored strategies and code changes.

---

## 6. Deployment & Git Synchronization Rules

1. **Commit and Push is Mandatory**:
   Every code change, feature update, and deployment task MUST be committed (`git commit`) and pushed (`git push origin main`) to GitHub. Vercel CD deployments trigger strictly off GitHub pushes; unpushed local changes will NEVER reach production or preview environments.
2. **Post-Deployment Verification**:
   After triggering a push or running backend deploy scripts (`./deploy_backoffice.sh`), verify that the git working directory is clean (`git status`) and origin is up to date. Never leave working tree changes uncommitted after completing a task.

---

## 7. Economics Governance & 10× Average Profit Floor (Revenue ≥ 10× AI COGS)

Scalegion enforces a strict founder requirement: **valid 10× profits minimum on average vs AI expenses** (`Platform Revenue ≥ 10 × AI COGS`, meaning AI COGS must never exceed 10% of recognized revenue).

### 1. Per-Plan Monthly AI Budgets
Budgets are derived directly from customer subscription prices:
* **Free Tier**: $1.50 lifetime trial cap.
* **Solo ($39/mo)**: Max AI COGS **$3.90/mo** per seat.
* **Growth ($119/mo)**: Max AI COGS **$11.90/mo**.
* **Scale ($299/mo)**: Max AI COGS **$29.90/mo**.
* **Enterprise**: Custom negotiated SLA (default 10% of monthly contract value).

### 2. Quota Thresholds & Throttling
* **70% Budget Utilization (Soft Warning)**: Visual yellow banner displayed on Project Settings and Admin Costs; non-essential speculative background jobs deprioritized.
* **100% Budget Utilization (Hard Throttle)**: Non-critical background AI calls (ideation harvesting, automated blog generation, autonomous code development) are throttled with HTTP 429 until the next billing cycle or quota top-up. Critical interactive user requests prompt the user to upgrade or add credits.

### 3. Autonomous Agent-Worker Pre-Cost Verification
* Prior to dispatching or executing autonomous dev tasks, the worker daemon estimates the task cost ($0.15–$0.40 depending on expected turns).
* If the project has exceeded its quota (or if the kill-switch is active), the daemon skips task execution, leaves the task in `pending`, flags `requires_approval = 1`, and generates an alert.

### 4. Platform-Level Rolling 30d Metric & Global Kill-Switch
* The Admin Costs dashboard (`/admin/costs`) tracks rolling 30-day recognized revenue vs AI COGS and displays the implied multiple. If the multiple falls below 10×, a red margin warning is flagged.
* **Emergency Kill-Switch**: If the rolling 30-day revenue-to-AI-cost multiple drops below **8×** (i.e. AI COGS > 12.5% of revenue) for longer than 48 consecutive hours, the platform activates the Global Kill-Switch. Nonessential background batch jobs are paused system-wide until founder/admin review or override.

---

## 8. CEO Dogfood Ops & Multi-Tenant Boundary

Founder-locked scope (2026-09-19):
* **Scalegion CEO Scope:** The internal Scalegion CEO autonomous agent and hourly loop (`runHourlyCeoOpsLoop` in `backoffice/services/ceoOps.js`) manage Scalegion's own dogfood project (`proj_1777457741023`) ONLY.
* **Tenant Isolation:** The CEO ops loop never queues, claims, mutates, or runs tasks for any other customer project or external tenant.
* **External Product & Tenant Interaction:** External products, customer tenants, and third-party agents interact exclusively through public unauthenticated endpoints:
  - Project-scoped feedback: `POST /api/projects/:projectId/feedback` (or `POST /api/error-proxy`)
  - Project-scoped error tracking: `POST /api/track-error`
  - Project-scoped dev issues: `GET /api/agent/issues?project=<project_id>&status=todo` (supports `type=code`)
  - Tenant claim-next endpoint: `POST /api/projects/:projectId/tasks/claim-next` (Atomically claims next pending automation=1 task for the project without manual ID specification)
  - Queue metrics: `GET /api/agent/metrics` (Latency, time-in-todo averages, and tenant queue breakdown)
* **Hourly Loop Core Duties:**
  1. List open dogfood tasks for `proj_1777457741023`.
  2. File new feedback/issues when product or growth is blocked.
  3. Prioritize high-intent traffic and organic attention without low-quality directory spray (directories produce ~0 traffic and are deprioritized or flagged).
  4. Never queue tasks or actions for other tenants.
* **Project Filtering:**
  - Admin & Agent API endpoints support strict project filtering:
    - `GET /api/projects/:projectId/tasks` (admin task list for project)
    - `GET /api/tasks?project_id=<id>&status=<status>&type=<type>`
    - `GET /api/agent/issues?project=<id>&status=todo` (supports `type=code`)
    - `POST /api/projects/:projectId/tasks/claim-next` (Single-flight claim next task)
    - `GET /api/agent/outreach/tasks?project=<id>`

* **Email Marketing AI Addon (`email_marketing_ai`, $29/mo Entitlement):**
  - All email endpoints (events, contacts CRUD, campaigns, stats) are gated with HTTP 402 if the project does not have the `email_marketing_ai` addon active in `advisor_addons`.
  - Addons Management: `GET /api/projects/:id/addons`, `POST /api/projects/:id/addons/:advisorId/activate` (or enable), `POST /api/projects/:id/addons/:advisorId/deactivate`, `POST /api/projects/:id/addons/:advisorId/toggle`.
  - Addon status: `GET /api/projects/:id/email/addon-status`
  - Addon enable: `POST /api/projects/:id/email/addon/enable` with `{ "path": "standard" | "dev_task" }`. Path `dev_task` automatically creates an AI Developer code task (`automation: 1`, `type: "code"`) to implement integration into the tenant's codebase.
  - Events ingestion: `POST /api/projects/:id/email/events` with `{ "event": "user.registered", "email": "...", "name": "...", "properties": { ... } }`. Upserts contact, executes matching trigger campaigns, logs messages with delivery status into `email_messages`. Query events via `GET /api/projects/:id/email/events`.
  - Contacts CRUD: `GET`, `POST`, `PATCH`, `PUT`, `DELETE`, `/batch`, `/:contactId/consent`, `/:contactId/resend-confirmation`.
  - Stats & Telemetry: `GET /api/projects/:id/email/stats` (overview alias), `GET /api/projects/:id/email/stats/overview`, `GET /api/projects/:id/email/stats/campaigns/:id`, `GET /api/projects/:id/email/messages`.

* **Question & Executive Memory Tasks:**
  - Task type `question`: Used when autonomous dev or advisory agents need executive founder decision, clarification, or direction.
  - Required fields: `question_text`, `answer_text`, `memory_write`.
  - Task List UI: Shows prominent `❓ Needs answer` badge (vs `👤 Needs work` or `🤖 Auto`).
  - Task Drawer: Features prominent Answer box with Submit button that marks the task `done` and writes the decision to Project Executive Memory (`POST /api/projects/:id/memories` with `type: "Decision" | "Note"`, `source: "task:{taskId}"`).
  - Notifications & Deep-links: All assignment and review emails for questions and tasks must include a prominent project header, project URL, question text, and deep link directly to `/project/{projectId}/tasks?task={taskId}` (secondary link to `/project/{projectId}`).

* **Automated Health Probes & Canaries:**
  - Automated probes from CEO monitor / hourly ops (e.g. `probe — ignore`, `health probe`, `safe to close/cancel`) verify telemetry, queue responsiveness, and gating logic.
  - Probes and canaries testing commit-hash gates and metric gates strictly prove rejection (HTTP 400). Code tasks (`type: "code"` or `automation: 1`) MUST NOT be marked `review` or `done` without a verified non-empty `commit_hash` (or `commit_hashes`), or an explicit human override flag (`human_override: true`). Runner must not move tasks to review on no-op / session-without-commits and must auto-release such sessions to `todo` with an error note.
  - Auto-Unclaim Policy: The runner must push commits or fail-closed and release claims within session limits. Code tasks remaining `in_progress` with null/empty `commit_hash` for > 60 minutes are automatically unclaimed by the control plane watchdog and runner daemon back to `todo` with an explanatory note to prevent multi-hour empty claims.
  - Discard/cancellation of probe spam is supported via `status: "cancelled"` or `status: "deleted"` with `discard_probe: true` or `hard_discard: true`.

---

## 9. Metric-Gated Acceptance for Monetization, KPI, and Metric Tasks

To protect platform and product integrity, commit-alone completion is strictly forbidden for metric-sensitive tasks. Closing code without proving that live metrics moved constitutes a false success.

1. **Gate Activation**:
   - Tasks with metadata flag `acceptance.metric_gate` or type/tags matching `monetization`, `kpi`, or `seo_metric` are metric-gated.
2. **Rejection Rules (HTTP 400)**:
   - **Missing Verification Payload**: Any attempt to mark a gated task `done` via `PATCH /api/agent/issues/:id` or `PUT /api/tasks/:id` without a verification payload is rejected with HTTP 400.
   - **No Metric Change (`after == before`)**: A commit that produces no metric change is rejected with HTTP 400. `after` must demonstrably improve or move compared to `before`.
   - **Missing Commit Hash**: Standard commit verification remains mandatory in addition to the metric delta (`commit_hash` or `commit_hashes` required for code/automation tasks on `review` and `done` unless `human_override` is explicitly set).
3. **Structured Verification Format**:
   ```json
   {
     "metric": "none_direct_stores",
     "before": 3900,
     "after": 3200,
     "source_url": "https://cash-it.com/admin/stores?filter=none_direct",
     "checked_at": "2026-09-21T12:00:00Z"
   }
   ```
4. **Autonomous Developer Obligations**:
   - The AI Developer must attach the structured verification object under `verification` or within resolution notes.
   - Unresolved merchant/external blockers (e.g. Lemon Squeezy store publishing, external KYC) or tasks whose metrics have not yet moved MUST stay open (`todo`/`review`) and must NOT be marked `done`.
   - Cash-it Wave 20/21 P0s (`51c1673c`, `a94c6fd1`, `975d50cd`) and related batches must remain open (`todo`) until live production metrics demonstrably improve. Specifically, metric P0 `975d50cd` must stay open until `unprocessed_views` moves (while AI blocked=true, ~10.73M flat); moving to review/done without verified improvement is strictly rejected.

---

## 10. External-Blocker Gate, Lemon Merchant Publish, and Dogfood Scope Integrity

1. **Metric/External-Blocker Gate (External HTTP 200)**:
   - Code Criticals whose acceptance criteria require external HTTP 200 (such as Lemon buy URLs `/buy/legion-solo`, `/buy/legion-growth`, `/buy/launch-sprint`, or store root not 403) MUST NOT move to `done` or `review` unless verification payload proves those URLs are HTTP 200, OR explicit founder `human_override: true`.
   - Unrelated `commit_hash` alone is strictly insufficient when acceptance metrics still fail (store 403 / buy 404). Attempting to close or move to review without HTTP 200 verification rejects with HTTP 400.
2. **Founder/Merchant-Only Publish Tasks**:
   - The runner daemon must not claim founder/merchant-only Lemon publish tasks for code sessions; leave `todo` until the founder publishes live checkout (HTTP 200). If claimed in error, control plane watchdog and runner daemon auto-unclaim them back to `todo`.
3. **Dogfood Project Scope (`proj_1777457741023`)**:
   - The Scalegion dogfood project (`proj_1777457741023`) manages Scalegion tasks and organic distribution only.
   - Foreign-project SEVs (such as Cash-it) must not be filed or claimed on dogfood `proj_1777457741023`. Filing or claiming rejects with HTTP 400.
4. **Resolution Notes & Commit Integrity**:
   - Any gate change requires a non-empty `commit_hash` (unless human override) and a non-empty `resolution_note` containing before/after probe evidence.

---

## 11. Live-URL Acceptance Gate for SEO, SSR, and Store-Hub Tasks

Commit-alone completion is strictly insufficient for tasks that produce or populate live URLs (such as SEO landing pages, SSR endpoints, and store-hub directories). Tasks cannot be marked `done` while live pages remain empty (0 matches) or return noindex/errors.

1. **Gate Activation**:
   - Tasks tagged `acceptance.live_url` (in `tags`, `type_tags`, title, or metadata) or with `metadata.acceptance.urls[]` are live-URL gated.
2. **Verification Requirements for `PATCH status=done`**:
   - **HTTP 2xx**: Each target URL must return a successful HTTP 2xx status code. Non-2xx responses (e.g. 404, 500) fail validation.
   - **Required Substring & Min Count**: If `required_substring` is specified, occurrences in the live page response body must meet or exceed `min_count` (e.g. `"/product/"` count >= 1). Tasks cannot close while target page has 0 matches.
   - **Forbidden Substring**: If `forbid_substring` is specified (e.g. `"noindex"`), occurrences must be 0.
   - **Commit Hash Required**: A valid, non-empty `commit_hash` (or `commit_hashes`) is mandatory. Closing without a commit hash is strictly rejected with HTTP 400.
3. **Rejection & Task State Behavior (HTTP 400)**:
   - If any URL verification check fails, `PATCH status=done` returns HTTP 400 and keeps the task in its current state (`in_progress` or `todo`).
   - The control plane logs verification evidence (status codes, match counts, forbid counts, and timestamps) in task metadata (`metadata.verification`) on verification attempts.
4. **Autonomous Developer Obligations**:
   - The AI Developer and runner daemon must verify that live pages are deployed and populated with target content before attempting to mark tasks `done`. Unverified tasks must remain open in `todo`.

---

## 12. Scalegion Homepage Styleguide, Email Design System & Mobile Header Navigation

To ensure seamless brand consistency across the platform, all agents must adhere to the Scalegion homepage styleguide for both user interfaces and system emails, as well as preserving accessible mobile navigation.

### 1. Brand Tokens & Design System
* **Primary Brand Orange**: `#F2500A` (Hover: `#E04A08`, Glow: `rgba(242, 80, 10, 0.55)`).
* **Brand Tint**: `#FFF1EA` (Used for chips, pill backgrounds, and highlight containers).
* **Neutral Backgrounds**: `#F7F8FA` (Page canvas), `#FFFFFF` (Card surfaces), `#F2F4F7` (Inner sections).
* **Borders**: `#E3E7EC` (Standard 1px hairline border).
* **Typography**:
  - Headings: `Archivo, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`
  - Body: `Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`
  - Badges/Code: `'JetBrains Mono', 'SF Mono', Consolas, monospace`
* **Official Logo Lockup**:
  - Wordmark SVG: `<img src="https://www.scalegion.com/brand/logo-wordmark.svg" height="28" alt="Scalegion" onerror="this.src='https://www.scalegion.com/logo.png';" />`
  - Pill Badge: `<span style="font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:800;color:#F2500A;background:#FFF1EA;border:1px solid rgba(242,80,10,0.25);padding:2px 6px;border-radius:4px;letter-spacing:0.05em;">SCALE</span>`

### 2. Email Design System Across All Backends
All outgoing automated emails (`backoffice/server.js`, `backoffice/services/hourlyDigestService.js`, `backoffice/services/assignmentEngine.js`, `backoffice/emailMarketingRoutes.js`, and `agent-worker/worker_daemon.js`) MUST use the official Scalegion email shell:
* Container: `#F7F8FA` canvas with `#FFFFFF` card, `1px solid #E3E7EC` border, and `14px` border radius.
* Header: Centered or left-aligned Scalegion Hinge wordmark + `SCALE` badge.
* Primary CTA Buttons: `#F2500A` solid background, `#FFFFFF` text, `font-weight: 700`, `border-radius: 8px`, `padding: 12px 24px`.
* Footer: Scalegion Inc. address and unsubscribe links in `#6B7584` steel typography.

### 3. Mobile Header Navigation UX
On mobile screens (`<= 980px` and `<= 560px`), the header navigation MUST NOT hide the login link. Both **Log in** (`.nav-login`) and **Start free** (`.btn`) must remain visible side-by-side:
* Navigation links filter: `nav.scalegion-nav .links a:not(.btn):not(.nav-login) { display: none; }`
* Log in link style: `display: inline-flex; align-items: center; color: var(--mut); font-size: 13px; font-weight: 600; padding: 6px 10px; border-radius: 8px; text-decoration: none;`
* Start free button: `padding: 6px 12px; font-size: 12px; border-radius: 8px; white-space: nowrap;`
This ensures high mobile conversion and immediate accessibility for returning users across all device sizes.
