Commit Graph
54 Commits
Author SHA1 Message Date
Omar Sobh 2527a888a2 e2e: replace stale post-login heading assertion with a URL wait
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 25s
ci / rust (push) Successful in 3m41s
ci / publish (push) Successful in 46s
ci / e2e (push) Failing after 29m36s
The shared signIn helper in every spec asserted
`getByRole("heading", { name: "Clawmates" })` after clicking Sign in, but
the dashboard's "Clawmates" is a decorative <span> in the top-bar logo,
not a heading — so all authenticated tests died on the same helper. Swap
that for `page.waitForURL((url) => !url.pathname.endsWith("/login"))`
with a 15s timeout. Robust across UI redesigns and doesn't couple the
signIn helper to a specific product surface. Should convert ~27 of the
remaining 30 failures to passes.
2026-07-05 21:46:21 -07:00
Omar Sobh c417097db2 LoginForm: restore proper <label> elements + update e2e tests to the single-step flow
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 40s
ci / rust (push) Successful in 3m2s
ci / publish (push) Successful in 42s
ci / e2e (push) Failing after 8m53s
The local-mode LoginForm had drifted to using styled <div> elements as
labels. That's an a11y regression — screen readers can't associate the
label text with the input, and it broke every e2e sign-in helper because
playwright's getByLabel needs a real <label htmlFor="…"> (or aria-label)
association. Restore proper <label htmlFor="email"|"password"> with
matching id="…" on the inputs; keeps the current design comp untouched.

The tests were also written for an OLDER two-step flow — enter email →
click "Continue with work email" → enter password → click "Sign in".
The current form is single-step (both fields, one Sign in click). Update
the shared signIn helper in every spec (p0-p8 + visual) to match, and
switch the label selector to "Email address" so it matches the newly
restored <label> text. Drop the stale a11y assertion in p6 that expected
the two-step button.

Also refresh the marketing landing check in p0-shell.spec.ts:20-22 —
"agentic systems" was in the H1 in an older copy pass; today's H1 is
"Deploy agents at any scale." Update the selector.

Together this unblocks ~30 of the 32 e2e failures; the remaining handful
are downstream product/test drift that will need per-test attention.
2026-07-05 21:27:34 -07:00
Omar Sobh 298eb8e20e e2e: move backend/dex/frontend from 8080 to 18080 so runners don't collide
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 23s
ci / rust (push) Successful in 3m43s
ci / e2e (push) Failing after 14s
ci / publish (push) Successful in 36s
Two of the fleet's Gitea Actions runners (morpheus, architect) already
had 8080 permanently bound by unrelated services (nginx on morpheus,
envio-hasura on architect) — every e2e run scheduled there died at
playwright's webServer preflight with "http://127.0.0.1:8080/healthz is
already used". 18080 is unused across morpheus/tank/architect.

Swap 8080 → 18080 in the eight e2e-scoped sites: clawmates.e2e.toml
(listen_addr + slack base_url + oauth redirect_base), dex.yaml (client
redirect URIs must match backend), playwright.config.ts + tests
(p4-slack, p6-oauth), the http.ts dev-fallback origin, and the two
shell scripts (e2e-backend safety check, rehearse-install healthz probe).

