Commit Graph
16 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 4.8 bd3250c9c7 feat: /judge review + scoring + leaderboard — TDD
Final screen — replaces the last WorkshopStub; App.tsx now has zero stubs:
- SubmissionList: live review queue with scored markers + selection
- AddReview: read-only render of a submitted 5-layer ADD
- ScoreForm: 0-10 rubric per layer, auto-summed total, notes
- Leaderboard: ranked teams by average judge total
- Judge page (behind name+code AccessGate): queue + review/score + leaderboard,
  refreshes on scoring and on any collective event

21 new tests; suite 140/140 green, typecheck + lint clean, build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:31:36 -07:00
Omar SobhandClaude Opus 4.8 6c07788fab feat: /admin instructor dashboard — TDD
- AccessGate: shared code (+optional name) gate for /admin and /judge,
  sessionStorage-backed
- TeamCard: pure 15-grid tile — phase dots, stats line, submitted/judged
  badges, stale dimming
- useCollective: REST-seeded + WS-live reducer of all teams/submissions,
  degrades to polling when the socket is silent
- useNow: ticking clock hook (effect-driven) for stale dimming
- Admin page: aggregate strip + 15-card grid behind the access gate

19 new tests; suite 126/126 green, typecheck + lint clean, build OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:27:08 -07:00
Omar SobhandClaude Opus 4.8 b18551f120 feat: collective client sync — api.ts + useCollectiveSync (B2)
- src/lib/api.ts: typed client for the collective — pushTeam/pushSubmission
  (public), getTeams/getSubmissions/getSubmission/postScore/getLeaderboard
  (code-gated), and openCollective WS with auto-reconnect
- src/lib/useCollectiveSync.ts: offline-first sync mounted once in App —
  projects the store to a TeamSnapshot, pushes on phase change + submission,
  throttles stat churn, and routes failures to a sessionStorage outbox that
  retries on interval + window 'online'. Never blocks the participant flow.

11 new tests (incl. backend-down path); suite 112/112 green, typecheck + lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:21:41 -07:00
Omar SobhandClaude Opus 4.8 9808e6958e feat(api): collective backend — Express + better-sqlite3 + ws — TDD
New api/ service powering admin + judge for the single-day event:
- db.ts: SQLite store (teams/submissions/scores), upserts, leaderboard;
  POST /submissions flips the team's add phase
- app.ts: REST — public PUT /teams/:id + POST /submissions (broadcast),
  code-protected GET /teams, /submissions[/:team], POST /scores, /leaderboard
- auth.ts: shared admin/judge access codes (header/bearer/?code=), const-time compare
- hub.ts + ws.ts: WS feed at /ws — auth via ?code=, snapshot on connect,
  team:update / submission:new / score:new broadcasts, heartbeat
- index.ts: http + ws wiring; types.ts mirrors the client DTOs

13 tests (REST via supertest + WS integration) green; typecheck clean;
boot smoke test: /healthz=ok, protected routes 401 without a code.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:19:24 -07:00
Omar SobhandClaude Opus 4.8 ca023cdaa5 feat: stable teamId in store + shared collective DTOs (B-prep)
- session store gains a persisted teamId (crypto.randomUUID, preserved
  across reset) used as the team's stable identity for the collective
- src/types.ts: TeamSnapshot/SubmissionDTO/ScoreDTO/LeaderboardRow/WsEvent,
  the contract shared with the api backend

2 new tests; suite 88/88 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:14:09 -07:00
Omar SobhandClaude Opus 4.8 7c141dcd89 feat: participant flow screens setup/module1/module2/add — TDD
All four workshop phases are now real screens, replacing WorkshopStub:
- EnvSetup (/workshop/setup): device check + serial self-test (no stats
  pollution) + provider/model selection; gated Proceed
- Module1 (/workshop/module1): live IMU feed via useSerial, actor map,
  ADD Layer 1 capture; gated on observed frames + L1 goal
- Module2 (/workshop/module2): harness tuner + live TOML preview, test
  triggers that classify against the tuned threshold, ADD L2/L3
