deckhearth/.convoys
varutasu c2ebd18cf0
convoy: flip visual-diff to a hard merge gate (harden-visual-diff-gate brief 2/2) (#140)
Removes `continue-on-error: true` from `.github/workflows/visual-diff.yml`'s
`Capture screenshots (PR)` step. Visual drift is now a real merge gate
on UI-touching PRs.

Brief 2/2 of the `harden-visual-diff-gate` convoy. PR #138 shipped the
seed workflow (Brief 1); PR #139 (`54495fe`) landed the fresh Linux
baseline regenerated against post-glass-redesign main on CT 111. With a
known-good baseline committed, the gate can flip without false-failing
every UI-touching PR.

## What changes

- `.github/workflows/visual-diff.yml` — drop the
  `continue-on-error: true` flag; add an inline rationale block linking
  to the convoy + the operator runbook for both intentional changes
  (dispatch seed workflow → manually open PR → merge → re-run) and
  unintentional regressions (inspect artifact diff → fix → push).
- `.github/workflows/ci.yml` — add 9th `forbidden-patterns` check that
  greps `visual-diff.yml` for `^\s*continue-on-error:\s*true` and fails
  the build if it returns. Risk #3 of the convoy made concrete: prevents
  silent re-introduction via template revert. Scoped narrowly to that
  one file; other workflows (`seed-visual-baselines.yml`'s PR-open
  step, etc.) legitimately use the flag. Job name bumped from
  "Forbidden patterns (8 checks)" → "(9 checks)". All `Check N/8`
  group labels renumbered to `N/9`.
- `AGENTS.md` — § Testing § Visual baselines rewritten to drop the
  "Known staleness as of 2026-06-12" callout (resolved by PR #139);
  § Testing § Screenshot diff rewritten to lead with "hard merge gate",
  document the intentional-change runbook, reference the new ci.yml
  check, and explicitly mention the org-setting caveat for the seed
  workflow's auto-PR step.
- `tests/visual/homepage.spec.ts` — module docblock rewritten to match
  the AGENTS.md runbook: drops the "advisory, not gating" language;
  promotes the seed-visual-baselines workflow as the primary
  re-seeding path; demotes the Playwright Docker image to the offline
  fallback.
- `.github/workflows/seed-visual-baselines.yml` — patches the
  `peter-evans/create-pull-request@v6` PR-open failure case discovered
  during Brief 1's first dispatch (run 27454132468). The PR-open step
  is now `continue-on-error: true` (narrowly scoped, with an inline
  rationale callout distinguishing it from the just-removed
  `visual-diff.yml` flag — that one silently hid real UI regressions;
  this one fronts a known org-level "Allow GitHub Actions to create
  and approve pull requests" limitation with a loud failure notice).
  New steps disambiguate the three possible outcomes (no-changes /
  pr-opened / branch-pushed-pr-blocked) via a `git ls-remote` check on
  the bot branch and exit non-zero on the blocked-PR case so the
  workflow run shows red and the operator gets the exact `gh pr create`
  command in the run logs.
- `.convoys/harden-visual-diff-gate.md` — status: shipping; Step 2
  marked SHIPPED; Decision D4 ratified (chose option C: accept org
  setting, document manual `gh pr create` fallback). Inline links to
  PR #139 + PR #140.

## Test plan

- [x] `npm run lint` — clean (1 pre-existing unrelated warning)
- [x] `npm run test:run` — 24 files / 118 tests pass
- [ ] CI on this PR: 9th forbidden-patterns check passes; visual-diff
  job passes against the fresh baseline; convoy-metrics-gate passes
  (2 new rows added by this commit)
- [ ] After merge: smoke test the 9th check by opening a throwaway PR
  that re-adds `continue-on-error: true` to `visual-diff.yml`; confirm
  it red-X's. (Skip if confident in the grep.)

## Convoy state

- Brief 1: SHIPPED (PR #138, `c100c5f`, 2026-06-13)
- Baseline refresh: SHIPPED (PR #139, `54495fe`, 2026-06-13)
- Brief 2 (this PR): shipping
- Convoy closeout: this PR's merge

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-12 22:03:17 -05:00
..
add-rate-limiting feat(security): rate-limit search/upload/import + gate import routes (P0 #6 - closes last P0) 2026-05-24 22:59:59 -05:00
adopt-playwright-smoke feat(test): adopt @playwright/test + ship playwright.config.js + visual scaffold (P1 #10 step 2) 2026-05-24 19:25:18 -05:00
bump-next-js convoy(bump-next-js): plan + brief 1 (Decisions A-D) 2026-05-23 02:31:26 -05:00
cors-tighten fix(security): drop wildcard CORS + redundant OPTIONS from 24 API routes (P0 #5) 2026-05-24 20:41:38 -05:00
drop-public-setup architect(drop-public-setup): expand scope with brief 2 (CJS→ESM) 2026-05-23 17:02:44 -05:00
fix-auth-bypass docs: post-convoy cleanup for fix-auth-bypass 2026-05-23 12:22:50 -05:00
fix-layout-default-user fix(layout+pages): default user=null + page audit sweep (P0 #7) (#15) 2026-05-24 14:31:37 -05:00
fix-vercel-deployment-protection-in-ci fix(ci): plumb VERCEL_AUTOMATION_BYPASS_SECRET into preview-smoke + visual-diff (#17) 2026-05-24 16:26:22 -05:00
liquid-glass-design-tokens feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
pick-a-name feat(brand): unify on Deck Hearth across in-repo strings + infra (P1 brand decision) 2026-05-25 02:28:29 -05:00
redesign-scanner-flow test(scanner): cover redesign API and component surfaces (#47) 2026-05-27 14:28:04 -05:00
unify-glass-panel-surfaces docs(convoys): unify-glass-panel-surfaces + cleanup palette — conductor seed + architect plan (#119) 2026-06-04 14:09:40 -05:00
.metrics.jsonl convoy: flip visual-diff to a hard merge gate (harden-visual-diff-gate brief 2/2) (#140) 2026-06-12 22:03:17 -05:00
add-rate-limiting.md docs: post-convoy cleanup for add-rate-limiting — MILESTONE, last P0 closed 2026-05-24 23:09:07 -05:00
add-real-ocr-layer.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
adopt-playwright-smoke.md docs: post-convoy cleanup for adopt-playwright-smoke 2026-05-24 19:33:43 -05:00
bump-next-js.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
catalog-sync-vercel-cron.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
cleanup-card-item-list-and-share-modal-palette.md docs(convoys): close unify-glass-panel-surfaces + cleanup-card-item-list-and-share-modal-palette (#130) 2026-06-05 06:18:30 -05:00
cleanup-legacy-design-css.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
cleanup-mobile-nav-dead-props.md docs: post-convoy cleanup for 7-convoy 2026-05-26 wave (#33) 2026-05-26 23:15:21 -05:00
cors-tighten.md docs: post-convoy cleanup for cors-tighten 2026-05-24 20:49:30 -05:00
drop-public-setup.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
fix-auth-bypass.md docs: post-convoy cleanup for fix-auth-bypass 2026-05-23 12:22:50 -05:00
fix-layout-default-user.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
fix-reset-db-script.md docs: post-convoy cleanup for fix-reset-db-script 2026-05-26 22:10:13 -05:00
fix-vercel-deployment-protection-in-ci.md docs: post-convoy cleanup for fix-vercel-deployment-protection-in-ci 2026-05-24 16:32:45 -05:00
harden-visual-diff-gate.md convoy: flip visual-diff to a hard merge gate (harden-visual-diff-gate brief 2/2) (#140) 2026-06-12 22:03:17 -05:00
lint-against-cjs-in-esm-scripts.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
liquid-glass-card-surfaces.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-design-tokens.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-form-primitives.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-layout-shell.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-modal-and-surface-primitive.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-public-and-auth.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
liquid-glass-redesign.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
migrate-button-input-mobilenav-to-glass-primitive.md refactor(glass): migrate Button.secondary + Input + MobileNav off bespoke glass-surface (#131) 2026-06-05 06:23:55 -05:00
migrate-ci-to-self-hosted.md convoy: forbidden-pattern gate + AGENTS.md docs (briefs 3+4) (#133) 2026-06-06 00:18:21 -05:00
migration-tool.md docs: post-convoy cleanup for 7-convoy 2026-05-26 wave (#33) 2026-05-26 23:15:21 -05:00
motion-system-pass.md feat(design-system): Liquid Glass redesign portfolio — foundation + primitives + Layout (#95) 2026-06-03 20:12:33 -05:00
pick-a-name.md docs: post-convoy cleanup for pick-a-name — first post-P0 P1 convoy 2026-05-25 04:10:12 -05:00
purge-quick-login-from-loginpage.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
purge-weak-creds-from-helpers.md docs: post-convoy cleanup for 7-convoy 2026-05-26 wave (#33) 2026-05-26 23:15:21 -05:00
README.md bootstrap: agent pipeline v0.5.0 + ship-readiness review 2026-05-23 02:31:26 -05:00
redesign-scanner-flow.md docs(convoy): close redesign-scanner-flow post-PR audit 2026-05-27 14:09:50 -05:00
redesign-v2-from-mockups.md docs(convoys): mark redesign-v2-from-mockups epic shipped (8/8 sub-convoys merged) (#108) 2026-06-04 11:24:34 -05:00
rename-collections-vocabulary.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
scanner-correctness-polish.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
scanner-redesign-a11y-fixes.md Remove Quick Login + scanner a11y polish (#56) 2026-05-29 22:58:41 -05:00
scanner-user-cards-quantity-guard.md test(scanner): cover redesign API and component surfaces (#47) 2026-05-27 14:28:04 -05:00
secure-scanner-gemini-key.md fix(security): stop leaking Gemini API key to browsers (#34) 2026-05-27 08:41:48 -05:00
server-side-scan-pipeline.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
ship-readiness.md feat(design-system): finish Liquid Glass — close all remaining sub-convoys (#96) 2026-06-03 20:34:06 -05:00
single-auth-provider.md docs: post-convoy cleanup for 7-convoy 2026-05-26 wave (#33) 2026-05-26 23:15:21 -05:00
single-sql-client.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
test-scanner-redesign-surfaces.md chore(convoys): mark shipped convoys and refresh ship-readiness (#66) 2026-06-02 11:01:27 -05:00
tighten-visual-diff-path-filter.md docs: post-convoy cleanup for 7-convoy 2026-05-26 wave (#33) 2026-05-26 23:15:21 -05:00
unify-glass-panel-surfaces.md docs(convoys): close unify-glass-panel-surfaces + cleanup-card-item-list-and-share-modal-palette (#130) 2026-06-05 06:18:30 -05:00

Convoys

A convoy is a multi-PR work-stream coordinated by an agent pipeline. One convoy = one feature, bug fix, or epic. Each convoy is a Markdown file in this directory plus an optional sub-directory of implementer briefs.

File layout

.convoys/
├── README.md                              (this file)
├── <slug>.md                              (the convoy file — written by role-conductor)
└── <slug>/
    ├── brief-1-<kebab-title>.md           (written by role-architect)
    ├── brief-2-<kebab-title>.md
    └── ...

Convoy file format

Frontmatter (set by role-conductor, then appended-to by other roles):

---
name: <kebab-slug>
classification: feature | hotfix | docs-only | infra-only | server-only | config-only
success_metric: <one sentence>
skip:
  - <flag1>
status: open | in-progress | merged | shipped | abandoned
created: <YYYY-MM-DD>
---

Body sections (added in order by the pipeline roles):

  1. ## Why (Conductor)
  2. ## Scope (Conductor)
  3. ## Roles invoked (Conductor)
  4. ## Todos (Conductor → refined by Architect)
  5. ## IA (IA Architect)
  6. ## UX (UX Reviewer)
  7. ## Architecture (Architect)

After Architect, briefs live in .convoys/<slug>/brief-N-*.md. Implementers read only their brief, not the whole convoy.

Skip flags

The Conductor sets skip: based on classification. These flags map to pipeline stages that no-op when set:

Flag Skips
ia IA Architect
ux UX Reviewer
arch Architect
test Component tests
review Reviewer
visual Visual diff
a11y A11y auditor
design Design-system auditor
smoke Staging smoke
qa Manual QA
docs Doc Writer
flag Flag rollout

Never skipped (mandatory human gates): plan-approval, pr-merge, prod-promote.

Status lifecycle

  • open — Conductor created the convoy; no work started.
  • in-progress — At least one brief has an open or merged PR.
  • merged — All briefs merged to umbrella; release PR to develop pending.
  • shipped — Release to main complete; flag rollout (if any) underway.
  • abandoned — Convoy closed without shipping; reason in convoy body.

Update status by editing the convoy frontmatter as you progress.

Adding a new convoy

  1. Open Cursor in this repo.
  2. Prompt: "Start a new convoy: . Success = ."
  3. The role-conductor subagent writes .convoys/<slug>.md.
  4. Run subsequent roles in order per the convoy's Roles invoked list.

See .cursor/agents/role-conductor.md for the Conductor's full spec.

Multitask + worktrees (Cursor 3.2+)

Cursor 3.2 (Apr 24, 2026) added /multitask async subagents and native worktree management in the Agents Window. The pipeline uses both:

Audit fan-out — after an implementer ships a PR draft:

/multitask role-reviewer + role-design-system-auditor + role-a11y-auditor

All three read the same diff and emit independent comments. Use group id audit-<convoy>-<pr> so analytics can compute wall-clock savings.

Implementer fleet — after architect's plan is approved (gate 1), if slice_dependencies: declares parallel-safe briefs (depends_on: [], disjoint files:):

/multitask role-implementer briefs 1, 2, 3

Use Cursor's Agents Window to create a worktree per brief — one click each. The legacy scripts/wt.sh is now a deprecation stub.

See the multitask playbook for the full guardrail set.

Self-analytics

Each L2 role appends one event to .convoys/.metrics.jsonl via scripts/log-convoy-event.sh. The file is gitignored by default — events stay local. To opt-in to commit team-shared metrics, remove .convoys/.metrics.jsonl from .gitignore.

Aggregate across repos and render a dashboard with the agent-pipeline analytics scripts:

cd ~/code/agent-pipeline/analytics
npx tsx analyze-convoys.ts <repo-path> [<repo-path>...]
npx tsx render-dashboard.ts
open ~/agent-pipeline-data/dashboard.html

Schema: analytics/schemas/convoy-event.json.