# PURE Site Governance â build spec (Code + Design)
*Authored by Lane A (Design) Â· 2026-06-30 18:00 CT Â· canon key suggestion: `pure.governance`*

**Mike's rule (verbatim intent):** *"We can't deploy something we can't control."* Every page on acquisto.biz must be **registered, kill-switchable, role-scoped, reachable, on-brand, live-data-bound, link-clean, and owned** â and stay that way automatically as new pages ship. This spec defines the registry, the tiered scans, the crons, and the store linkage. Design owns the **Site Control** surface (a tab in `pure-admin-console`, the canonical Pure Admin Center); Code owns the table + RPCs + crons.

---

## 1. `pure_pages` â the page registry (Code builds)
One row per top-level page. The single source of truth for "what exists and how it's controlled."

| column | type | notes |
|---|---|---|
| `path` | text PK | e.g. `pure-location.html` |
| `title` | text | from `<title>` |
| `module` | text | owning module (crm, brand, tech, deals, marketingâ¦) |
| `owner_hat` | text | role that administers it (tech, brand, brokerâ¦) â drives orphan check |
| `enabled` | bool default true | **kill switch**. false â page redirects to a "temporarily unavailable" notice |
| `visibility` | jsonb | array of hats allowed to see it in nav, e.g. `["tech","broker"]` |
| `status` | text | `new` Â· `reviewed` Â· `parked` (mirrors `pure_boneyard`) |
| `strictness` | text | `soft` (default) Â· `staff` Â· `strict` â see Â§5 ratchet |
| `scan` | jsonb | last scan result per check (see Â§3) |
| `scan_tier` | text | `fast` Â· `medium` Â· `deep` â last run |
| `scanned_at` | timestamptz | |
| `store_product` | text null | linked Pure Store product slug, if any |
| `first_seen` | timestamptz | set on first registration (drives the 30/90-day ratchet) |
| `reviewed_by` / `reviewed_at` | text / ts | admin sign-off |

**RPCs:** `mcp_pages_list(p_module?,p_hat?)` Â· `mcp_page_get(p_path)` Â· `mcp_page_set(p_path,p_patch jsonb)` (enabled/visibility/owner/store_product/status â **gated `mcp_action_preflight`**, admin only) Â· `mcp_pages_scan(p_tier,p_paths?)` (runs the scan, writes `scan`/`scanned_at`) Â· `mcp_pages_register()` (the sweep â see Â§4).

---

