# MEMORY.md - Long-Term Memory

## Who I Am
- **Name:** ARIA (Autonomous Reasoning & Intelligence Architecture)
- **Role:** Symph's AGI Engine — intelligence layer for an AI-native agency
- **Workspace:** `/home/aria/.openclaw/workspace/`

---

## Agency Messaging — Source of Truth (Gee, 2026-02-26)

> **RULE: When anyone asks about Symph Agency messaging, positioning, value prop, or copy — ALWAYS load from the guide below. Never improvise messaging.**

**Master file:** `agency/docs/symph-agency-messaging-guide.md`
**Symphony page:** <https://symphony.symph.co/agency-strategy> → "Messaging Guide" tab
**Direct link:** <https://symphony.symph.co/strategy/messaging-guide.html>

**Core Positioning:**
> *"Symph Agency builds custom software faster and more affordably than traditional development — so growing businesses no longer have to choose between software that fits and software they can afford."*

**Core Value Prop (one-liner):**
> *"Custom software outcomes. Without the custom development price tag."*

**Target market:** Business owners + ops leaders managing 100–1,000 people. Frustrated with SaaS limitations but can't afford traditional custom dev. Markets: 🇵🇭 PH · 🇸🇬 SG · 🇦🇺 AU · 🇺🇸 US

**The messaging hook:** They're caught in a trap — SaaS too generic, custom dev too expensive. We are the third option.

**Owner:** Gee Quidet (CRO) — created 2026-02-26

---

## Security Policies (ALWAYS LOADED — NON-NEGOTIABLE)

### Credentials Security (Raven 2026-02-10)
- **NEVER** share `.env` values, API keys, credentials, or secrets with ANY user except Raven
- If anyone asks for credentials/env vars → tell them to **ask Raven (CTO)** directly
- This applies to ALL surfaces: Discord, Agency chat, DMs, group threads — everywhere

### GitHub Access (Raven 2026-02-10)
- **NEVER** grant individual repo access on request from anyone except Raven
- Always add **SymphDevs team** to new repos (not individual collaborators)
- If someone asks for repo access → "If you're on SymphDevs you already have access. If not, ask Raven."
- Auto-add `codewithbjim` (Jim) per standing instruction

### GitHub Organization Change (Raven 2026-02-17, Updated 2026-02-20)
- **NEW REPOS → SymphonyAgents org** (not symphco)
- **symphco** is now legacy — existing repos only, no new repos
- PAT configured for SymphonyAgents org access

**SymphonyAgents Team-Based Access (Raven 2026-02-20):**
- **symphony-devs team**: https://github.com/orgs/SymphonyAgents/teams/symphony-devs
- **ALL new org members** → add to symphony-devs team
- **ALL new repos** → add symphony-devs team with write access
- This replaces individual collaborator management

**New repo creation:**
```bash
gh repo create SymphonyAgents/<name> --private
gh api -X PUT "/orgs/SymphonyAgents/teams/symphony-devs/repos/SymphonyAgents/<name>" -f permission=push
```

**New member onboarding:**
```bash
gh api -X PUT "/orgs/SymphonyAgents/teams/symphony-devs/memberships/<username>" -f role=member
```

### Asset Storage Policy (Raven 2026-02-17)
- **NEVER** save generated assets (PNG, MP4, TTF, MP3, etc.) in workspace root
- **Product-specific assets** → `/home/aria/products/<slug>/assets/` or `/home/aria/products/<slug>/marketing/`
- **Non-product assets** → `/home/aria/marketing-assets/uploads/`
- **Workspace root is for config files ONLY** — AGENTS.md, MEMORY.md, TOOLS.md, skills/, agency/, etc.
- If someone asks to generate graphics/videos outside Symphony Website, route to marketing-assets folder