- AddBuilder (/workshop/add): ADD L4/L5, assembled AddDocument, print-to-PDF
  export, deterministic submission code; completes the run
- New components: ActorMap, HarnessTuner, TriggerButtons, AddDocument

23 new tests; suite 86/86 green, typecheck + lint clean, build OK.
Only /admin and /judge remain stubbed (need the backend).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:13:07 -07:00
Omar SobhandClaude Opus 4.8 965af7e5c0 feat: shared workshop components (ADD form, stats, feed, harness) — TDD
- AddLayerForm: keystone ADD capture — string layers (L2-L5) as textarea,
  object layers (L1) as per-field inputs; writes straight to the store
- StatsTally: live classified-frame counts
- LiveFeed: presentational IMU readout (props-driven)
- HarnessTomlPreview: live harness.toml render
- HarnessProviderSelect: provider toggle group + model field
- ui/textarea primitive

14 new tests; suite 63/63 green, typecheck + lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:07:20 -07:00
Omar SobhandClaude Opus 4.8 66191217ec feat: Web Serial bridge + harness/submission libs — TDD
- src/lib/serial.ts: serialSupported, parseLine, classifyFrame (pure),
  requestPort with deterministic mock fallback for tests/unsupported browsers
- src/lib/useSerial.ts: React hook streaming frames into stats via recordEvent,
  classifying against the live (re-readable) harness; inject() for test triggers
- src/lib/harness.ts: harnessToToml renderer
- src/lib/submission.ts: deterministic makeSubmissionCode
- TeamRegistration.onConnect now uses requestPort (sync mock fallback keeps
  the existing flow test green)

20 new tests; suite 49/49 green, typecheck + lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:05:08 -07:00
Omar SobhandClaude Opus 4.8 8163dd7829 feat: Lecture page (/lecture, 5 movements) — TDD
Replaces the WorkshopStub for /lecture with a real content screen:
5 movement sections (agency, perception loop, ZeroClaw, failure modes,
edge vs cloud), mirroring the Landing visual idiom. No PhaseStrip — the
lecture is not a workshop phase. 6 new tests; suite 29/29 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-16 19:01:53 -07:00
Omar Sobh e64bce81ab fix(perf): non-blocking Google Fonts load + chmod assets in image
Two issues surfaced when the deployed site was loaded:

1. favicon.svg shipped from public/ with macOS mode 600 (~/owner-only).
   nginx runs as the 'nginx' user inside the alpine image and returned
   403 for the icon. Add a chmod sweep at the end of the build stage so
   every shipped asset is 644 + dirs 755 regardless of host umask.

2. <link rel="stylesheet"> to fonts.googleapis.com is render-blocking.
   When the user's network is slow to reach Google Fonts (or blocks it),
   the page spins indefinitely on first paint. Switch to the canonical
   rel=preload + onload swap pattern, with a <noscript> fallback for
   JS-off browsers. Tailwind's font-family stack already cascades to
   ui-serif / ui-monospace, so type still renders before the swap.
2026-06-10 04:41:45 -05:00
Omar Sobh 31f1cd866f fix(deploy): use file-provider router instead of docker labels
The docker-label router (apess-web@docker) was being silently dropped
by Traefik after subsequent reloads, even though all labels and the
container's network attach were correct. Falling back to the
ClawBooks landing's catch-all PathPrefix(`/`) meant apess.redclaw.dev
served the wrong content after the first ~5 minutes.