## 2. Soft enforcement + immediate sweep (Mike's pick)
- **New pages are NOT blocked on deploy** (we're building fast). Instead the **registration sweep** auto-registers any unknown page as `status:new` with `strictness:soft` and **safe-default visibility** (admins/staff only until reviewed â see `new_page_default`).
- The sweep runs **on a schedule (Nx/day, default 4Ã) AND on-demand** ("Run sweep now" button in Site Control). After each run it **posts the new/changed pages into the Pure Admin daily update** for review. If an admin doesn't act, the page **stays live at its safe default** (not hidden) and is **rollback-able** later.
- This is the "soft now, ratchet later" model â Â§5.

---

## 3. Tiered scans (admin-configurable from Site Control)
Three depths so admins can trade speed for thoroughness. **The check list itself is data-driven** (`pure_scan_config` table: `check_key`, `tier`, `enabled`, `severity`) so admins toggle checks without a deploy.

**FAST** (seconds â run on every sweep):
- `registered` â in `pure_pages`
- `killswitch` â has an `enabled` row
- `favicon` / `canonical` / `viewport` present
- `title` present & non-generic

**MEDIUM** (Fast + ):
- `visibility_set` â has a role scope
- `owner_assigned` â `owner_hat` non-null
- `reachable` â linked from `/pure-home` for its `owner_hat` (no orphans)
- `brand_tokens` â uses canon `--brand/--gold` vars + Montserrat/canonical fonts (no off-brand hexes like `#11213a`, no rogue gradients)
- `auth_gate` â token-sending pages use `PureAuth.authedFetch`

**DEEP** (Medium + ):
- `live_data` â flags hardcoded values that should bind to RPC/`PureLive` (SAMPLE badge present where unbound)
- `link_health` â every internal link resolves (no 404s)
- `store_match` â has a relevant Pure Store product linked (see Â§4)
- `a11y` â alt text, contrast, focus states
- `dict_terms` â uses canonical `pure_dictionary` terms (dict-lint)

Each check writes `{status: ok|warn|fail, note}` into `pure_pages.scan`. Site Control renders these as badges; admin can **override/snooze** any check per page (stored), because *we control it*.

---

## 4. Governance crons (Code schedules in Supabase)
All are **idempotent, additive, logged to `audit_log`**, and **manually runnable** from Site Control (Mike's ad-hoc requirement). Group: `governance`.

| cron | cadence | does |
|---|---|---|
| `pages_register_sweep` | **4Ã/day** (6/12/18/0 CT) + on-demand | discovers pages from the repo tree â upserts `pure_pages`, runs FAST scan, posts new/changed to the daily admin update |
| `pages_orphan_scan` | nightly | every page must be reachable from `/pure-home` for its `owner_hat`; strays â auto-nominate to Boneyard candidate (never auto-delete) |
| `pages_linkcheck` | nightly | DEEP link-health; dead links â `pure_board` task |
| `pages_brand_audit` | nightly | brand/token/favicon compliance; drift â task + flag |
| `pages_store_match` | daily | for each page, find a fitting Pure Store product; **link it** (encourage the sale per standards). **If none fits and one should exist â post a `pure_board` task tagged `product-create`** so a builder cron/agent makes the product |
| `pages_strictness_ratchet` | daily | advances `strictness` by age (see Â§5) |
| `pages_dict_lint` | weekly | dict-term compliance |

The daily **Pure Admin update** aggregates: new pages, failed checks, orphans, dead links, brand drift, store-match gaps, ratchet changes â one review feed.

---

## 5. Strictness ratchet (soft â strict over time)
Mike: *"soft nowâ¦ toggle stricter over timeâ¦ 30 days up, 90 days very strict."* Per-page, by `first_seen` age â **admin-overridable** at any time:

- **0â30 days â `soft`**: auto-register, safe-default visible, warns don't block.
- **30â90 days â `staff`**: must have owner + visibility + pass MEDIUM; failures demote to staff-only until fixed.
- **90+ days â `strict`**: must pass DEEP (live-data, link-health, store-match, a11y); a hard fail flips `enabled:false` (kill switch) and files a task. *(Global ratchet level also adjustable from Site Control so Mike can accelerate.)*

---

## 6. Cross-lane memory (set these in `pure_memory`)
- `pure.governance` â this spec (page registry + scans + crons + ratchet).
- `routine.turn_sizing` â *"Parse big builds into one-surface-per-turn chunks: write â preview â deploy â checkpoint. Never batch multiple large file writes + screenshots + deploys in a single turn (causes response overrun). Checkpoint after each deploy so an interruption resumes cleanly."* (Lane A operating lesson, 6/30.)

---

## 7. Design â Code notes (answering Code's 4 relay items)
1. **`boneyard.html`** â DONE on Design side: it reads the live `pure_boneyard` table via `PureLive.rpc('mcp_boneyard_list')` with fail-soft to seed+local, has cat/tag filters, the "Go to current version" `replacement_url` link, the bone watermark, and a **Park-a-URL one-step modal** (`mcp_boneyard_park`). Code: confirm `mcp_boneyard_list`/`mcp_boneyard_park` signatures match.
2. **Merged hub linking (~60 tools)** â Design decision: **"All Modules" directory section** on `/pure-home` (a searchable grid) rather than an ever-expanding rail. Code: supply the link dataset (`path,title,module,owner_hat`) â ideally just expose `mcp_pages_list`, and the hub renders from it (one source, no drift).
3. **Transplant homes** â secure-doc-share â **Deals/Transaction Room**; 3FA step-up â **Profile/Security** (invoked on sensitive actions); dict-lint â **Brand Workspace** (Cecile) + a Site Control check. 
4. **`testdrive.html`** (Ana's tour) â keep/current, leave untouched.

**Net for Code:** build `pure_pages` + `pure_scan_config` + the 7 RPCs + 7 crons above; expose `mcp_pages_list` for the hub directory; set the two `pure_memory` keys. Design builds Site Control + the All-Modules directory + the Meetings hub against these.