Prod compose (/opt/clawmates/docker-compose.yml on gw-04) is untouched;
prod continues to expose the server on 8080 internally on the compose
network (that's per-network, not host-shared).
2026-07-05 20:25:27 -07:00
Omar SobhandClaude Opus 4.8 654ec0f511 feat(frontend): topology compare/Pareto UI
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Add a Compare tab to /topologies: pick a task + roles + topology kinds, build a
graph per kind, run POST /api/topologies/compare, and render a leaderboard table
+ a quality/cost Pareto scatter (SVG, no deps). Wrap Build + Compare in a tabbed
TopologyWorkbench. e2e p8 extended to run a comparison end-to-end (build×N →
compare → leaderboard + Pareto). Full suite 39 green; build + TS clean.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 03:54:54 -07:00
Omar SobhandClaude Opus 4.8 7648487a59 feat(frontend): Topologies page — catalog browser + builder
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
New authed workspace page (/topologies, in the global nav) that browses the
topology catalog and builds + visualizes a topology from a kind + roles:
- lib/api/topology.ts: zod schemas + fetchTopologyCatalog (server, authed).
- TopologyGraphView: lightweight SVG renderer (no new deps), laid out per kind
  (row for pipeline/ring, star for delegation kinds, circle otherwise).
- TopologyExplorer (client): catalog list + roles input → POST
  /api/topologies/build via the /api proxy → render the graph.
- ShellNav: add the Topologies nav item.
- e2e (p8): sign in → nav → browse catalog → build a pipeline → graph renders.

Full suite green (38); npm build + TS clean. Goes live with the next server+
frontend deploy (compare/Pareto UI to follow).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 03:41:30 -07:00
Omar SobhandClaude Opus 4.8 34da54ccaa feat(marketing): full-width square top bar
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Replace the floating rounded nav pill with an edge-to-edge sticky header:
solid bg, bottom border, square corners, content centered to max-w-[1392px].
Drop the hero's -mt-[98px] underlap so it sits below the solid bar. Refresh
the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 17:23:38 -07:00
Omar SobhandClaude Opus 4.8 05c49dc418 feat(marketing): add value sections + trim FAQ
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / e2e (push) Has been cancelled
Page is now Hero → Hierarchy → Scale → Why → Use cases → FAQ → CTA → footer.

- Scale: per-tenant runtime / scale-to-zero / delegation hierarchy.
- WhyGoverned: humans-in-the-loop, single audit journal, delegation, no rogue access.
- UseCases: support / marketing / research / engineering / finance / data.
- FinalCta: dark ink band bookending the hero ("Build your agent company").
- Trim FAQ to 4 (keep the e2e-referenced Qs); repoint nav/footer anchors to
  the live section ids. Refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:44:14 -07:00
Omar SobhandClaude Opus 4.8 16c3231fba feat(marketing): drop crew/security usage + refresh baseline
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Completes 02cde39: remove the CrewStrip and Security functions, their consts,
and the now-unused AgentToken/lucide imports from Sections.tsx; render only
Hero → Hierarchy → FAQ in the marketing page; refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:16:15 -07:00
Omar SobhandClaude Opus 4.8 5638006eb6 feat(marketing): trim landing to hero, crew, hierarchy, security
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Remove the Pitch, One-click, Works, Always-on and Skills sections and the
"Build your AI crew" footer CTA banner. Page is now Hero → CrewStrip →
Hierarchy → Security → FAQ → footer (dark tier kept). Prune the now-dead
section functions, consts, and imports (Image, skills icons). Repoint the
"marketing rendered" heading assertion (p0/p7/visual) from the removed
Pitch heading to the hero h1 (/agentic systems/); refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 16:06:05 -07:00
Omar SobhandClaude Opus 4.8 44512a744f feat(marketing): redesign landing as "trusted infrastructure"
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Re-skins the playful/consumer feel into disciplined agent-infrastructure,
keeping the animated hero canvas (re-themed) and adding the hierarchy story.

- Palette: re-point coral→ember (#E0584A); add ink/surface/mist/slate-light/
  azure/teal tokens. One accent per viewport; retire the black/coral split-
  headline pattern across all 8 headings (single ink color).
- Typography: hero/section weights 800→~650-675, tighter tracking, smaller
  hero size; uppercase eyebrow label.
- Hero: dark ink base with glowing azure/indigo + faint ember canvas blooms;
  light copy; new positioning ("Build safe, scalable agentic systems" + the
  single-agent-to-company subhead); ember primary CTA + ghost "Read the docs".
- Imagery overhaul (code-built, no mascots): AgentToken chips (CrewStrip,
  OneClick card, footer), AlwaysOn rebuilt as a terminal/log with an approval
  line, SkillsShowcase as duotone lucide cards on Mist, Security as a shield/
  lock motif.
- New HierarchyDiagram section ("One agent, or a whole org chart"): SVG org
  chart with an azure active path and teal human-approval checkpoints on
  sandbox-leaving actions.
- Tests: dark-hero/terminal/eyebrow contrast fixed to AA; refreshed the
  marketing @visual baseline (hero masked).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 15:56:58 -07:00
Omar SobhandClaude Opus 4.8 4b55c4d81e feat(marketing): new hero copy + single CTA
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
- Headline → "Scale your Large World" (coral on "Large World").
- Subtext → "Building safe and scalable systems of claws for any domain of work."
- Drop the "Get started for free" hero button; keep "Book a demo".
- Remove the three hero trust pills (free credits / no card / self-hostable).
- Point the p7 hero CTA assertion at "Book a demo"; refresh the @visual baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 14:30:05 -07:00
Omar SobhandClaude Opus 4.8 c7c1ff5d23 feat(marketing): ambient "shift" canvas hero (replaces the desk illustration)
ci / gates (push) Has been cancelled
ci / rust (push) Has been cancelled
ci / sandbox-k8s (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / e2e (push) Has been cancelled
Port of crnacura/AmbientCanvasBackgrounds' shift effect: large circles drift
at random with hue driven by 3D simplex noise, drawn to an offscreen buffer
then blurred and composited onto the visible canvas. Re-tuned to a light brand
palette (pale periwinkle base; blue→violet→coral blooms) so the dark hero copy
stays readable. Self-contained (vendored simplex noise), scoped to the hero,
respects prefers-reduced-motion, and pauses when scrolled out of view / tab
hidden.

- Replace claws-at-desk.png with <HeroAmbient/>; add a soft fade into the
  section below.
- Mask the animated hero region in the marketing @visual snapshot (keeps the
  baseline deterministic) and refresh the baseline.
- Fix a latent AA contrast bug the old illustration was hiding: the CrewStrip
  caption (#77879e on white, 3.65:1) → #647289 (4.87:1).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-15 14:02:35 -07:00
Omar SobhandClaude Opus 4.8 34b8d2f903 Brand: replace PawPrint mark with the new clawmates claw logo
Swapped the placeholder PawPrint icon for the new claw logo everywhere it
appears: the marketing nav (mobile + desktop), the footer, the login card,
and the app left rail. The supplied PNG was a red claw on a solid near-black
background, so I flood-filled the background to transparent (the dark-red
outline survives the black threshold) and exported a trimmed, optimized
public/images/clawmates-mark.png (321x256, 88KB from 1.7MB). It reads cleanly
on both light (nav/login) and dark (footer/rail) surfaces.

Also regenerated the favicon + PWA icons from the new mark:
- src/app/icon.png (Next uses it as the favicon; removed the old favicon.ico)
- public/icons/icon-192.png and icon-512.png (claw on #0a0a0a, maskable)

Roster-card avatars on the login panel stay as PawPrint (decorative, not the
brand). Regenerated all seven @visual baselines that contain the mark — the
swap is sub-threshold for maxDiffPixelRatio, so I deleted and recaptured them
rather than relying on update-snapshots.

typecheck/lint/build green · all @visual green · deployed and verified live
(mark, /icon.png, and PWA icons all 200).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 18:43:14 -05:00
Omar SobhandClaude Opus 4.8 8d9ea7faaa Login: match WorkClaw's /sign-in form exactly (progressive, Clawmates)
The live /sign-in is a Clerk-rendered SignInForm (SSR is just a spinner); the
rendered design is the email-first progressive form. Reworked our /login to
match it visually while keeping our real email+password auth underneath.

- Email step: "Sign up with Slack" (cosmetic), OR, Work Email / Phone Number
  tabs, work-email field, "Continue with work email →", "Other SSO Options".
  Slack / Phone / SSO are cosmetic placeholders we don't support yet.
- Password step: "Continue" reveals the password field + "Sign in" (our actual
  POST to /auth/session). A Back link returns to the email step.
- Headline now mirrors WorkClaw ("Multiply your team's brainpower" / "Sign up
  to get early access").
- Right panel is now the role-card roster grid (PawPrint avatars, our own
  roles) + "The AI crew for your team" + the claws-at-desk art.
- Updated all eight E2E signIn helpers (and the load assertions) for the new
  two-step flow: fill Email → Continue → fill Password → Sign in. Labels
  (Email/Password) and the "Sign in" button name are preserved.
- A11y: bumped the inactive tab text to full slate (was 3.41:1).

typecheck/lint/build green · p0-shell (full sign-in) green · p6-a11y (login
clean) green · all six @visual baselines green (login regenerated) · deployed
and verified live.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 14:27:53 -05:00
Omar SobhandClaude Opus 4.8 a5ae0d6042 Login: clone WorkClaw's two-panel /sign-in shell (Clawmates-branded)
Restyled /login into WorkClaw's two-panel auth design: a white form card on
the left, a periwinkle "meet the crew" panel on the right (claw roster strip,
"Your AI crew, all hands on deck", the claws-at-desk art), light-themed via
the marketing palette. The right panel is hidden on mobile.

- Kept /login as the canonical route (workspace redirect, /api/auth/login,
  and the whole E2E sign-in flow depend on it) and kept our email/password
  mechanism — only the chrome changed. Field labels (Email/Password) and the
  "Sign in" button are preserved so p0–p6 keep passing.
- Added /sign-in → /login redirect so WorkClaw's URL resolves.
- New AuthShell wraps both the local form and the Clerk SignIn branch.
- LoginForm restyled to the light card aesthetic (rounded inputs, full-width
  ink button); uses AA-safe coral-strong for the focus ring / error.
- Regenerated the login visual baseline.

typecheck/lint/build green · p0-shell (full sign-in flow) green · p6-a11y
green · login + marketing @visual green · deployed and verified live
(/login 200, /sign-in 307 → /login).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 14:13:20 -05:00
Omar SobhandClaude Opus 4.8 df589b70d4 Marketing landing: rebuild to WorkClaw structure 1:1 (Clawmates-branded)
Re-scanned the live workclaw.com (same content as our prior capture; they
redeployed but shipped no landing changes) and rebuilt our landing to mirror
its full structure section-for-section, keeping Clawmates branding and honest
claims (no borrowed customer logos, no unverified SOC 2).

Now matches the real layout: sticky pill nav (Product/Blog/Pricing/FAQ +
Sign In + dark Get Started) · light-blue hero with the claws-at-desk art ·
crew strip (honest stand-in for the customer-logo marquee) · "Multiply your
brainpower…" + four trait badges · One-click setup with the create-claw card
(Sandy Clawson) · Works where you do with the 13-app icon grid + Slack
conversation mockup · Always on (dark, moon + composite art) · Your work,
your way skills tiles · Enhanced security (hand-key + key-snap, 4 icon
columns) · FAQ on the textured field · two-tier footer (Build your AI crew
+ dark footer with socials).

- Pulled the WorkClaw assets the public capture missed (claws-at-desk,
  support-claw, slack-convos/cards, always-composite, 13 app icons, security
  icons, footer-team). Dropped WorkClaw's own logo mark for our PawPrint.
- Honest substitutions where WorkClaw's claims aren't ours: no SOC 2 (4th
  security column is "Air-gappable"; trust pill is "Self-hostable &
  air-gapped"), and the FAQ keeps our self-host/air-gap positioning.
- A11y: consolidated to AA-safe coral-strong (#d23a3a) for button fills and
  small coral text; axe reports zero serious/critical.
- Regenerated the marketing visual baseline.

typecheck/lint/build green · p7-marketing (render + a11y) green · @visual
green · deployed via Compose and verified live on :3000.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 13:54:25 -05:00
Omar SobhandClaude Opus 4.8 3b699f2e98 Marketing landing: full WorkClaw-structure clone with ship-crew copy
Rebuilt the public landing to mirror WorkClaw's complete section layout
(verified against tools/wc-capture/out/shots/marketing.png), with original
"clawmates crew on a ship" copy and captured WorkClaw art wired as
swappable placeholders.

Sections (top to bottom): sticky pill nav (dark Get-started CTA) · hero
(dual CTA + trust row + crew banner) · crew strip · positioning headline +
four trait badges · One-click setup (periwinkle panel) · Works where you do
· Always on watch (dark panel) · Your work, your way (3 skill tiles) ·
Safety built into the hull (security columns) · FAQ on the blue field · Build
your AI crew CTA on the dotted field · dark footer.

- No SOC 2 / compliance claims (p7-marketing enforces this); honesty kept by
  replacing WorkClaw's customer-logo marquee with our own crew strip.
- A11y: AA contrast fixes — text-xl coral CTAs (large-text bar), darker
  coral-strong accent on periwinkle, deeper FAQ blue for white text.
- New tokens: marketing-blue, marketing-coral-strong.
- visual.spec marketing test scrolls + waits for lazy art before the shot;
  regenerated the marketing baseline. (Deepest <img> — the security art —
  renders for users but is blank only in Playwright's full-page capture.)
- Vendored the captured WorkClaw asset bundle under public/images/.

Built, typechecked, linted, p7-marketing + @visual green, deployed via
Compose and verified live on :3000.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 09:37:45 -05:00
Omar SobhandClaude Opus 4.8 02456dfdc3 Left rail: vertically center the claw stack (WorkClaw)
The rail's middle scroll container was a plain block (flex-1 overflow-y-auto
py-4), so the claws clustered at the top with empty space below. Match
WorkClaw: make it a centered flex column —
flex w-full flex-col items-center [justify-content:safe_center] overscroll-contain
[&::-webkit-scrollbar]:hidden — so the stack sits in the vertical middle with
balanced space above/below (safe = no clipping on overflow).

To preserve last commit's left-aligned rows under items-center, the RosterList
ul and the New-claw link are now w-full (else they'd shrink/center). Row gap
0.5→1 to match WorkClaw. (Capture shows no gap on the container itself — the
reviewer's suggested gap-1 there was dropped.)

typecheck/lint(0)/86 unit/30 E2E/6 visual green; workspace-home baseline updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-13 07:38:09 -05:00
Omar SobhandClaude Opus 4.8 3a81be17d9 Left rail: horizontal rows, 44px avatars, left-aligned (WorkClaw)
Match WorkClaw's left sidebar (verified vs left-sidebar captures): claw rows
are horizontal — a 44px squircle avatar (was 58px, centered) on the left with
the name beside it, hugging the edge at px-4, gap-3. The "New claw" tile is a
bare 44px dashed + at the same inset (no label, like the reference). RosterList
drops items-center; collapsed (full-panel) mode still centers the avatars.

Avatar `rail` size 58px→44px (size-11) / radius 15px; test updated.
typecheck/lint(0)/86 unit/31 E2E/6 visual green; workspace-home baseline
regenerated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 23:10:37 -05:00
Omar SobhandClaude Opus 4.8 704541f846 Computer panel: open phone-first, full-height, full-bleed, tight grid
Five capture-verified panel fixes (vs the WorkClaw size captures):

- Open from chat lands at PHONE size (launcher sets device:phone), and the
  Computer launcher icon hides while the panel is open (ChatHeader).
- Card fills the column at every size (md:h-full, dropped the 652px centered
  card) so phone/tablet are full-height with the dock anchored at the bottom.
- Full bleeds horizontally (drop the px-6 inset + radius at full) so it meets
  the rail and covers the reserved chat — no squished text behind. Vertical
  pt-[88px] kept so the app header clears the chat-header close (no overlap).
- Home grid → grid-cols-[repeat(4,72px)] so icons stay 72px/tight at every
  width instead of stretching at tablet/full.

Regenerated computer-home baseline (now phone + full-height). typecheck/lint/
86 unit/31 E2E/6 visual green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 22:38:50 -05:00
Omar SobhandClaude Opus 4.8 b61073ce05 Panel app-header system + Settings hero (P1, capture-verified)
The panel app header now matches WorkClaw's measured pattern (dark captures
agent-settings / files-explorer / edit-profile):

- App TOP screen: the header lives on the app surface (sticky), showing the
  app name (text-lg font-semibold) + a size-7 rounded-full close-X → home,
  at px-5 pt-4 pb-3 — replacing the old px-8 pt-6 chevron+small-title. The
  home screen keeps its dot + "{agent}'s Computer" header.
- Sub-screens (AppShell SubViewHeader): back-chevron PILL + text-lg
  font-semibold title at px-5 pt-4 pb-3 (was text-xs px-3 pt-3 pb-2).
- Settings hero: 96px squircle avatar + text-xl name + text-sm role (matches
  the capture; reviewer's 126px was wrong). New Avatar `settings` size.

p3-panel E2E updated (home nav is now the "Close" button). typecheck/lint/
86 unit/31 E2E/6 visual all green; no visual baseline change.

Known follow-up (P2): Settings/Files sub-screens still stack the top header +
the back-header (pre-existing) — to be unified per-app.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 21:32:02 -05:00
Omar SobhandClaude Opus 4.8 db3dcff932 Computer panel: "Add Apps" tile with a visible plus
The far-right home tile read "Add" and rendered its plus through GradientGlyph
(coral, faint/unclear). Match WorkClaw's capture: label "Add Apps" and a plain
lucide-plus in currentColor (white/65, inherits from the dashed tile),
strokeWidth 2, 19px. Updated the p3-panel E2E label + computer-home baseline.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 18:30:42 -05:00
Omar SobhandClaude Opus 4.8 8dac7aff49 Computer panel: filled glyphs + 32px grid inset + header padding
All verified against the captured WorkClaw panel DOM (not the reviewer's
live-preview guesses, which were wrong on two points):

- Glyphs are now FILLED — gradient on fill + stroke, 1px stroke, and a
  drop-shadow(0 1px 2px rgba(0,0,0,0.25)) — via a `filled` prop on
  GradientGlyph. Applied to the dark-tile glyphs (Claw Chat + dock
  Skills/Files/Routines/Settings). The reviewer said keep Skills outline —
  the capture shows WorkClaw fills the zap too; and it missed the drop-shadow.
- Grid inset 12px → 32px (px-8): the grid is now 336px so grid-cols-4 resolves
  to 72px tracks (capture shows repeat(4,1fr) at 336px — NOT explicit 72px cols
  as claimed; same grid-cols-4 as ours, just the right container width).
- Panel header: drop the fixed h-11/px-3, use px-8 pt-6 = padding 24px 32px 0
  (matches WorkClaw's inline style exactly).

typecheck/lint/86 unit/31 E2E/6 visual green; computer-home baseline updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 18:25:02 -05:00
Omar SobhandClaude Opus 4.8 36087c30f5 Computer panel: match measured WorkClaw geometry (from capture)
Forensic capture of the live app's Computer panel gave exact ground truth,
correcting my prior commit (which trusted a reviewer's measurements):

- Dock is content-width (~380px) centered by a w-full wrapper, NOT stretched
  full-width — my last change had wrongly stretched it. Reverts to the real
  centered-pill behaviour.
- Dark tiles (#1f1f1f) gain the measured grounding drop in --shadow-dock-tile
  (0 4.65px 9.35px rgba(0,0,0,0.2)); previously flat (hairline + inset only).
- AppIcon cells fixed to 68px / 8px gap; grid gap 34px×16px; icons 34px; the
  dock now uses the same nested tile component as the grid.
- White brand-tile shadow + tile nesting were already exact (capture confirms).

Regenerated computer-home baseline. typecheck/lint/86 unit/31 E2E/6 visual green.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 08:00:16 -05:00
Omar SobhandClaude Opus 4.8 23a4bad07d Computer panel: full-width dock bar + WorkClaw tile structure
Two measured parity changes to the Computer home screen (HomeScreen.tsx):

- Dock: mx-auto centered pill → flex items-end justify-center, so it spans
  the panel width as a bottom-anchored frosted bar instead of a floating
  content-width pill. (Shadow/blur/bg/ring already matched prod.)
- App-grid tiles: adopt WorkClaw's nested DOM (cell → button → fade layer →
  visual tile) and the measured 4-layer "physical icon" shadow on the white
  brand tiles (browser/slack), where its dark hairline + drop + bright inset
  read. Dark glass tiles keep the white-bevel shadow-dock-tile (a dark drop
  is invisible on them). Brand icons sized to the measured 34px.

Regenerated computer-home visual baseline. typecheck/lint/86 unit/31 E2E
green; all 6 visual pass.

Note: WorkClaw's Computer panel is behind auth, so unlike the token work
these targets couldn't be verified against prod CSS — applied per the
reviewer's live measurements at the user's direction.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 07:18:25 -05:00
Omar SobhandClaude Fable 5 c174c94594 Chat header: remove the agent identity block
Dropped the avatar + name + role + online dot from the top of the chat
header (the claw is already shown in the rail and the welcome state). The
header now holds only the right-aligned action cluster (and the device/
Close overlay while the panel is open). Removed the now-unused agent prop
+ Avatar/Agent imports; ChatWorkspace no longer passes agent to the header.
Regenerated chat-welcome + computer-home baselines; full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 18:14:48 -05:00
Omar SobhandClaude Fable 5 8c9b750673 Left rail: match WorkClaw sizing/weights/container
Measured sidebar parity:
- Container: dropped the aside's px-1 so the rail is the full w-rail 176px
  (was 168px inner); added bg-background (solid #0a0a0a, was transparent);
  padding now 8px 0 24px (pt-2 pb-6).
- Bottom nav (Skills/Apps/Team/Credits): 14px/400 → 12px/500 (text-xs
  font-medium, leading-[1.3]); trailing credits balance likewise.
- Claw-name labels: active 400→600 (font-semibold), inactive 400→500
  (font-medium); kept 12px.
Verified live at 1440: rail width 176, bg rgb(10,10,10), nav 12px/500,
active claw name 12px/600. Rail-wide change → regenerated all 7 visual
baselines; full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 15:25:38 -05:00
Omar SobhandClaude Fable 5 ddc1f8fbe0 Fonts: drop body antialiased so text renders at the reference weight
The <body> carried Tailwind's `antialiased` (-webkit-font-smoothing:
antialiased), which inherits through the whole tree and renders every
chat/message/UI text thinner & lighter than WorkClaw. WorkClaw leaves the
browser default (`auto`), giving the crisper/heavier weight. Removed the
class — body is now just `min-h-full`; computed -webkit-font-smoothing is
`auto`. The font itself was always 14px/400 Geist; only the smoothing
differed. Global rendering change → regenerated all 7 visual baselines;
full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 14:06:03 -05:00
Omar SobhandClaude Fable 5 2910189717 Regenerate computer-home baseline: chat condenses beside the panel
Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 12:19:35 -05:00
Omar SobhandClaude Fable 5 914ffae8f9 Regenerate computer-home baseline: action cluster in the middle column when expanded
Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 11:59:43 -05:00
Omar SobhandClaude Fable 5 fa1f64803c Regenerate chat-welcome + computer-home baselines for the right-aligned cluster
Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 11:17:14 -05:00
Omar SobhandClaude Fable 5 fbff4cbbc8 Regenerate chat-welcome + computer-home baselines for the Slack-chip cluster
Action cluster now Slack → Sessions → New → separator → Computer, chip-styled.
Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 08:42:10 -05:00
Omar SobhandClaude Fable 5 e0a59e3b95 Regenerate chat-welcome + computer-home baselines for the two-zone header
Action cluster centered, device/Close zone top-right. Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 07:46:22 -05:00
Omar SobhandClaude Fable 5 40e7e66eea Regenerate computer-home baseline for the 67% tablet overlay
The panel is now a 847px (67%) absolute overlay at tablet, covering the
right of the chat which stays full-width underneath. Fresh capture; full
suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 06:38:40 -05:00
Omar SobhandClaude Fable 5 dab08e47aa Regenerate rail baselines + de-flake the visual signIn helper
Rail logo (coral paw-print brand tile) and 58px agent tiles updated in
workspace-home, chat-welcome, computer-home (the last also shows the
panel as a right overlay — chat no longer shifts). Fixed the visual
signIn helper: it matched the login page's lowercase 'clawmates' heading
and could screenshot mid-navigation, so workspace-home captured the login
page — now it waits for navigation off /login and matches 'Clawmates'
exact. Avatar unit test updated for the 58px/rounded-20 rail tile.
Full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 05:30:02 -05:00
Omar SobhandClaude Fable 5 9456edf198 Regenerate chat-welcome + computer-home baselines for the new welcome stack
Composer centered in the welcome stack with attach/screenshot icons and
no Send, 12px subtitle, rounded 126px hero avatar, and the larger chat
header (58px avatar / 18px name / 14px role). Captured fresh; full suite
(37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 04:29:15 -05:00
Omar SobhandClaude Fable 5 7393b6538b Chat welcome + active conversation: composer controls, layout, header
Measured welcome-screen + active-conversation feedback:

Composer redesigned with two variants (no Send button — Enter to send,
Shift+Enter for newline; attach + screenshot icon affordances on the
left). 'welcome' = short single-row 672px-capped pill, icons inline;
'active' = taller two-row card (textarea on top, 36px icon-button row
below), placeholder switches to 'Type your message…'. A cream Stop pill
appears while the agent is generating, wired to a real useChat.stop()
that aborts the SSE and finalizes the partial reply (new 'stopped'
reducer action).

Empty state un-pinned: the composer is now part of the centered welcome
stack (avatar → heading → subtitle → composer → chips) instead of being
pinned to the viewport bottom. Subtitle dropped to 12px. Hero avatar
kept at 126px but with a proportional 40px squircle radius (a flat 17px
read as square at that size).

Chat header sized up to match: 58px avatar (new Avatar 'header' size),
name 18px/600 neutral-200, role 14px. The neutral-500 role/subtitle tone
nudged to #7d7d7d to clear AA contrast on #0a0a0a.

84 unit + 31 functional E2E green; verified both states live.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-11 04:27:27 -05:00
Omar SobhandClaude Fable 5 660dbc6583 Regenerate computer-home baseline for the new panel layout
Tablet-width card, size toggles + close in the global header, and the
enlarged dock (56px tiles / 34px glyphs / 11px labels). Captured from a
verified-fresh server; full suite (37) green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 22:05:24 -05:00
Omar SobhandClaude Fable 5 2df933b0c0 Computer panel: header toggles, device-state widths, bigger dock
Measured panel feedback — four fidelity gaps closed:

1. Size toggles + close moved OUT of the panel card header into the
   global chat header (where the reference mounts them), beside a thin
   divider. DeviceSizeToggle restyled to 28px p-1.5 rounded-md with
   inactive at opacity-30, active at full. The panel card header now
   carries only the home/back button + title + status dot.
2. Device-state widths wired (were stuck at 400px). DevicePanel now
   manages its own complementary <aside> sized by flex per ?device=:
   phone basis-[448px] (400 card), tablet basis-[550px] (502 card),
   full basis-0 grow-[4] — fluid, fills the row beside the chat. Verified
   live: aside measures 448 / 550 / 1011 at a 1440 viewport. Wrapper
   px-3→px-6 (24px gutters); card is now w-full (width driven by aside).
3. The grow animates — transition-[flex-basis,flex-grow] with the
   signature --duration-normal / ease-app on the aside.
4. Dock glyphs enlarged: tiles size-12→size-14 (56), glyph 22→34, plus
   the 11px label under each tile.

Mount/unmount preserved via transitionend (flex-basis|flex-grow), as is
role=complementary aria-label=Computer, the device-panel-theme testid,
and the mobile full-screen overlay. p3/p4 updated to find the toggle +
close at page scope (now in the header, outside the panel region).
83 unit + 31 functional E2E green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 22:03:26 -05:00
Omar SobhandClaude Fable 5 b135c114df Regenerate visual baselines against the corrected build
The previous baselines were captured against a stale next-start server
(Playwright reuseExistingServer reused a ghost on :3100 serving the
pre-fix bundle), so they encoded the broken render. Deleted and
regenerated from a verified-fresh server: chat-welcome (coral name, 2×2
pill chips, #1A1A1A composer), computer-home (real Chrome/Slack brand
tiles, coral Claw Chat glyph, frosted dock, icon size-toggle), credits,
marketing, team-orgchart. Full suite (37) green against them.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 21:34:40 -05:00
Omar SobhandClaude Fable 5 337f059afd R7: test reconciliation + visual baseline lock
- Regenerated all 7 @visual darwin baselines for the restyled surfaces
  (login, workspace home, chat welcome, computer panel, credits) and
  added two new ones: the marketing landing (full page) and the Team
  org-chart tab.
- Credits visual made deterministic: balance + the whole usage card are
  masked (testids), and the runway line always renders so the card
  height is constant — shared-backend credit spend during the full run
  no longer shifts the diff.
- Full gate sweep green end to end: 173 Rust tests + clippy/fmt clean,
  83 frontend unit + lint + typecheck, all 37 Playwright journeys
  (functional + visual), axe serious/critical at zero across every
  surface, LOC ≤1250 and no-placeholder gates.

The interface now matches the reference design system across the app,
the Computer panel, the global pages, and a new light-theme marketing
site — design system only, our brand throughout.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 20:26:10 -05:00
Omar SobhandClaude Fable 5 200bb56299 R5: marketing landing — light-theme public site at /
A new (marketing) route group with its own LIGHT layout (slate palette +
marketing coral #E95656 + periwinkle cards on near-white), the inverse of
the dark app. The middleware rewrites '/' → /marketing for logged-out
visitors (keyed on the session cookie / Clerk __session); authed users
fall through to the workspace app unchanged.

Built to the measured marketing system with OUR copy and honest claims —
NO SOC 2 / compliance badges: floating white pill nav, the 75px/800/-3px
display hero with a single coral keyword span, dual pill CTAs (coral
primary / white-bordered secondary), trust badges ('free credits',
'no credit card', 'self-hostable & air-gapped'), periwinkle feature
cards, a structural-security section (approval-gated, broker-held creds,
air-gappable — our real differentiators), an interactive FAQ accordion,
CTA band, and footer.

E2E (p7-marketing): renders for logged-out visitors, FAQ accordion works,
asserts NO SOC 2 claim, and an axe pass (coral CTAs sized to clear the
AA large-text threshold). p0-shell updated: logged-out '/' now shows
marketing with a Sign-in link to /login.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 20:13:09 -05:00
Omar SobhandClaude Fable 5 e65bcd4130 Post-1.0 finale: Calico-enforced egress denial + visual-regression lock
- scripts/netpol-cluster.sh: a kind cluster with Calico (default CNI
  disabled) — the only way to PROVE the §15 default-deny NetworkPolicy,
  since kindnet accepts the object but never enforces it. New live test
  on that cluster: outbound connect to 1.1.1.1 dropped, DNS egress
  dropped, while API-server exec keeps working (not pod network).
  Kernel-level enforcement of the sandbox egress claim, demonstrated
- K8sDriver::connect_with_context: pin a kubeconfig context instead of
  ambient. The whole k8s suite now pins its cluster explicitly — the
  netpol cluster's creation had silently switched the current context
  and stranded the seccomp test on the wrong cluster (fixed and made
  impossible to recur)
- CI: netpol-cluster up + calico egress test in the sandbox-k8s job
- Visual-regression lock (plan P6): @visual Playwright spec with
  animation-disabled, masked-dynamic-region screenshots of login,
  workspace home, chat welcome, computer panel, credits; darwin
  baselines committed (5 PNGs); CI excludes @visual until linux
  baselines are generated there. Full local suite: 33 journeys

165 Rust tests + 5 live kind tests (2 clusters) + 33 journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 13:30:10 -05:00
Omar SobhandClaude Fable 5 add4f79fed Rebrand: TeamClaw -> Clawmates (clawmates.work)
Full-depth rename per the approved plan; the 'claw' product vocabulary
(claws, /claws routes, clawId, Claw Chat) stays — it is now the brand.

- Display brand: Clawmates (manifest, titles, hero, login/rail logo
  'clawmates'); default host app.clawmates.work; registry
  ghcr.io/clawmates
- Crates tc-* -> cm-* (16 crates + all imports); binaries
  clawmates-server/broker/bundler; images clawmates/*; env prefix
  CLAWMATES_* (+ CM_TEST_DATABASE_URL / CM_LIVE_LLM); config
  clawmates.toml; helm chart deploy/helm/clawmates with clawmates-*
  resources; db names clawmates*; sockets /run/clawmates; cookie
  cm_session; kind cluster clawmates-test; seccomp node profile
  clawmates-agent-profile.json
- All 9 Playwright brand assertions updated in lockstep; historical
  spec document left untouched as the only remaining 'TeamClaw'
- Local env migrated: dev pg clawmates-dev-pg/clawmates_dev, shared
  test server clawmates-test-pg, kind cluster recreated with image +
  profile, compose images rebuilt under clawmates/*

Verified end to end: 161 Rust + 68 frontend tests, 29 Playwright
journeys, 4 live kind tests, helm/install/LOC/placeholder gates, and
the clean-room install rehearsal serving the clawmates login page from
a signed bundle of the rebuilt images.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 12:31:25 -05:00
Omar SobhandClaude Fable 5 ace66d7ffb P6 complete: PWA, route motion, dex browser-flow OAuth, release pipeline
- PWA (§16): hand-rolled 60-line service worker (network-first pages with
  offline fallback, cache-first hashed statics, /api NEVER touched — SSE
  and approvals stay live), app manifest with §2 identity, stdlib-
  generated coral claw icons, prod-only registration. E2E asserts
  manifest, real PNG icons, an ACTIVATED service worker, and the /api
  bypass. (Serwist was tried and dropped: its webpack plugin fights
  Next 16's Turbopack builds; sixty lines we own beat a plugin we fight.)
- Route motion (§3): (workspace) template re-mounts per navigation with a
  quiet fade-rise, zeroed under prefers-reduced-motion. The a11y sweep
  now settles running animations before scanning — axe was reading
  mid-fade opacity as contrast failures
- OAuth browser flow vs REAL dex: the e2e harness boots dexidp/dex with
  static client + password; the journey drives the actual dex login form
  from /api/apps/oauth/start through the callback 303 and asserts the
  app reads connected (closing the P4 deferral honestly)
- release.yml: tag-triggered — builds all four images + postgres, saves
  tarballs, assembles the SIGNED air-gapped bundle (compose, config,
  migrations, seccomp profile, installer, bundler binary), derives the
  public key via the new Could not find command "pubkey". subcommand (tested), verifies
  the bundle customer-style with the public half only, attaches tarball
  + public key to the GitHub release

153 Rust + 63 frontend tests + 29 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 09:57:21 -05:00
Omar SobhandClaude Fable 5 ccf96053e6 P6: security soak, axe a11y sign-off, signed air-gapped bundle tooling
- Concurrency soak (exit criterion): 12 concurrent gated runs, every
  decision attempted twice concurrently, explicit resumes racing the
  durable sweeper — exactly one execution per approval, grants consumed
  at most once, every decision audited, zero stuck runs, zero unaudited
  executions. (Testkit pool raised to 20 connections; the 5-connection
  pool starved the storm.)
- axe a11y sweep (exit criterion): serious+critical violations fail CI on
  login, shell, chat, computer home, settings app, all global pages, and
  the wizard. Two real violations found and fixed: aria-label on a plain
  div (wizard progress -> role=group) and a button directly inside a <dl>
  (settings -> plain bordered list).
- tools/bundler (exit criterion): keygen / assemble / verify CLI — copies
  artifacts, writes manifest.json + sha256 checksums.txt + a detached
  ed25519 signature; verification is fully offline (keyless signing is
  internet-dependent and disqualified). Tests: round trip, tampered
  artifact caught by hash, tampered checksum list caught by signature,
  wrong key refused, missing artifact reported.

147 Rust + 63 frontend tests + 27 Playwright journeys (incl. 4 a11y).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 07:36:15 -05:00
Omar SobhandClaude Fable 5 a8efada690 P5 exit: usage metering, credit billing, promo codes, 3-step wizard
- LlmEvent::Usage across all three providers (Scripted deterministic
  word-count accounting; Anthropic message_start/delta usage; OpenAI-compat
  stream_options include_usage)
- tc-billing: ceil(tokens/1000) min 1 credit; lots drain oldest-first under
  FOR UPDATE; balance clamps at zero while the usage ledger records the
  full obligation; promo codes redeem exactly once via CAS (migration 0006)
- Runtime charges every completed run (billing failure never fails a run);
  proven: 1 token in + 3 out -> 1 credit deducted
- API: GET /api/team/usage, POST /api/credits/redeem (409 on reuse, audited)
- Credits page: balance, 7-day usage meter with runway estimate, PromoRedeem
- /claws/new is the full §9 wizard: ?step=identity|access|slack deep-linked
  progress, accent swatches + name randomizer, access toggles, optional
  Slack step, explicit review-and-confirm (creation = live agent), animated
  provisioning state -> straight into chat
- E2E: chat decrements the visible balance and fills the usage meter;
  WELCOME500 adds exactly 500 once then refuses; wizard round trip

140 Rust + 63 frontend tests + 23 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 07:19:34 -05:00
Omar SobhandClaude Fable 5 91327e3618 P4 complete: OAuth authorization-code flow, MCP-OAuth, AddApps connects
- migration 0005 oauth_states: one-time states (10-min TTL), consumed by a
  CAS DELETE on callback — replays and forgeries both 404
- POST /api/apps/oauth/start: OIDC discovery on the configured issuer (or
  the custom MCP issuer for authType=mcp_oauth), state row, authorize URL
- GET /api/apps/oauth/callback: code exchanged at the REAL token endpoint
  (client id+secret form POST); the access token goes straight to the
  broker (test proves it never appears unencrypted in Postgres); connection
  row + audit; redirects to the claw's Add Apps panel
- [oauth] config (issuer/client/redirect_base) wired through AppState
- Tests against a real local IdP server (discovery + validating token
  endpoint): full round trip, broker-held token, replay/forged state
  refused, bad code fails exchange, mcp_oauth uses the custom issuer while
  plain oauth refuses without a configured IdP
- AddAppsApp: live connection badges + inline API-key connect per app
  (E2E: connect Notion by key from the directory)

136 Rust + 63 frontend tests + 21 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 06:50:41 -05:00
Omar SobhandClaude Fable 5 6dbdd20ee0 P4: Slack inbound @mention — broker-verified signatures drive real runs
- Broker op VerifySlackSignature: v0 HMAC-SHA256 computed INSIDE the broker
  (constant-time compare); the signing secret never crosses the socket.
  Slack secrets are one JSON credential {bot_token, signing_secret}; the
  broker extracts the right field per operation
- Public POST /api/slack/events: signature verified against connected slack
  connections via the broker; forged signatures 401; url_verification
  handshake echoed only when signed; app_mention starts a real run in the
  agent's dedicated '💬 Slack' session — and the agent's reply is itself a
  gated outbound post
- SlackApp Connection tab captures bot token + signing secret
- Integration test: forged 401, signed challenge, signed mention -> run ->
  slack.post pending in the approval queue
- E2E: full loop — connect, gated outbound (sink empty -> exactly one post),
  then a node-crypto-signed mention -> approval card -> approve -> 'On it!'
  lands in the sink

134 Rust + 63 frontend tests + 21 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 06:40:04 -05:00
Omar SobhandClaude Fable 5 000b9b3a4b P4 core: broker-held app connections + gated, broker-executed Slack posting
- app_connections repo; POST /api/apps/connect (keys/basic): the credential
  goes to the secret broker over its socket and only the encrypted ref lands
  in the row; disconnect endpoint; /api/apps directory merged with live
  connection status; audit rows for connect/disconnect
- Broker protocol: InvokeHttp carries a JSON body
- slack.post tool (SendsExternally -> gated): marked broker_executed — the
  runtime skips its own grant consumption and the BROKER independently
  verifies + consumes the single-use grant, then calls Slack with the bot
  token injected; the runtime never sees the credential
- Config: [broker] socket_path + [slack] base_url; e2e harness spawns the
  real teamclaw-broker daemon and the server hosts an e2e-only /__slack sink
- SlackApp: Connection tab stores the token via the broker; connected state
- Integration test: blocked while pending -> approved -> sink received
  exactly one post with 'Bearer xoxb-test-token' -> grant replay refused
- E2E journey: connect Slack in the panel -> gated post card with preview ->
  sink empty while pending -> approve -> exactly one post, queue clear

133 Rust + 63 frontend tests + 21 Playwright journeys.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-06-10 05:51:19 -05:00