Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and `merge --ff-only` refuses while tracked paths are dirty. Discard is not available here (workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed. - `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new prose — the commit exists so the trunk merge can proceed. - `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat owns (AGENTS.md § Live-sync tiers). `ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the inert all-zero AWS example id — and they appear inside the two skill pages that teach that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal dies with this landing. No `--no-verify` was used: the gate ran and its verdict is recorded here. Refs #61
51 lines
3.3 KiB
Markdown
51 lines
3.3 KiB
Markdown
---
|
|
name: franksign-demo-inspection-stack
|
|
description: "Boot franksign's prod-shaped stack, seed all assignment lifecycle states through the real API, and open a headed inspection tour (platform + storybook) without squatting the e2e port."
|
|
---
|
|
|
|
Visual-inspection recipe for the franksign repo (Dank boxes). Proven 2026-10-20; use when asked to "show/open the platform" or tour a new slice.
|
|
|
|
## Boot (do NOT squat :3100 — the e2e seam curls whoever owns that port)
|
|
```bash
|
|
node --env-file=.env apps/api/dist/cli.js # binds :3000 by default; use named service
|
|
cd apps/web/storybook-static && python3 -m http.server 6007 # gate seam 12 already built it
|
|
curl -s http://127.0.0.1:3000/health # {"status":"ok","db":"up"}
|
|
```
|
|
|
|
## Seed lifecycle states through the real API (cookie jar, NOT bearer)
|
|
better-auth sign-up returns a bearer `token`, but the org routes resolve sessions
|
|
from **cookies only** (`Authorization: Bearer …` → get-session null → 401). Use
|
|
`-c /tmp/jar` at sign-up and `-b /tmp/jar` after; state-changing calls need an
|
|
`origin:` header. Keep auth headers out of argv via `curl -K <file>`.
|
|
|
|
1. `POST /api/auth/sign-up/email` `{"email","password"(>=8 chars),"name"}` → save cookies (`-c`)
|
|
2. `POST /api/orgs` `{"name"}` → `org.id`
|
|
3. `POST /api/orgs/:org/templates` `{"name","baseTemplateId":"sample"}` → `template.id`
|
|
4. `POST /api/orgs/:org/templates/:tpl/assignments` `{"email"}` → `{token, signUrl}` (repeat per demo signer)
|
|
5. signed state: `POST /api/releases/:token` `{"values":{"name":…,"date":…,"agreement":true},"signatureName":…}` — no auth needed (token seam)
|
|
6. voided state: `POST /api/orgs/:org/assignments/:assignmentId/void` (cookie session)
|
|
Remaining pending assignment → three inspectable pages: `/app/sign/:token` renders form / already-signed / cancelled.
|
|
|
|
## Byte-identity spot check (reconstruction contract, issue #18)
|
|
Fetch `GET /api/releases/:token/pdf` twice with `sleep 1.5` **between** fetches
|
|
and sha256-compare, plus the org door `GET /api/orgs/:org/assignments/:aid/pdf`
|
|
(cookie jar). Same-second-only comparisons are blind to clock leaks
|
|
(pdf-lib's `PDFDocument.load` restamps `/ModDate` unless `updateMetadata:false`).
|
|
To see printed text: inflate the content streams and unescape `\(`, `\)` —
|
|
pdf-lib writes hex-string `Tj` operands.
|
|
|
|
## Inspection browser (managed Chromium via browser eval)
|
|
- `viewport` must be `{width, height}` — string fails
|
|
- `tab.waitFor(ms)` does NOT exist (ms is parsed as selector) → `await Bun.sleep(900)`
|
|
- open with `headed: true, persist: true`; window lands on the desktop — confirm with `niri msg windows | grep -i chrome`
|
|
|
|
## Teardown (hard gate hazard)
|
|
A live demo API on :3000 **hangs the full `tests/run.sh` gate for ~10 minutes**
|
|
(observed 2026-10-21: >600s kill with the service up; 14/14 in ~15s without
|
|
it). Always `proc://franksign-demo-api/kill` BEFORE running the gate; verify
|
|
`pgrep -f apps/api/dist/cli.js` is empty so the next `tests/run.sh` e2e seam
|
|
owns :3100 honestly.
|
|
|
|
## Adjacent Gitea quirk (same fleet)
|
|
Closing an issue/PR: `PATCH {"state":"closed"}` → 201; `POST` → 405. Merging needs form-encoded lowercase `do=merge` (see gitea-merge-form-encoded). Label assignment: `PATCH /issues/N` with `labels:[id]` silently clears labels — use `POST /issues/N/labels` `{"labels":[id]}`.
|