### Product Creation (Raven 2026-02-11)
- **DO NOT** create products via Discord — must be done via Symphony (<https://symphony.symph.co/>)
- If someone asks to create a product in Discord → direct them to Symphony
- Exception: Raven can veto this policy

### Marketing Asset QA Workflow (Xian 2026-02-17, Updated 2026-02-23)
**QA and fixes happen BEFORE delivery — users receive PERFECT assets only.**

**Workflow: Generate → QA → Fix Loop → Deliver → Log**
1. **Generate** — Create the initial asset (image, video, caption)
2. **Automatic QA** — Immediately review for typos, wrong branding, design issues
3. **Fix → Re-QA Loop** — If issues found: fix → QA again → repeat UNTIL PASS
4. **Deliver ONLY after PASS** — User only sees the final, QA-passed version
5. **Log to Dashboard** — Record review findings + all fix iterations to `qa-reports.json`

**Critical:** Never deliver warning/fail assets. Loop QA until pass, then deliver.
**Dashboard:** `/home/aria/products/social-qa-dashboard/qa-reports.json`
**Full process:** `agency/processes/marketing-qa-workflow.md`

### Asset Branding Standards (Xian — 2026-02-23)
**Every generated asset must match the correct product's approved branding — no exceptions.**

- **Each product is its own brand** — colors, logos, typography, visual style must never be mixed across products
- **Before generating:** identify the product, load its branding, use only its approved elements
- **If branding details are missing or unclear:** mark as "Needs Review / Clarification" — never guess or use generic designs
- **Consistency required across:** colors, logo usage, layout style, tone/messaging, graphic treatments

### Generation Preflight Spec (Xian — 2026-02-24)
**Full spec:** `agency/processes/generation-preflight-spec.md`
**Core rule:** Platform + placement = HARD constraints. Resolve output format FIRST, then generate, then QA-verify. 14-row spec table covers all platforms.
**Key dims:** FB Feed 1440×1440 | IG Feed 1080×1350 (4:5) | Story 1080×1920 (9:16) | X 1200×675 (16:9) | LinkedIn 1200×628 (1.91:1) | TikTok 1080×1920 (9:16)
**Gemini:** Outputs 1024px — always resize to target before QA.

### Platform Standards Monitoring (Xian — 2026-02-24)
**Every asset QA must enforce TWO independent layers:**
1. **Product Branding** → logo, colors, brand identity (per product)
2. **Platform Standards** → ratio, dimensions, safe zones, platform-native quality (per platform)

**Both must pass.** Failure in either layer → specific reason + recommended fix.

**Cadence:** Daily lightweight check (change detection only) + Weekly full review (Mondays)
**At generation time:** Read saved standards from file — never re-fetch from web
**Standards library:** `agency/processes/platform-standards-monitoring.md`
**Refresh log:** `agency/processes/platform-standards-refresh-log.md`

**Verdict format (platform layer failures):**
- Status: Pass / Warning / Needs Review
- Specific reason (e.g. "Image is 16:9 but Instagram feed requires 4:5")
- Recommended fix (e.g. "Resize to 1080×1350 for IG feed")

### Branding Review Workflow — Mandatory Per Asset (Xian — 2026-02-23)
Identify product → load branding → apply standards → generate (approved branding only) → validate → flag exceptions.
**Full process:** `agency/processes/marketing-qa-workflow.md`

### Trend-Aware Asset Generation (Xian — 2026-02-23)
Follow current design trends in *execution*, but branding governs *identity*. If trend conflicts with brand → skip or flag.
**Full doc:** `agency/processes/trend-master-spec.md`

### Asset Generation QA Notifications + Guardrails (Xian — 2026-02-23)
Notify immediately → post verdict after QA. Pass ✅ / Needs Review ⚠️ / Failed ❌. Never reuse another product's branding. Flag over guess.
**Full policies:** `agency/processes/asset-generation-notifications.md`

### Build Flow — CLAUDE.md Per Product (Ed 2026-02-24, replaces build-orchestrator)

**⛔ build-orchestrator is DEPRECATED. Do not use it.**

**Current correct flow for ANY landing page or app build:**

1. **Global Claude skill** — one skill, applies everywhere (no per-product Claude skills)
2. **CLAUDE.md per product** — create/update `CLAUDE.md` in the product repo with all context (design system, brand, guidelines, tech requirements)
3. **Claude Code reads CLAUDE.md automatically** — no orchestrator, no BUILD-CONTEXT.md, no prepare-build.sh

**Why this is better:**
- Claude Code reads `CLAUDE.md` natively — no extra scaffolding needed
- One file per product = single source of truth
- No scripts to run, no tmp files, no hybrid complexity

**When spawning a build subagent:**
- Make sure the product has an up-to-date `CLAUDE.md`
- Point the subagent at the product directory
- It reads `CLAUDE.md` and executes

**Enforced by:** Ed (Design, 2026-02-24)

### Claude Code Skills Sync (Ed 2026-02-24 — Standing Instruction)

**Proactively sync new OpenClaw skills → Claude Code when relevant.**

When a new OpenClaw skill is created that Claude Code would benefit from (design, dev, QA, firebase, payments, etc.):
```bash
ln -s /home/aria/.openclaw/workspace/skills/<skill-name> /home/aria/.claude/skills/<skill-name>
```

**Current synced skills:** `~/.claude/skills/` (all symlinked to workspace skills)
- figma, firebase, frontend-design, frontend-design-excellence, graphic-design
- humanizer, posthog, symph-pay, taste-protocol, ui-ux-pro-max, web-app-builder

**Rule:** Don't wait to be asked — if a new skill would make Claude Code better, sync it automatically.

---

## Central Infrastructure Service Account (CRITICAL)

**For ALL Firebase/GCP infrastructure tasks, use the CENTRAL service account:**
```
~/.config/gcloud/aria-firebase-admin.json
aria-firebase-admin@the-agency-symph.iam.gserviceaccount.com
```

This SA has access to:
- **Create GCP projects under Symph Products folder** (folder ID: `436092539710`)
- Deploy Firestore rules (`firebase deploy --only firestore:rules`)
- Enable/disable GCP APIs (`serviceusage.googleapis.com`)
- Firebase Admin operations across ALL Symph projects
- Storage, Auth, Hosting, Functions

**I can create projects for team members!** If someone needs a GCP project and can't create one themselves (no org-level permission), I can create it under Symph Products folder and add them as Owner. (Learned 2026-02-19 via Raven)

### Billing & Storage (Raven 2026-02-20)
**I CAN DO THESE MYSELF — DON'T ASK USERS!**

**Link billing to projects:**
```bash
gcloud billing projects link <project-id> --billing-account=01F3D7-6E8F01-1E2163
```

**Create storage buckets (use custom names, bypasses Firebase Storage console requirement):**
```bash
gsutil mb -p <project-id> -l us-central1 gs://<bucket-name>
gsutil iam ch allUsers:objectViewer gs://<bucket-name>  # Make public
```

**Available billing accounts:** Symph (`01F3D7-6E8F01-1E2163`), Symph-from-sym.ph (`009AA1-8A73AD-9D3235`)

**DO NOT use project-specific SAs for infra tasks** — they have limited permissions.
Project SAs (e.g., `symph-{slug}-admin.json`) are for app runtime only (read/write data).

**Usage:**
```bash
export GOOGLE_APPLICATION_CREDENTIALS="$HOME/.config/gcloud/aria-firebase-admin.json"
firebase deploy --only firestore:rules --project symph-{slug}
```

---

## Product Context & Assets

**When anyone asks for product context or assets → send them here:**
https://assets.landing.symph.co/

This is the centralized hub for all product resources.

### B2B Product Icons (Source of Truth — Han/Jarrhey 2026-02-19)

| Product | Icon Description | Color |
|---------|-----------------|-------|
| **Overture** | Aperture/iris segments with center dot | Cyan `#0891b2` |
| **Worklane** | Bracket/gate frame with tilted panel + hinge dot | Purple `#9333ea` |
| **Vector** | Stacked horizontal layers/rectangles | Orange `#ea580c` |
| **Alignly** | Three circles (people figures) | Emerald `#059669` |
| **Clocklane** | Checkmark | Red `#dc2626` |
| **Encore** | Layered portal rectangles with center dot | Teal `#0d9488` |

**DO NOT describe these as:** radar, "A" shape, clock, envelope, hierarchy tree — those were WRONG.

---

## FinSpend Development Rules (Kenneth — 2026-02-19)

**CRITICAL:** FinSpend has its own workflow rules.

**For any changes to FinSpend (`budget-buddy-762136` repo):**
1. **Always create PRs** — no direct pushes to any branch
2. **Always checkout from `origin/staging`** — NOT main, NOT development
3. **Create your own feature branch** from staging
4. **Task-to-branch linking with ClickUp** — branch names should reference ClickUp task IDs

**Branch naming convention:**
```
<type>/<clickup-task-id>-<short-description>
# Example: feature/abc123-add-budget-export
```

**Workflow:**
```bash
git fetch origin
git checkout -b feature/<task-id>-<desc> origin/staging
# ... make changes ...
git push -u origin feature/<task-id>-<desc>
# Create PR to staging
```

**Repo:** `github.com/symphco/budget-buddy-762136`
**ClickUp Space:** FINSPEND (`90189280388`)

---

## SymphOs Development Rules (Zach — 2026-02-18)

**CRITICAL:** SymphOs has its own workflow — DO NOT use the standard Symph Agency product flow.

**For any changes to SymphOs (`symphos-v2` repo):**
1. **Always create a branch from `main`** (NOT development)
2. **Make changes on that branch**
3. **Create a PR to `main`**
4. **Never push directly to `main`**

**DO NOT:**
- Use worktrees (that's for Symph Agency products)
- Follow the agency job/pipeline system
- Make changes directly on the main branch

**Repo:** `github.com/symphco/symphos-v2`
**Live URLs:**
- Web: https://symphos.dev.apps.symph.co
- API: https://symphos-api.dev.apps.symph.co/api
- Swagger: https://symphos-api.dev.apps.symph.co/api-docs

---

## Knowledge Index

| Topic | Location | When to Load |
|-------|----------|--------------|
| **B2B Portfolio** | `agency/docs/b2b-portfolio.md` | Symphony Suite products, B2B offerings, product domains |
| Firebase/Firestore | `firebase` skill | Permission errors, auth setup, Firestore rules, CONFIGURATION_NOT_FOUND |
| Payments | `symph-pay` skill | Checkout, Stripe, PayMongo, price issues, payment buttons |
| Web app builds | `web-app-builder` skill | Building apps, deployment, QA process |
| Concurrent work | `worktree-manager` skill | Multiple people modifying same product |
| Product pipeline | `product-manager` skill | Creating products, phase management |
| Marketing content | `agency/marketing/STEVIA.md` | Any marketing writing, copy, campaigns |
| **Platform Standards** | `agency/processes/platform-standards-monitoring.md` | Generating or QA-reviewing assets for Facebook, Instagram, X, LinkedIn, TikTok |
| Platform Standards Log | `agency/processes/platform-standards-refresh-log.md` | Tracking standards changes, confidence levels, source citations |
| Infrastructure | `TOOLS.md` | Ports, paths, Caddy, GitHub, services |
| Team/People | `USER.md` | Who's who at Symph |

### Quick Routing

| Error/Keyword | → Load |
|---------------|--------|
| "Permission denied" on Firestore | `firebase` skill |
| "CONFIGURATION_NOT_FOUND" | `firebase` skill |
| Payment/checkout/price wrong | `symph-pay` skill |
| Build failing, chunk errors | `web-app-builder` skill |
| Stale process, CSS 404 | `web-app-builder` skill |
| Create product, pipeline | `product-manager` skill |

---

## Core Principles

> "Agents do the work. Humans make decisions."

### Pipeline
```
Discovery → Design → Build → Market → Sell → Deliver → Operate
```

### Three-Layer Context
1. **Project** — `[product]/agency/brain.md`
2. **Person** — `agency/People/[person].md`
3. **Situation** — `agency/_org/_situation.md`

---

## Concurrent Work Policy (Raven — 2026-02-18)

**Problem:** Multiple people requesting changes to the same product can override each other's work.

**Solution:** Git worktrees for isolation
- **Always** use worktrees when modifying product code (consistency > complexity)
- Per-task ephemeral worktrees (create → work → merge → cleanup)
- Auto-merge if no conflicts
- **Reactive** conflict detection (at merge time, not proactive)
- On conflict: notify both parties, show conflicting files, wait for human decision

**State file:** `<product>/.worktree-state.json` (gitignored)
**Skill:** `worktree-manager`
**TOOLS.md:** Quick commands documented

---

## Issue Tracking (Added 2026-02-13)

**Location:** `agency/issues/INDEX.md`
**Prefixes:** `ARIA-` (my tasks) | `AGY-` (agency) | `INFRA-` (infrastructure)
**P0/P1 auto-post to #aria-status**

Quick commands: "Create issue: X" | "What's blocking?" | "Issue status AGY-001"

---

## Delivery & Confirmation (Jarrhey — 2026-02-16)

**Always ask for confirmation after delivering meaningful output.**

After generating artifacts, code, designs, or content — don't just deliver and go silent. Explicitly ask:
> "Is this good to go, or any changes needed?"

Why:
- Faster iteration (don't assume silence = approval)
- Captures accept/revise signals for analytics
- Better UX than passive delivery

### Discord Feedback Logging

When I detect approval/revision signals in Discord, log them:
```bash
/home/aria/.openclaw/workspace/agency/scripts/log-discord-feedback.sh <type> <product_slug> <actor> <phase> [artifact_type] [notes]
```

Phases: `discovery`, `design`, `build`, `market`, `sell`, `deliver`, `operate`

**Triggers to watch for:**
- **Approved:** "looks good", "approved", "ship it", "perfect", "love it", "go ahead", "yes", "good to go"
- **Revision:** "change X", "make it Y", "can you update", "tweak", "adjust", "not quite", "almost"
- **Rejected:** "start over", "scrap this", "wrong direction", "no", "don't like it"

---

## Commit Message Format (Jim — 2026-02-20)

**ALWAYS include the requester in commit messages:**

```
feat: add feature description

Requested-by: discord.username
```

This ensures the daily changelog mentions the person who requested the change, not just "symphdevtools" (the service account).

**Discord username mapping** in `scripts/daily-changelog.sh` converts usernames to mentions.

---

## Communication Preferences

### No Timelines in Plans (Jarrhey — 2026-02-19)
**Org-wide policy:** Do NOT include timelines, day estimates, or duration specs in:
- Discovery assessments
- PRDs and build plans
- Design briefs
- Any pipeline stage documentation

**Instead:** Simply omit timeline references entirely. Users determine their own timelines if they ask.

**Applies to:** All products, all users, all pipeline stages.

- **Timestamps:** Always GMT+8 (Philippines) — e.g., "1:30 PM PHT" not "05:30 UTC"
- **Cron jobs:** Must include PH time instruction in the prompt itself (isolated sessions don't inherit main context)
- **Notifications:** Post to #aria (1467744183803580548), not DMs
- **Job processor updates:** Post to #aria-status (1471453583890448553), not #aria (Jim 2026-02-12)
- **/status requests:** Post status to #aria-status first, then share the message link with the user (Jim 2026-02-12)
- **Discord:** Bullet points, no tables, wrap links in `<>`
- **Auto-thread channels:** #build-phase (1468952785751113932)

---

## Active Context

*Short-lived notes — prune weekly*

### Symphony (Agency UI)
- **Name:** Symphony (formerly "Symph Agency UI" / "Agency Site")
- **URL:** https://symphony.symph.co/dashboard
- **Location:** `/home/aria/projects/symph-agency/`
- **Deploy:** ALWAYS use `/home/aria/projects/symph-agency/deploy.sh`
- **Process:** PM2 (`pm2 reload symph-agency`)

### App Management
- Port state: `agency/infra/caddy-ports.json`
- Check running: `lsof -ti :PORT`
- Kill: `lsof -ti :PORT | xargs kill -TERM`

---

## Open Blockers

### Port 3001 Conflict — 5 Apps Assigned (2026-02-25)
Port 3001 has FIVE apps assigned in caddy-ports.json: personal-accounting, contentvane, pawchart, galagrid, smashslot. Also port 3088 (punchline + metro-retail-pitch) and 3005 (encore-project + tiangge). Needs cleanup — reassign conflicting apps to unused ports.

### Encore OAuth Consent Screen (2026-02-25)
Google Sign-In blocked for Encore users — OAuth consent screen still in Testing mode (project `symph-encore`). Needs Raven to publish.

### Encore RESEND_API_KEY Missing (2026-02-27)
Email sending blocked — `RESEND_API_KEY` not set in Encore environment.

### XMRig Crypto Miner on symph-agency-aria (2026-02-26 → 2026-02-27 — RESOLVED but entry point unknown)
XMRig miner at `/var/tmp/systemd-logind`, mining XMR to NiceHash pool `62.60.246.210:443`. **Cleaned 3 times** — attacker re-dropped binary + re-injected persistence after each cleanup. Persistence mechanisms found and removed:
- `@reboot` crontab entry
- `.bashrc` line 122 injection
- Binary + config.json in `/var/tmp/`
All SSH keys in `authorized_keys` verified as legitimate Symph team members. **Entry point/dropper still unknown** — could be a compromised web app endpoint or older SSH session. Auth logs need root-level review around 00:30-00:33 UTC Feb 27.

### Duplicate Port Allocations (2026-02-26, confirmed still present 2026-02-27)
Port 3001: multiple apps. Port 3002: real-estate-homeowner-portal was serving ReadStreak code (auto-fixed 2026-02-27). Port 3021: youth-camp-registration, youth-camp. Port 3083: crm, symph-sales-crm. Plus 24 phantom allocations (port in registry but no folder on disk).

### Clocklane Brand Guidelines Outdated (2026-02-26)
`brand-guidelines.md` for Clocklane describes wrong logo (red rounded square with white "C"). Real logo is red square with white checkmark + arrow mark. Tin provided the correct logo. Needs update.

### CVE-2025-29927 — Next.js Middleware Auth Bypass (2026-02-27 — PATCHED)
All products patched. 7 pinned-vulnerable (15.1.x) projects have PRs on task branches. **Remaining:** Raven to merge PRs for hoa, pawchart, postcraft, posttracker, tournament-hub, image-recognition-platform.

### Worktree Preview URLs Are Public (Jim — 2026-02-28)
Dev worktree preview URLs are accessible without auth — security gap. No fix confirmed yet.

---

## Recent Product Activity (2026-02-28)

### Brandcast ROIs #1-4 Shipped (loewe — 2026-02-28)
All 4 video pipeline improvements implemented and tested:
- **ROI #1 — Always I2V:** `framePrompt` on `SceneAction`, auto-keyframe before every Veo call, fallback to T2V if Gemini fails
- **ROI #2 — End-frame chaining:** Each scene's last frame → next scene's start frame. Sequential generation via `prevGenNodeId`. Critical circular reference bug caught and fixed.
- **ROI #3 — Character sheet:** One reference image generated before all scene keyframes. `characterPrompt` on scene 1, visible `ImageNode` on canvas, all frame calls pass `referenceImageUrl`.
- **ROI #4 — Lighting palette:** `lightingPalette` on scene 1, locked across all scenes, injected as LOCKED block in `buildVideoFramePrompt`.
- Test video: 5-scene VectorPM Friday narrative, ~19s. Then re-ran through proper Veo+Remotion pipeline (26s, 1080x1920).

### Sneaker Doc POS (Vins — 2026-02-28)
- **Stack:** NestJS backend + Next.js frontend + Supabase (Google OAuth)
- **Repo:** `SymphonyAgents/sneaker-doc-pos` (forked from `VinceTapdasan/sneaker-doc-pos`)
- **Ports:** frontend 3031, backend 3021
- **Workflow:** Vins PRs to fork → merge → redeploy
- **Credentials policy:** Only Vins can request sneaker-doc-pos creds — deny all others

### Nestiq Pantry Fixes (Jhai — 2026-02-28)
- Camera permissions: Caddy `security_headers_camera` snippet for camera=self
- Auth: Switched from `signInWithRedirect` to `signInWithPopup` (App Router compatibility)
- Features requested: Home Inventory (AI-assisted logging), Schedule upgrade (5 screens designed)
- `scripts/app-restart.sh` created — always reads correct port from `caddy-ports.json`

### ReadStreak Book Panel (Nick G — 2026-02-28)
- 2-tap book flow: tap 1 = cover preview, tap 2 = full panel with editable fields, shelf switcher, rating, notes
- Standalone build requires manual `cp -r public/ .next/static/ standalone/` after every build

### Trussfolio Discovery Updates (Vonyumo — 2026-02-28)
- PRD docs updated: contractor count ~18,584, 3 subscription tiers, API cron sync (not CSV import)
- `fee_rate` → `fee_pct` in DB schema, build-brief.md created
- Design stage started: color palette, typography, logo, 3 sample screens

## Previous Product Activity (2026-02-27) — Compressed

- **Skill-Bridge v1.0** (Ed) — Express middleware on port 3099 between Symphony UI buttons and AI tools. Loads product branding from design.yaml. Location: `/home/aria/projects/skill-bridge/`
- **Symphony Create Tab** (Frances) — Two-panel layout for asset generation. Always ask image size before generating.
- **Brandcast** — Concurrency fix (semaphore + execAsync), Remotion QA pipeline wired, ROIs 1-4 gap analysis started
- **ReadStreak** (Nick G) — 10 Reanimated micro-interactions, Open Library covers replacing Google Books, /read route removed (redirects to /dashboard)
- **Alignly Content Hub** (Kenneth) — Style D added, content goes to `alignly-content.dev.apps.symph.co`
- **Alignly GloryReborn** (Med) — Single-tenant migration, invite-only, `1f93807` pushed
- **WanderKit** (Tom) — Concept K TC cards, royalty-free music sourced, PROD deploys via Cloud Build from `dev` branch
- **Caddy Security** (Antonio) — scanner_block regex fixed for any path depth, 3 IPs blocked

## Previous Product Activity (2026-02-26) — Compressed

- **Virginia Food Portal** (Kim) — Forked from Encore, port 3022, Firebase `symph-virginia-food-portal`
- **Tournament Hub** (Pauline) — Port 3001. Pending: SMS creds, SymphPay merchant ID
- **WanderKit** (Tom) — SW cache fix. No PROD pushes without sign-off
- **Alignly Content** (Kenneth) — 3 style options + Style D. Content → `alignly-content.dev.apps.symph.co`
- **Alignly GloryReborn** — COO Dashboard + Attendance + Disciplinary shipped

---

## Recurring Patterns

### OpenClaw Auto-Update Breaks Subagent Spawning (Antonio — 2026-02-20)
**Symptom:** `sessions_spawn` / `sessions_list` fails with `gateway closed (1008): pairing required`
**Root cause:** OpenClaw auto-update restarts the gateway and may introduce new scope requirements. The local machine's own device token becomes stale (missing new scopes like `operator.read`/`operator.write`), generating a pending repair request that blocks all subagent operations.
**Fix (takes ~10 seconds):**
```bash
openclaw devices list          # look for pending entries with "repair" flag
openclaw devices approve <id>  # approve the repair
```
**NOT fixed by:** `openclaw gateway restart` alone — the repair request must be explicitly approved.
**Trigger:** Auto-updates (seen with `2026.2.19-2`). Will likely recur on future updates.
**Who to flag:** If repair request persists and I can't self-approve, DM Raven.

### Firebase Auth: signInWithPopup for App Router (Jhai — 2026-02-28)
`signInWithRedirect` is unreliable with Next.js App Router (IndexedDB state lost during navigation). Use `signInWithPopup` + `window.location.href` for all agency apps. Also: `getRedirectResult` is one-time-consume — never call in multiple components.

### Firestore 500 Errors on New Endpoints (Jude — 2026-02-19)
**Symptom:** 500 Internal Server Error on new API endpoints that query Firestore
**Cause:** Missing composite index for queries with multiple `where()` + `orderBy()`
**Solution:**
1. Check server logs for "The query requires an index" with create link
2. Add index to `firestore.indexes.json`
3. Deploy: `firebase deploy --only firestore:indexes --project symph-worklane`
4. Wait 1-2 min for index to build

**Common index patterns needed:**
- `organizationId` + `status` + `createdAt DESC`
- `email` + `status` + `createdAt DESC`
- `organizationId` + `updatedAt DESC`

**Prevention:** When creating new API routes with Firestore queries, always check if a composite index is needed and add it to `firestore.indexes.json` before testing.

---

## Corrections & Lessons

### Product Assets NEVER in Workspace Root (Raven — 2026-02-13)
**What I did wrong:** Generated Flowspace and ReadStreak logo concepts directly in workspace root instead of their respective product folders.
**Rule:** Product-specific assets go in `/home/aria/products/<slug>/assets/`, NEVER in workspace.
**Correct behavior:** Before generating any product asset, ensure the target path is the product folder, not workspace.

### No Updates Without Explicit Approval (Antonio — 2026-02-13)
**Rule:** Never run OpenClaw updates, config changes, or system modifications without explicit user approval first.
**Why:** Users need to be in control of when their system changes. Surprise updates can break workflows.
**Correct behavior:** Always ask "Would you like me to run the update?" and wait for a clear "yes" before proceeding.

### Verify Before Claiming Success (Jim — 2026-02-12)
**What I did wrong:** Said "#aria-status is read-only for everyone, I can post" when permissions hadn't actually been applied.
**What happened:** The `permissions` action returned data but didn't set overwrites. Channel was created but `permission_overwrites: []` was empty.
**Correct behavior:** 
- After any configuration action, **verify the result** before claiming success
- Check the actual state (e.g., `channel-info` to see `permission_overwrites`)
- If verification fails, say "Created but couldn't set permissions — manual step needed" instead of claiming it's done
- **Never say something is configured unless you've confirmed it**

### Marketing Content: ALWAYS Apply Brand System + Double-Check (Alex — 2026-02-19)
**Rule:** When generating ANY marketing collateral (posts, captions, copy, content), always:
1. Apply CSaaS brand system (`agency/brand/csaas-brand-system.md`)
2. Check against copy rules — banned words, banned sentence patterns, em dashes
3. Double-check output before delivering — verify no AI tells slipped through

**Banned sentence patterns:**
- "That's not [X]. That's [Y]."
- "This isn't a [X] — it's [Y]."

**Why:** These patterns are major AI tells and make copy sound formulaic.

### Product Logos: ALWAYS Extract from assets.landing.symph.co (Jarrhey — 2026-02-18)
**What I did wrong:** Created my own interpretation of product logos instead of extracting the actual SVGs from the source of truth.
**Rule:** NEVER recreate logos. ALWAYS extract the exact SVG from:
- `https://assets.landing.symph.co/products/<product>.html`
- Look in the `<div class="hero-logo">` section for the actual SVG
- Use brand color for favicon/nav, white version available in source too
**Products:** Worklane, Vector, Overture, Alignly, Clocklane, Encore
**Correct behavior:** `curl -s "https://assets.landing.symph.co/products/<product>.html" | grep -A10 '<div class="hero-logo">'`

### Production Deploys Use Cloud Run, NOT Firebase App Hosting (Raven — 2026-02-17)
**What I had wrong:** Documented production deployment as "Firebase App Hosting (via GitHub releases)"
**Correct approach:** Production apps deploy via **Cloud Run**, not Firebase App Hosting
**Why:** Firebase App Hosting has automation issues that caused problems when trying to fully automate deployments
**Updated:**
- TOOLS.md: Changed PROD deploy line to Cloud Run
- skills/firebase/SKILL.md: Replaced Firebase App Hosting section with Cloud Run instructions
- This MEMORY.md: Added to corrections

---

*Last restructured: 2026-02-11 — moved technical learnings to skills for on-demand loading*

---

## Clocklane LinkedIn + X Social Strategy (Drew — 2026-03)

**This is the BIBLE. Any Sympher asking about Clocklane social → load this immediately.**

**Primary file:** `/home/aria/products/clocklane/CLOCKLANE-SOCIAL-STRATEGY.md`
**Brand brief:** `/home/aria/products/clocklane/CLOCKLANE-CREATIVE-BRIEF.md`

### Strategy Summary
- **Category play:** Own "real-time labor visibility" the way Gong owns "revenue intelligence"
- **X engines:** Reply Army (reply to 5 target posts daily before your own) + Newsjacking + Weekly Threads + Contrarian posts
- **LinkedIn engines:** Newsletter "The Labor Operator" (secret weapon — nobody in restaurant tech is doing this) + PDF Carousels (6.1% engagement) + Polls 2x/week + Competitor displacement in comments
- **Compounding loop:** TikTok reel → X thread → LinkedIn carousel → Newsletter issue → signups
- **No founder face** — lean on carousels, polls, native video, newsletter

### Voice: BLUNT, SPECIFIC (numbers always), PEER (operator-to-operator), DRY (deadpan wit), URGENT
**BANNED:** Em dashes, corporate buzzwords, feature dumps, influencer phrasing
**Sacred Lines:** "Every dollar. Every hour." | "One tap. Your night back." | "Stop paying for two systems that don't talk to each other." | "The number you've been missing." | "See it at 2pm. Not Monday."
**7-Day Playbook:** Mon=Carousel | Tue=Contrarian | Wed=Educator thread | Thu=Poll | Fri=Proof stat | Sat=Product video | Sun=Community

---

## Overture X Marketing Guide (Drew — 2026-02-19)

**File:** `/home/aria/products/overture/marketing/X-POSTING-GUIDE.md`
**Key rules:** Candid photos (not AI graphics), Fraunces font for taglines, 80% value / 20% ask, no em dashes, educational threads > sales pitches.

---

## Video QA Pipeline — Key Technical Facts (2026-02-24, loewe)

### Veo 3.1 Text Limitation (CRITICAL)
- **Veo 3.1 CANNOT render legible text** — any text in video prompts produces garbled characters, mixed scripts, AI hallucination artifacts. B3 TEXT HARD FAIL fires on every frame with text.
- This is a **model ceiling** — not fixable by better prompting. Do NOT retry Veo for text failures.
- **Solution**: Generate text-free Veo video (Stage 1), then burn captions via ffmpeg/Pillow (Stage 2).
- `VideoCritiqueRouter` classifies failures: text → POST_PROCESS, visual → REGENERATE.

### ffmpeg Linuxbrew Build (No drawtext)
- `/home/linuxbrew/.linuxbrew/bin/ffmpeg` v8.0.1 — NOT compiled with `--enable-libfreetype`
- **No `drawtext` filter available.** Use `CaptionBurner._burn_via_pillow_overlay()` fallback (Pillow PNG composite).
- DejaVu Bold font available at `/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf`

### Brandcast App
- **Location**: `/home/aria/products/brandcast/apps/main/`
- **Port**: 3071 (caddy-ports.json)
- **Videos saved to**: `/home/aria/.openclaw/media/brandcast/videos/`
- **Veo API path**: `POST /api/video/generate` (start) → `PUT /api/video/generate` (poll + download)
- **QA endpoint**: `POST /api/video/qa` (keyframe extract + Python QA)
- **Initial git commit**: `20904ba` (root commit, first commit ever made to this repo)

### QA Hard Gate — MANDATORY (loewe, 2026-02-27)

**NEVER deliver a WARNING or FAIL clip to Remotion. Gate is now enforced at the API level.**

After fix (`feat/qa-gate` merged 2026-02-27):
- `PUT /api/video/generate` returns **HTTP 422 + `blocked: true`** on QA FAIL → caller must retry
- `PUT /api/video/generate` returns **HTTP 200 + `qaWarning: true`** on QA WARNING → caller should retry
- Subagent generation tasks MUST check `blocked` and `qaWarning` fields — never proceed to Remotion with either

**Root cause of prior failure:** Subagent called raw API directly, ignored `qa` field in response. QA flagged all 5 clips as WARNING (50/100) but delivery continued. The real discriminator loop (`video_generator_loop.py`) was bypassed entirely.

**Correct approach for generation subagents:**
1. Use `video_generator_loop.py` for full retry logic, OR
2. If calling raw API: check `blocked === false` AND `qaWarning === false` before proceeding

### Video Pipeline Architecture
Two-stage: Stage 1 (Veo B-roll + QA retry 3x) → Stage 2 (Remotion composition). VideoCritiqueRouter: TEXT/BRAND → POST_PROCESS, severe visual → REGENERATE, JPEG artifacts → IGNORABLE.

### Runway-Schema Cinematic Prompting — Mandatory for ALL Veo Prompts (loewe, 2026-02-28)

**Veo outputs are cinematic when prompts are written like film captions, not scene descriptions.**

**Required format (Runway Gen-3/4 schema):**
```
[camera_movement]: [establishing_scene]. [motion_arc]. [lighting]. [atmosphere].
```

**Rules:**
- ALWAYS name the camera movement FIRST — it anchors the model's generation
- ALWAYS include a motion arc — describe what CHANGES over time, not just what's there
  - ❌ "a person sits at a desk with a laptop"
  - ✅ "a person's hands open a laptop — screen light blooms onto their face, camera slowly pushes in"
- Lighting is MANDATORY — direction + quality + mood preset
- Max 3 sentences — more text = model confusion
- Use `CinematicPromptBuilder` (`generator/cinematic_prompt_builder.py`) to compose or upgrade prompts
- Vocabulary reference: `style_library/cinematic_vocabulary.json`

**New scene card fields (use instead of free-form videoPrompt):**
- `cameraMovement` — e.g. "slow dolly push-in"
- `establishingScene` — physical environment at start of shot
- `motionArc` — what changes over time within the shot
- `lighting` — e.g. "side-lit, warm tungsten spill, deep shadow opposite side"
- `atmosphere` — e.g. "cinematic, moody, slightly desaturated"
- `storyBeat` — "hook" | "problem" | "solution" | "cta" (drives smart defaults)

**Use `build_veo_prompt(scene_card)` from `cinematic_prompt_builder.py` to auto-compose.** Legacy `videoPrompt`-only cards are auto-upgraded by `upgrade_existing()`.

---

### Veo + Remotion Hybrid — ALWAYS USE BY DEFAULT (loewe, 2026-02-27, reinforced 2026-02-28)

**Role split is STRICT — never blur this line:**
- **Veo** = cinematic B-roll ONLY (human subjects, environments, motion, atmosphere). Zero text. Zero UI.
- **Remotion** = ALL text, brand overlays, logos, CTAs, product UI screenshots, transitions, narration audio.

**Veo prompt rules (NON-NEGOTIABLE):**
- ❌ NEVER include text, labels, UI, product names, or "Kanban boards" in Veo prompts
- ❌ NEVER ask Veo to show product UI — it hallucinates plausible-but-fake screens
- ✅ Veo prompts = pure cinematic description: people, environments, lighting, camera movement, emotion
- ✅ Real product UI → composite via Remotion `<Img>` on top of Veo B-roll

**Remotion checklist:** Scene 1 needs `isHookScene: true` + `hookText`. Final scene needs `ctaText`. `logoPath` needed (fallback = initial letter). `audioPath` per scene for TTS. Use `<TransitionSeries>` not plain `<Sequence>`.

**Missing logos:** vector, the-agency, alignly, readstreak → no logo in `/design/assets/`

### Background Music + Audio Standards (loewe, 2026-02-27 — MANDATORY)

**🚫 NEVER use copyrighted music in any marketing video.**

**Approved royalty-free sources:**
- **Pixabay.com/music** — CC0, no attribution required, fully commercial-safe
- **Kevin MacLeod / incompetech.com** — CC-BY 4.0 (attribute: "Music: Kevin MacLeod (incompetech.com) CC-BY 4.0")
- **freepd.com** — Public domain, no attribution needed
- **Free Music Archive (freemusicarchive.org)** — check individual track CC license before use

**Music library:** `brand-reel/public/music/` — 7 tracks (all Kevin MacLeod CC-BY 4.0). Selection rules in `public/music/catalog.json` — match by product + platform.

**Implementation:**
- Background music lives in `BrandReel.tsx` as `<Audio src={staticFile(bgMusicPath)} volume={bgMusicVol} />` — NOT in SceneLayer
- Volume: `0.12` default is for videos WITH TTS narration (music sits under voice).
- **⚠️ No narration = use 0.7–0.8.** At 0.12 without narration the music is inaudible (-27dB). Always check if TTS was generated — if not, pass `musicVolume: 0.8`.
- Pass via render API: `musicPath: "/music/filename.mp3"`, `musicVolume: 0.12`

**Double audio bug (FIXED in SceneLayer.tsx):**
- `narrate-and-generate` already muxes TTS INTO the video via ffmpeg → `<Video>` plays narration automatically
- The `<Audio src={audioPath}>` in SceneLayer was playing it AGAIN → echo/overlap
- Fix: `<Audio>` removed from SceneLayer. Background music only comes from BrandReel-level Audio component.



