deckhearth/.convoys
Randall Stillwell d640795959 docs: post-convoy cleanup for pick-a-name — first post-P0 P1 convoy
Reflects the merged pick-a-name convoy (PR #21, squash commit 9abbab6)
in repo documentation. **This is the first post-P0 cleanup** —
add-rate-limiting (squash 708ef45) closed the LAST P0 ship-blocker on
2026-05-24, and pick-a-name immediately follows as the first post-P0
P1 quality-bar convoy, closing P1 #12 (brand-consistency — the
inconsistency `AGENTS.md` line 5 had flagged since project setup).
Two file-disjoint briefs landed serially (B1 commit ac8c998
display + comment sweep, B2 commit 1c18d21 infrastructure + email
migration); five canonical-string D-decisions ratified verbatim at
gate-1 plus Risk 4 PRESERVE on the negative regression-lock literal.
Architect commit 50ce9ab; no scope expansions and no implementer
deviations from the verbatim spec beyond the parallel-vs-serial
dispatch choice (parallelizable in theory; serial in practice for
lockfile-regen + migration-script audit cleanliness).

.convoys/pick-a-name.md:
  - frontmatter Status: in-progress -> shipped (added Shipped:
    2026-05-24 line, matching the file's existing **Status:** /
    **Opened:** markdown-line shape rather than YAML frontmatter).
  - new ## As-shipped section replacing the placeholder
    "(To be appended post-merge by role-doc-writer.)" stub. Opens
    with the post-P0 transition language pointing at ship-readiness's
    "8 of 8 RESOLVED" baseline + this convoy's role as the first
    P1 quality-bar closure. Decisions section captures all five
    D-ratifications verbatim (D1 Deck Hearth two-word internal-cap;
    D2 deck-hearth kebab matching the existing CSS class + Node
    convention; D3 deckhearth single-token for IDs/Redis; D4
    admin@deckhearth.com placeholder TLD pre-domain-acquisition,
    swept across admin/alice/bob uniformly; D5 full deckhearth
    Redis prefix not abbreviated dh, with the architect's
    self-documenting-prefix-vs-memory-savings rationale preserved)
    plus the Risk 4 PRESERVE on test/lib/permission-middleware.test.js
    line 87's negative regression-lock literal — including the
    project-pattern justification (Gotchas #2/#3/#4/#5/#8 in
    AGENTS.md all preserve historical-shape locks for the same
    audit-trail reason). As-shipped surface broken into B1/B2 split
    with file-disjoint inventory + the serial-in-practice dispatch
    note (the conductor's parallel-via-multitask path stayed open as
    fallback). As-shipped diff captures B1 (7+/7-) + B2 (133+/30-)
    + lockfile STOP-on-churn confirmation (only the two `name` lines
    diffed; npm ci clean against regen). Empirical CI metrics from
    post-merge run 26387909625 (Aggregate gate 10s, Lint 45s 128
    baseline, forbidden-endpoints + forbidden-cors-headers 4s each,
    Playwright smoke 1m4s 3/3, Screenshot diff 1m5s continue-on-error
    swallow per Decision 4, vitest 21/21 in 35s with Risk 4 PRESERVE
    test green). Cross-validation finding: 4th convoy in a row where
    the same 3-test smoke spec defends the auth surface through a
    sweeping change (PR #15 Layout -> #19 CORS -> #20 rate-limit ->
    #21 brand-rename). Implementer-vs-architect calibration note on
    the B2 forecast paragraph vs § Full surface inventory — both
    correct, cross-reference between them could be tighter for the
    next architect. Operator-action-required-going-forward: run the
    new migration script before the next admin login attempt
    (idempotent + UNIQUE-collision-safe). What did NOT change audit
    trail (~25 lines of historical .convoys/ tcgvault references stay
    byte-identical per no-go-zones, plus seed-collections-*.js
    historical scripts with stale WHERE-clauses that now no-op
    harmlessly post-migration, plus repo-name references deferred to
    rename-repo-and-vercel-project, plus the docs/agent-context
    + add-api-route SKILL.md repo-name references that sweep with
    the same downstream convoy).

.convoys/ship-readiness.md:
  - § Status summary: P1-quality-bar-work-in-progress line added
    below the existing 8/8 RESOLVED milestone footer, citing
    pick-a-name as the first such convoy.
  - § P0 launch sequence step 5 (pick-a-name): marked RESOLVED
    2026-05-24 with the squash commit + brief shape + smoke metrics
    + operator-action callout inline, mirroring the format of step 4
    (add-rate-limiting RESOLVED) introduced by the previous
    doc-writer pass.
  - § Queued convoys: four new entries surfaced by pick-a-name
    inserted as a logical group after purge-weak-creds-from-helpers
    (the natural neighbor — all brand-bound + credential-bound
    post-pick-a-name follow-ups):
    - rename-repo-and-vercel-project (P2 polish; GitHub repo +
      Vercel project rename; auto-redirects make low-urgency; lists
      the 8 architect-verified literal-repo references that sweep
      together; Risk 5 .agent-context-manifest.yml source-tag
      re-evaluation noted).
    - point-domain-at-deckhearth (P2 polish; blocked on domain
      acquisition; DNS pointer + Vercel domain claim + admin email
      TLD swap if non-`.com`; current placeholder-email rationale
      preserved — auth uses email as identity not as mail target).
    - regenerate-brand-assets (P2 polish; favicon, OG images, social
      cards; requires design pass; cross-references the original
      Role-design-system-auditor finding about unifying DH logo +
      AnimatedFireLogo).
    - convert-reset-db-to-esm (P2 hygiene; CJS-in-ESM bug at
      scripts/reset-db.js:142; fold-into-purge-weak-creds-from-helpers
      noted since both convoys touch the same file).
  - seed-visual-baselines-on-linux entry: extended with the
    AFTER-pick-a-name ordering note (now satisfied — 9abbab6 merged
    2026-05-24); first Linux baseline will capture Deck Hearth strings
    not pre-rename TCG Vault strings.
  - purge-weak-creds-from-helpers entry: scope narrowed — the
    @tcgvault.com email-half is now satisfied by pick-a-name B2;
    remaining scope is the admin123/alice123/bob123 weak password
    literals only (which survived pick-a-name deliberately per
    Brief 2's scope boundary). Fold-into-convert-reset-db-to-esm
    suggested (overlapping file).

AGENTS.md:
  - line 5 (top-of-file branding note): rewritten in full from the
    B1-installed transitional shape ("Deck Hearth is the canonical
    product brand (ratified 2026-05-24...)") to the post-merge
    documented shape with the squash commit + PR # citation + the
    Vercel-project parenthetical + the Risk 4 PRESERVE caveat
    citing test/lib/permission-middleware.test.js. **This is the
    showstopper change** — it's the line that's been flagged as
    inconsistent since project setup; the rewrite finally closes
    the brand-consistency loop end-to-end.
  - line 13 (§ 1 Project overview Auth bullet): stale
    `admin@tcgvault.com` reference updated to `admin@deckhearth.com`
    to match the post-B2 seed state. Per Brief 2's "Files explicitly
    out of scope" line: "AGENTS.md line 13 = doc-writer scope".
  - Gotcha #4 (Default admin credentials in the seed): extended
    with a new paragraph below the existing operator-caveat copy
    documenting the post-pick-a-name email rename + the migration
    script + the migration-FIRST-then-setup-db ordering rule + the
    UNIQUE-collision-safe failure mode. Existing drop-public-setup
    operator-caveat copy preserved verbatim above the new content.
  - Gotcha #12 (Rate-limit env vars): per-class limiter table
    extended with a Redis-prefix column showing the renamed
    `deckhearth:*` values (was implicit/missing); one-liner about
    the rename + accepted counter reset added immediately below the
    table. Original env-var contract paragraph
    (KV_REST_API_URL / KV_REST_API_TOKEN, fail-closed-in-prod /
    warn-and-noop-in-dev) preserved verbatim above the new table.
    The defensive THROW + gate-ordering-rule + sixth-class-shape
    paragraphs below stay byte-identical from the
    add-rate-limiting milestone doc-writer pass.

.cursor/rules/api-routes.mdc:
  - § Rate limiting opening lineage line: extended to add the
    pick-a-name attribution (squash 9abbab6, PR #21, 2026-05-24)
    and to note the rename is namespace-only — call shape, return
    shape, and gate-ordering rules below are byte-identical
    post-rename. The convoy-attribution lineage now reads:
    fix-auth-bypass Brief 4 (auth class) -> add-rate-limiting (the
    other four classes + 7 routes) -> pick-a-name (Redis prefix
    rename). No example code blocks in this rule had `tcgvault:`
    literals to swap (verified via re-read); the per-class table
    earlier in the rule doesn't enumerate prefix values either,
    so the lineage line is the only edit needed.

Files explicitly NOT changed: package.json, package-lock.json,
lib/rate-limit.js, lib/**, pages/**, components/**, scripts/**,
test/**, tests/**, .github/workflows/**, README.md, TESTING_GUIDE.md,
playwright.config.js, eslint.config.mjs,
scripts/migrations/2026-05-24-rename-admin-email.js. Doc-writer
pass touches docs only. The four queued downstream convoys
(rename-repo-and-vercel-project, point-domain-at-deckhearth,
regenerate-brand-assets, convert-reset-db-to-esm) own the remaining
brand-bound + helper-bound source-code work; this commit only
records them in the queued-convoys ledger.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 03:04:29 -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
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
add-rate-limiting.md docs: post-convoy cleanup for add-rate-limiting — MILESTONE, last P0 closed 2026-05-24 23:09:07 -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 convoy(bump-next-js): plan + brief 1 (Decisions A-D) 2026-05-23 02:31:26 -05:00
cors-tighten.md docs: post-convoy cleanup for cors-tighten 2026-05-24 20:49:30 -05:00
drop-public-setup.md architect(drop-public-setup): expand scope with brief 2 (CJS→ESM) 2026-05-23 17:02:44 -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 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.md docs: post-convoy cleanup for fix-vercel-deployment-protection-in-ci 2026-05-24 16:32:45 -05:00
pick-a-name.md docs: post-convoy cleanup for pick-a-name — first post-P0 P1 convoy 2026-05-25 03:04:29 -05:00
README.md bootstrap: agent pipeline v0.5.0 + ship-readiness review 2026-05-23 02:31:26 -05:00
ship-readiness.md docs: post-convoy cleanup for pick-a-name — first post-P0 P1 convoy 2026-05-25 03:04:29 -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.