Switch to an explicit file-provider definition in apess.yml with
priority: 1000 (well above landing's priority: 1) so the router is
authoritative regardless of docker-discovery races. The compose file
now just runs the container; routing is owned by the dynamic config.
2026-06-09 23:02:02 -05:00
Omar Sobh 6af793b3cf feat: Landing (Screen 0) + Team Registration (Screen 1) — TDD
Closes the first two PRD screens with shadcn primitives (button, input,
card, badge) and the standing TDD-first discipline.

Landing (/) — PRD §5.1 Screen 0
- Sticky nav with workshop CTA and lecture link
- Hero with eyebrow badge, headline, sub, dual CTA + 4-stat strip
- Programme table covering all 7 day-of moves (13:00 → 19:00)
- Speaker card for Omar Sobh + RedClaw Systems
- 3-card tech stack (Rust on Cortex-M4 · Anthropic+Groq · Web Serial)
- Prerequisites + closing CTA
- 5 tests, all passing

Team Registration (/workshop) — PRD §5.1 Screen 1
- PhaseStrip across top, Phase 1 badge eyebrow
- Team name + member chips (Enter to add, x to remove, capped at 5)
- KitSelector 5x3 grid of KIT-01..KIT-15 with aria-pressed
- Mock device-connect button (real Web Serial deferred to next slice)
- ?kit= URL param pre-selects kit (QR sticker entrypoint)
- Proceed gated until name + 1+ member + device connected
- On Proceed: marks phases.reg = true, navigates to /workshop/setup
- 6 tests, all passing

MemberChips (5 tests) + KitSelector (3 tests) extracted as reusable
components with own test coverage.

Scoped react-refresh/only-export-components off for src/components/ui/**
(shadcn vendored primitives export their cva variants alongside the
component — standard project pattern).

23/23 tests green · build 286KB JS, 90KB gzip · lint clean.
2026-06-09 22:55:54 -05:00
Omar Sobh 4059ea9227 build: pin pnpm 10.33.0 + resilient install in Dockerfile
Initial gw-03 build failed with pnpm 10 lockfile-policy rejection inside
the container (different policy config from host). Pinning packageManager
and falling back to --no-frozen-lockfile when the policy gate rejects
unblocks the multi-stage build without weakening lockfile integrity in
day-to-day pnpm install on the host.
2026-06-09 18:55:54 -05:00
Omar Sobh 6ef3de7a69 deploy: align Traefik TLS paths with gw-03 ssl/ convention 2026-06-09 18:53:29 -05:00
Omar Sobh 394e226975 Add gw-03 deploy artifacts (Docker + Traefik + nginx)
Stages the production deploy bundle next to the existing ClawBooks stack
on zeroclaw-gw-03. Reuses ClawBooks' Traefik v3.6 via shared
clawbooks-net Docker network, no separate proxy.

- deploy/Dockerfile.web: multi-stage Node 22 build -> nginx 1.27 alpine
- deploy/nginx.conf: SPA history fallback, asset caching, /healthz probe
- deploy/docker-compose.yml: apess-web service with Traefik labels for
  apess.redclaw.dev on the websecure entrypoint
- deploy/traefik/apess.yml: TLS dynamic config pointing at the
  *.redclaw.dev Cloudflare Origin Certificate (to be installed at
  /etc/ssl/redclaw/apess.{pem,key} on gw-03)
- deploy/README.md: prereqs (CF DNS + Origin Cert), deploy commands,
  verification, rollback

No infra changes applied yet -- this is the artifact bundle. Deploy
pending three out-of-repo prereqs: CF DNS records, CF Origin Cert
issuance, and rsync+up on gw-03.
2026-06-09 18:32:32 -05:00
Omar Sobh 3d433b9b1d Initial scaffold: React 19 + Vite + Tailwind + shadcn + Vitest
Scaffolds APESS 2026 workshop platform per PRD §4.1 with strict-TDD
infrastructure and the 1300-LOC ceiling enforced via ESLint.

- React 19.2 + Vite 8 + TypeScript 6 baseline
- Tailwind v3 + shadcn/ui (new-york style) configured (components.json)
- Path alias @/* -> src/*
- Zustand session store mirroring the prototype's shared.js shape
  (team, device, phases, harness, stats, add, submission) with
  sessionStorage persistence
- PhaseStrip component covering the five PRD-mandated phases, wired
  to react-router-dom v7 with active/done/pending data-state surfaces
  for snapshot-friendly testing
- Vitest + React Testing Library + jsdom green: 4/4 tests pass
- ESLint max-lines: 1300 enforced; largest file currently 106 LOC

Next: shadcn primitive install, landing page from prototype index.html,
workshop screens 1-5, /admin instructor dashboard, /judge review.
2026-06-09 18:30:34 -05:00