Commit Graph

9 Commits

Author SHA1 Message Date
Ben Stull 999c4b65ef §22 M3 frontend: /p/<project>/ routing, runtime branding, directory, 308s (v0.35.0)
Implements the M3-frontend slice of the §22 multi-project track, per
docs/superpowers/specs/2026-06-03-m3-frontend-design.md (design merged in
#10). Completes the runtime-config cut 0.33.0 (M3-backend Plan A) began.

Frontend:
- DeploymentProvider boots GET /api/deployment → {name, tagline,
  defaultProjectId, projects}; brandTitle() neutral 'RFC' pre-fetch fallback.
- /p/:projectId/* routing with generic /e/<slug> segment. ProjectLayout
  fetches /api/projects/:id, applies per-project theme (reset on switch),
  provides ProjectContext, guards the corpus (served only for the default;
  others get NotServedPlaceholder — decouples this slice from Plan B).
- Directory at / (2+ projects) with N=1 redirect into the single project;
  ProjectSwitcher in deployment chrome; entry-noun by project type.
- VITE_APP_NAME hard cut: removed from vite.config + index.html; the 6 brand
  reads now use deployment.name via context; static <title>RFC</title> + JS
  document.title. Internal /rfc·/proposals links → /p/<project>/e|proposals
  via lib/entryPaths.

Backend:
- GET /api/deployment returns default_project_id (the guard contract).
- Server-side 308s: /rfc/<slug>, /rfc/<slug>/pr/<n>, /proposals/<n> →
  /p/<default>/… . nginx (testing + prod) routes /rfc/ and /proposals/ to
  the backend.

Tests: 3 new backend redirect/deployment tests (438 pass); Vitest unit for
DeploymentProvider, ProjectLayout (theme/guard/404), Directory (11 pass);
clean build with no VITE_APP_NAME. Playwright e2e deferred until Tier-1 seeds
a registry (see CHANGELOG 0.35.0 step 5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 05:58:59 -07:00
Ben Stull 0252e40527 v0.34.0: containerize for per-PR preview environments (flotilla SPEC §15) 2026-06-04 01:52:50 -07:00
Ben Stull 34a65e099e deploy(nginx): terminate TLS with the *.wiggleverse.org wildcard, drop per-host certbot
Restructure the ohm vhost from the pre-certbot template into an explicit
80->443 redirect + hand-managed 443 TLS block, pointed at the wildcard cert
installed on the VM (/etc/ssl/certs/wiggleverse-wildcard.crt + the key under
/etc/ssl/private). Adds modern ssl_protocols/session settings that previously
came from certbot's managed snippet. All CSP/HSTS/security headers, root, and
locations preserved verbatim. Enables flipping ohm to the Cloudflare orange
cloud (SSL mode Full strict). Cert files must be installed before reload;
retire the old cert with `certbot delete` once cut over.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 02:57:02 -07:00
Ben Stull 714c2aed86 docs(deploy): correct stale infra facts after GCP name-alignment
The deploy docs predated the GCP name-alignment and described
infrastructure that no longer exists. Discovered during the v0.31.4
deploy. Corrections:

- Project wiggleverse-rfc -> wiggleverse-ohm; VM rfc-app -> ohm-rfc-app;
  install path /opt/rfc-app -> /opt/ohm-rfc-app; system user + service
  rfc-app -> ohm-rfc-app; external IP 34.132.29.41 -> 136.116.40.66.
- SSH is now IAP-only (direct port 22 times out): document
  --tunnel-through-iap on every gcloud compute ssh.
- Meta repo wiggleverse/meta -> wiggleverse/ohm-content.
- Two-remote reality: the VM's git origin is git.benstull.org/benstull/
  rfc-app, a SEPARATE Gitea from the release one (git.wiggleverse.org)
  that does not auto-mirror — so a release must be pushed to the
  benstull remote before the VM can fetch it. The VM tracks a detached
  release TAG, not a branch.
- Frontend-only changes are live once dist/ is rebuilt (nginx serves it
  directly); pip install only when requirements.txt changed.

Docs-only; no version bump (cf. the docs-only commit after v0.31.3).
The First-Time Deployment blocks keep the structural commands with a
substitution note rather than unvalidated rewrites.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 10:15:58 -07:00
Ben Stull bd3ef269d4 Release v0.27.0: security hardening (audit 0026)
Remediates the rfc-app application + deploy-config findings from the
Session 0026 security audit. Cut as the "v0.25.0-security-hardening"
branch (from v0.24.0); reversioned to 0.27.0 on rebase onto main since
v0.26.0 (#28) shipped while this was in flight.

- C1 (Critical): single sanitizeHtml.js chokepoint (DOMPurify) for every
  marked→innerHTML / dangerouslySetInnerHTML sink (MarkdownPreview,
  ProposalView x2, Editor); rel=noopener hook on target=_blank links.
- H1: per-account OTC-verify lockout (migration 023, auto-applied) +
  per-IP throttle via new ratelimit.py; wired on otc verify/request +
  passcode check/verify.
- M1: device_trust.lookup() single indexed-row read — cookie value is now
  "<row_id>.<raw_token>"; bcrypt-checks one row, not a global table scan.
  (Behavior change: existing device-trust cookies re-prompt once.)
- M2: HTTP security headers (CSP/HSTS/XFO/XCTO/Referrer-Policy) at nginx.
- M4: session cookie Secure-by-default (SESSION_COOKIE_SECURE opt-out).
- M5: bounce webhook fails CLOSED (503) when secret unset, instead of open;
  RFC_APP_INSECURE_BOUNCE_WEBHOOK=1 dev opt-in.
- L2/L3: per-IP cooldown + check-endpoint throttle.
- L4: systemd sandbox knobs. L8/I1: nginx server_tokens off + TLS1.0/1.1 out.

VERSION + frontend/package.json → 0.27.0; CHANGELOG documents the upgrade
steps (incl. the out-of-band nginx + systemd apply, which the flotilla
deploy gesture does not perform).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 18:28:10 -07:00
Ben Stull 21fcbc92d4 Release 0.3.0: private-beta gate + anonymous read mode
Adds an email allowlist (toggleable per deployment) that restricts
OAuth sign-in to listed emails while keeping read paths public.
Anonymous visitors now see the full app shell in read-only mode
instead of the §14.1 landing wall. Empty allowlist = gate off, so
deployments that don't enable it behave exactly as 0.2.3.

Also fixes single-finger scroll on /philosophy and other .chrome-pane
views on iOS Safari (.app: 100vh → 100dvh).

Renames deploy/nginx/rfc.wiggleverse.org.conf →
ohm.wiggleverse.org.conf to match the deployed-domain rename
(rfc.wiggleverse.org deprovisioned 2026-05-27).

See CHANGELOG.md for full details + upgrade steps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:58:58 -07:00
Ben Stull ee6e3491e7 Drop "prototype/carryover" framing now that v1 is shipped
SPEC, DEV docs, and code comments still talked about the codebase as
a rewrite-in-progress against an external prototype. With v1 shipped
the framing reads oddly — it implies code is provisional when it's
the production thing. Recast §18 as "the technical stack," strip
"carryover from the prototype" comments across backend (api.py,
chat.py, providers.py) and frontend (DiffView, PromptBar,
SelectionTooltip, modelStyles), and rework SPEC §1 / §18 to introduce
OHM up front rather than as a follow-on to a prototype reference.

Also:
- RUNBOOK: bump Python prereq to 3.11+ to match the production VM
  (was 3.13).
- Remove IMPLEMENTATION-PROMPT.md — the original implementation brief
  is no longer load-bearing.
- Add deploy/DEPLOY-NEW-SESSION-PROMPT.md as the durable
  deploy-handoff prompt for new sessions.
2026-05-25 10:32:46 -07:00
Ben Stull 36635049c7 Slice 8: v1 ships — integration coverage, runbook, spec corrections
- Five new integration test files raise the suite from 75 to 96 green:
  test_hygiene_vertical (7), test_branch_path_routing (4),
  test_metadata_pr_merge (3), test_cache_bootstrap (4), test_e2e_smoke
  (3). The smoke test walks propose → super-draft → edit branch →
  body-edit PR → graduate → active-RFC PR → merge → notification →
  hygiene-sweep deletion end-to-end.
- deploy/RUNBOOK.md replaces the prior DEPLOY.md stub as a real
  runbook: prerequisites, first-time bring-up, day-2 ops (logs, DB
  backup, secret rotation, the §12 hygiene cadence), rollback shape,
  troubleshooting table.
- backend/.env.example grows the SMTP block, HYGIENE_TICK_SECONDS,
  and WEBHOOK_EMAIL_BOUNCE_SECRET with inline commentary.
- README points to RUNBOOK.md; the "what the build lets you do"
  section adds Slices 7 and 8.
- docs/DEV.md gets a Slice 8 — shipped section; the "Next slice"
  footer becomes the v1-complete epitaph.
- SPEC corrections per the §19.3 working agreement: §10.7 names the
  shared §12 sweep; §12 names the bot as actuator and the per-user
  branch_chat_seen preservation contract; §19.1 marks v1 complete
  and records Slice 8; the five §19.2 candidates Slice 8 folded in
  are marked settled with pointers at the resolution.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 04:14:50 -07:00
Ben Stull 33d9d7a482 Add deploy/ — nginx vhost, systemd unit, runbook
Single-host deployment of the app at rfc.wiggleverse.org alongside
the existing Gitea instance. nginx reverse-proxies /api/* and
/auth/* to a single uvicorn process on 127.0.0.1:8000 and serves
the Vite build output as static files; certbot adds the TLS cert
in place; systemd supervises the process per §4.2's
single-process-with-WAL-SQLite contract (one worker; raising
--workers would break the invariant).

deploy/DEPLOY.md is the step-by-step runbook covering host prep,
Gitea bot + OAuth setup, .env shape, meta-repo seed, nginx +
certbot, systemd, smoke test, and the update/rollback shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 05:18:28 -07:00