phase: 101_tokens_page_overhaul
Build and Push Containers / build-and-push-app (push) Successful in 1m49s
Build and Push Containers / build-and-push-db (push) Successful in 13s

All gates verified green — no defects found, nothing to fix. Final report:

## Phase 101 — final verification pass (all tasks already complete; verified, not re-implemented)

**Verified against the working tree** (task files 01–04 present in `complete/`):
- Active/revoked table split (Status column gone, section hidden while 0 revoked, per-table search with query state surviving re-renders) in `frontend/index.html` + `tokens.js`
- `generateToken()` refuses blank/whitespace names (`Give the token a name first.`, no request); `|| "token"` fallback deleted
- Atomic rotation: `regenerate_token` service + `POST /api/tokens/{id}/regenerate` (201 new-plaintext-once / 404 / 409 / router-wide 403) + `TokenListItem.revoked_at` (D5)
- Regenerate two-step confirm UI + CSS (`.token-regenerate`, neutral hover, no new hue); A4 pins intact

**Test / lint / coverage results:**
- `uv run pytest` → **2065 passed**
- `uv run pytest --cov=app --cov-report=term-missing` → **TOTAL 99%** (>90% ✓)
- `uv run ruff check . && uv run pyright` → clean (0 errors)
- `uv run pytest tests/e2e/test_tokens_page.py -v --no-cov` → **4 passed** (isolation, DB up)
- Regression, each in isolation: `test_api_tokens.py` **9 passed**, `test_admin_auth.py` **6 passed**, `test_shared_header.py` **6 passed**, `test_theme_semantic_completion.py` **8 passed** (its revoked-pill pin was correctly re-scoped to the revoked table in this phase)

**Completion criteria:** 1 ✓ split+search (E2E 1–2) · 2 ✓ required name (E2E 3 + source pin) · 3 ✓ rotation end-to-end, old token refused at gate (E2E 4 + API 404/409 pinned) · 4 ✓ A4 holds (list carries no plaintext/hashes) · 5 ✓ suite/coverage/lint green · 6 ✓ E2E + regressions green in isolation · 7 commit left to the harness per executor rules (all changes uncommitted in the working tree)

**Deviations:** none. Next pending phase: `98_sync_summary_visibility`.
This commit is contained in:
2026-09-12 15:16:02 -04:00
parent 58e9d94cff
commit 4dbac1660a
32 changed files with 2321 additions and 150 deletions
+54 -2
View File
@@ -3167,14 +3167,66 @@ details.thinking .thinking-text ul { margin: 0 0 0.5rem; }
}
.token-revoke:hover:not(:disabled) { background: var(--err-bg); color: var(--err-ink); border-color: var(--err-line); }
.token-revoke:disabled { opacity: 0.5; cursor: wait; }
/* Empty-state row: the muted centered message at full table width
(the .history-empty-row language, inline in the table). */
/* Regenerate (phase 101 task 03, D2): the .token-revoke's structural
twin — the SAME size / border / radius / focus, the transparent
fill + ink-soft text — but the NEUTRAL action's hover
(brand-soft / brand-ink), NOT the revoke's error hover: a
rotation is a hand-out of a successor, not a deletion (no new
hue — the phase-92 monochrome invariant). The confirm pair
reuses the .history-confirm-* classes unchanged (the pair CSS
above). :disabled mirrors the revoke button's rule (the
in-flight state, while the rotation POST is out). */
.token-regenerate {
min-height: 44px;
padding: 0.35rem 0.7rem;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: transparent;
color: var(--ink-soft);
font: inherit;
font-weight: 600;
font-size: 0.82rem;
white-space: nowrap;
cursor: pointer;
}
.token-regenerate:hover:not(:disabled) { background: var(--brand-soft); color: var(--brand-ink); }
.token-regenerate:disabled { opacity: 0.5; cursor: wait; }
/* Empty-state + search no-match rows (phase 101): the muted centered
message at full table width (the .history-empty-row language,
inline in the table) — CLASS-based, so both the active table's
#tokens-empty-row / #tokens-no-match-row and the revoked table's
#tokens-revoked-no-match-row share it. */
.tokens-empty-row td {
padding: 2.25rem 1rem;
text-align: center;
color: var(--ink-soft);
font-style: italic;
}
/* Phase 101 (task 02, D4): the per-table live label search — the
house input surface (the #token-label / archive-upload input
family: --line hairline, --surface fill, ink text — AA pairs, no
new hue), full width, the ≥44px target, the global :focus-visible
ring (no custom focus rule — the house pattern). */
.token-search {
width: 100%;
min-height: 44px;
padding: 0.55rem 0.8rem;
border: 1px solid var(--line);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--ink);
font: inherit;
font-size: 0.9rem;
}
/* The revoked section's sub-heading (phase 101 D1): the phase-97
.kb-level h2 voice — mono, 1rem, brand-ink (the path voice, AA on
the page background). */
.tokens-revoked-heading {
margin: 1.5rem 0 0.5rem;
font-family: var(--mono);
font-size: 1rem;
color: var(--brand-ink);
}
/* ---------- Theme view (phase 91, tasks 04 + 05) ----------
The shell's seventh view (#view-theme): the admin palette + branding