Changelog
What we shipped, in plain language. Generated from our commit history, so it cannot quietly fall behind the product.
Features
- trust: W6 launch — announcement copy + a credential-rotation qualifier on the RLS trust claim
- billing: say the 14-day refund window BEFORE the money moves
- gates: wire typecheck into local_ci -- it was running in no lane at all
- local_ci: refuse a dirty tree, void a verdict whose tree moved (owner ruling)
- identity: record released email addresses, close HOUSE-R-175 Half A (0056)
- identity: key OAuth identities on the provider subject, not the email (HOUSE-R-175)
- shell: head metadata — brand-first title, description, OG basics
- shell: account credential cards + change-email landing; gate the Cancel surface for Free households (HOUSE-R-146, HOUSE-R-163)
- identity: self-service change-email + change-password (HOUSE-R-146)
- gateway: serve the Apple Pay domain association file
- paddle: the arming pre-flight, the dunning gap's real defect, and the runbook
- release-os: let the health pass be re-run without deploying again
- release-os: the prod path — typed confirmation, the 423 lock, and automatic promotion
- release-os: the preprod deploy button, streamed progress, and the health pass that arms the lock
- release-os: mechanical review facts, and an AI digest that can never become one
- release-os: the git map, the wire probes and the diff view
- release-os: the deploy pane's skeleton — prod lock, HTTP gates, Jarvis child on 8768
- gates: HOUSE-R-134 price-map CONTENT gate + HOUSE-R-133 late-claim ledger tie test
- seo: write the robots.txt and sitemap the site has been 404ing, and gate them
- preprod: mount vonkara/heldaro/kragara into the preprod compose
- registry: declare Kragara's content surface as a CLASS + the DISJOINT gate
- refund: the tracked refund-request queue — a mechanism for the 14-day promise
- copy: reposition the regulated wording, place the claim footnotes, clear the landing jargon
- catalogue: declare the levers Vonkara and Kragara actually enforce
- catalogue: remove the hollow Capacity pack, and retire the rung its price was propping up
- catalogue: park the Office SKU — it sold two features that 403 for every House buyer
- auth: let a person actually verify their own email
- legal: the POPIA data-subject request machinery — cluster A closed
- gates: watch the compliance docs; framework §12 — before a new purpose ships
- identity: waitlist marketing consent (POPIA s69) + the dormancy ruling
- docs: F2 notice on Ask-the-docs; F3 checklist; PIIA corrected — F2 was already live
- identity: enforce the 18-or-older attestation on both signup doors (PIIA F1)
- legal: PIIA (Reg 4(1)(b)) — G3 closed; four claims found ahead of their mechanisms
- legal: Reg 4(1)(a) compliance framework + request register; correct a 2FA over-claim
- legal: generate the PAIA manual PDF; s51(3)(b) needed one and none existed
- legal: E4 fully closed — the IO was registered on 2026-08-06, cert 2026-063826
- legal: E4 — PAIA entity facts filled, plus the s55(2) gate the fill created
- finance: Phase 9.3 — zero opening basis RATIFIED + marker one-shot + basis_at cutoff
- finance: Phase 9.4 — the v1-vs-v2 divergence reporter (shadow-period second half)
- finance: Phase 9.1 — prod finance lane behind the owner-ratified arm var
- finance: Phase 8.4 — partition roller sidecar (posting survives the year boundary)
- finance: Phase 8.3 — KRI/reporting layer on the tie-out sidecar
- finance: Phase 8.2 — AR/manual-collection lane per the ratified CAO shape
- finance: Phase 8.1 — payment_attempt/dunning projection lane
- finance: ruling 6.1 v2 Stage 1 — tax-only fee-return detection, posts nothing
- erasure: finance retention phase in check_erasure_safety + schema-wide preflight (Ruling G)
- finance: implementation wave 2 — the projector, the tie-out engine, and their teeth
- preprod: wire the finance-v2 lane — finance-migrate, projector + tie-out sidecars, inbox flag
- finance: implementation wave 1 — uuid7, inbox ingest lane, roles+guards, RETAIN class, containment gate
- finance: fold Phase 3 wave-2 board conditions + owner-ratified CLO rulings
- finance: Phase 2 — the greenfield finance schema proposal (DDL + design + uuidv7 gate)
- preprod: Phase 0 — generated Caddyfile.preprod + gate, gateway bake, money-path compose subset
- t5: the gate over the gates — one mechanism for teeth-loss, and the three gates it found
- t4-6: control total + stuck-reservation sweeper for the free-tier AI meter
- billing,shell: name the period-end DATE before the cancel click — S3d §5.K-B
- billing: resolve a returning customer's household when the nonce is dead — R-133 opt 2
- identity,shell: let the reset link follow the server's email capability — HOUSE-R-017
- billing: detect charge-after-cancel — nothing ever scanned cancel_request_open
- billing,shell: show a SCHEDULED cancel on every visit — S3d §5.K-A
- billing: claim-side grace for a late first webhook delivery — HOUSE-R-133
- billing: content-aware money-path signal on /version — HOUSE-R-134
- legal: S4b — legal pages authored vs actual tracking + R-128 acceptance recording (roadmap §C2–C6)
- erasure: PR-4.2 right-to-erasure built + gated — closes R-052 + R-126 (roadmap §C1)
- billing: tag the personal-suite refund contra with its room (S3b-2)
- registry: hero addons unsellable until the Q4 allowance consumer ships (S3b-1)
- shell: the v2 purchase surface — per-room tier cards + room-overlay plans (S3a)
- analytics: checkout_opened — the funnel's missing middle step (S3a)
- shell,analytics: S2d — first_value_reached event, R-018/R-019 UX dead-ends closed
- tour: UXD-27.10 — the tour rides the 2D world, and the home mount is pinned
- world: the 2D world becomes the home, and the 3D lot becomes the testbed
- world: the 2D world rendered through the S1b seam — panorama, badge, line, doors
- world: the 2D world's sixteen rooms + their hotspot geometry, with a gate
- lot-art: Timeless Lot room panoramas -> production assets + provenance
- tools: parameterise room_probe's target slug
- tools: room_probe — prove a mounted room BOOTS before a human walks it
- tools: local_ci — a runner you can trust when Actions minutes are gone
- tools: a live-shot harness — see the world, not a diagram of it
- tour: intent capture as the tour's opening beat (W1-2, UXD-20)
- lot: the generalised armature — UXD-22/23/24, bands, and a level axis
- lot: draw the lot as a PLAN, and ratchet the thing it exposes
- tour: video-scene direction — script for approval, free roam restored, build gated
- tour: move the tour onto the LIVE LOT, driving its own spirit (W1-1i)
- tour: she FLIES, the first pass runs itself, and actions get a nudge (W1-1c)
- tour: the two presenters — 2D room card + 3D werf guide (W1-1b)
- werf: keep FELT Rykie - the procedural rebuild was wrong (owner call)
- werf: Rykie rebuilt in the werf's own material language
- tour: the mascot tour spine (W1-1) - runtime, types, locale guard
- signup: close self-serve signup behind a waitlist (UXD-12)
- werf: build out the werf - two wings close the courtyard, products bound to buildings
- werf: material + scale gate with teeth (owner ruled full scope)
- werf: engine proof round 3 — polish + condition 5 answered
- werf: engine proof round 2 — the silhouette test now passes
- werf: the engine proof for the world direction — round 1, partial pass
- email: wire the six SES SMTP env vars into identity — the runbook's no-compose-edit claim was wrong (O-5 class)
- i18n: Paraglide JS across the House-owned surfaces, en + af
- growth: public roadmap (Fider) + generated GA-gated product directory
- lot3d: seat the study round-2b re-roll — warm-umber graduation set (CWO PASS)
- lot3d: Phase-1 signatures — ship FIVE vignettes; study re-roll pending (owner rulings)
- privacy: replay erasure runbook + export metadata — close the P1/P2 replay trust gaps
- lot: in-world upsell overlay — a locked-room click no longer ejects to /account (P0/E1)
- analytics: register fireplace_entered — D3 dwell baseline
- world-ux: wire the wave-1 lot HUD/scene changes (D1.1-D1.5, D2, D3)
- world-ux: Account control, Help card, postcard fallback components
- world-ux: D1.2 first-paint splash + branded loading rungs
- world-ux: pure decision helpers for the wave-1 lot interactions
- gateway: bake docs dist + route /docs and /api/ask-docs (no new hostname)
- ai-egress: "Ask the docs" RAG endpoint on the egress chokepoint
- docs: Starlight docs workspace + Scalar API reference (baked under /docs)
- replay: gateway @replay surface (forward_auth, before /api/* catchall)
- replay: shell recorder + consent UI + default-deny + viewer
- replay: DB sink + identity ingest/viewer routes
- flags: the shell/product consumer seam — useSession().hasFlag + the exported hasFlag helper
- flags: the flag:<name> gradual-rollout namespace — /_verify DB-resolved, fail-soft, kill-switched (FLAGS_ROLLOUT_DESIGN.md)
- analytics: bake the Umami website id — the landing beacon goes live
- analytics: re-enable Umami — pgcrypto fixed, migrate hand-proven
- pricing: P7 RATIFIED — Math Board 2026-07-19 verdict recorded, price gate flipped
- pricing: encode Math Board caveats — allowance 75, refund clamp, trial policy, overage invoicing
- identity: /_verify enforces expires_at at read time + mints X-House-Allowances
- billing: v2 runtime — one-main CAS, tier reconcile, allowances write, 0031 hardening; suite 24F/55P -> 99P
- analytics: T0-3 in-house product-analytics pipeline (HOUSE-R-007 storage half)
- catalogue: P7 go-live price gate — LIVE Paddle sync refuses unratified seed prices
- tools: sync_paddle_catalogue — the registry is the source of truth, Paddle is derived
- catalogue: registry 0.3.0 — per-room tier ladders, packs, hero addons + catalogue gate v2
- shell: /verify-email landing page (unblocks the email-verification prod-flip)
- identity: email delivery seam for forgot-password + verify-email (HOUSE-R-017)
- billing: book non-USD MoR settlement in the functional currency (HOUSE-R-012)
- identity: build the self-serve password-reset flow (HOUSE-R-017)
- lot3d: the tree wears its coils — sitting 2b PASSES and F3 CLOSES with zero residuals
- lot3d: F3 sitting 2 — the walk winds, the facade closes, the rim rings (5 of 6 shipped)
- lot3d: the clip gate sees the signature anchors — and its first run caught two real clips
- lot3d: the wall probe PASSES — the house is felt (sitting 1b)
- lot3d: F3 sitting 1 — 6 of 8 assets shipped; the yard comes alive
- lot3d: the felt hill — plateau, skirt, treeline, stitch hem + drag clamp (W4a)
- lot3d: F3 AUDIT #1 + every confirmed composition/scene fix (W2+W3)
- 3d: F3 W1 eyes — unpack_kit.py + render_lot.py headless review renders
- lot3d: F3 W0+W1 CI slice — clip/parity + material-law gates, day-one fixes
- lot3d: spirits roam free — home-tethered wander per the motion law
- lot3d: F2 — the spirits move in (Rykie, Vonkie, Heldie, Kraggie)
- lot3d: the lamplighting — dusk parity pass (Track D round 2)
- lot3d: the amber hour — dusk horizon glow + warm dusk grade (Track D gap fix)
- 3d: Tier-3 felt pass — cream walls + oak floors; compose fixes
- lot3d: V3 re-compose of the default lot — the Hearthfelt landmark silhouette
- 3d: Hearthfelt Minimum Lot Set installed — 11 new pieces + 4 replacements, catalog + thumbs
- 3d: Hearthfelt intake processor + proof-round adjudication + batch convention
- gates: token-drift gate covers the mascot-law colours (star-glow, ember, krag)
- lot3d: Hearthfelt F0 — warm token night, a sky full of homes, hearth glow, void fix
- kragara: wire the ingest+generate worker + ai-egress base URL (Kragara W6a/W6b go-live)
- dashboard: remediation steps per risk row — normal + novice toggle, "no known fix" highlight (#58)
- dashboard: one-click interactive viewer (dashboard.cmd → localhost server + Run buttons) (#57)
- dashboard: DASH-P1b + P3 — light the last blind lanes + verdict-change alerting (adversarially reviewed) (#56)
- dashboard: DASH-P1 — module-budget gate (lights blind QUA) + reconcile newly-measurable rows (#55)
- dashboard: DASH-P2 — must-act aging + multi-run history/trend (assess change, not just state) (#53)
- dashboard: EFF efficiency dimension + apply the top-tier infra optimizations (#52)
- dashboard: house health + risk register dashboard (tools/house_health.py) (#50)
- shell: wire the paywall into the 3D lot + delete the dead 2D-lot engine (#46)
- gateway: serve Microsoft publisher-domain verification file
- shell: Phase 2 — per-product 'open the door' room previews
- shell: Sterryk legal pages + close Phase-1 gaps
- shell+identity: Sterryk landing + /login + /signup + 14-day gate + Google/Microsoft OAuth (Phase 1)
- gateway+services: X-Request-Id correlation (PR-2.6) + /healthz probes & compose healthchecks (PR-2.5)
Fixes
- main is red — HOUSE-R-208 is missing 'opened', and the changelog is stale
- repair risk/RISK_REGISTER.yaml — the previous commit left conflict markers
- docs: declare the W6 claim table's terminal status for doc_freshness
- disclose the new storage key, correct R-178's likelihood, regenerate
- auth: clear the verification card in OTHER tabs too
- auth: don't show "Send verification email" to someone who just verified
- nav: the You menu opened off the top of the screen in the 2D world and on landing
- auth: tell the refused OAuth visitor how to actually fix it
- release-os: isolate the ledger in the selftest's HTTP section
- registry: re-sync the baked catalogue copies after the Paddle reclassification
- local_ci: the selftest fixtures tripped the secrets scanner
- shell: providers can be null where the card stays mounted (TS18047)
- shell: change-email warns that provider sign-in follows the address; the cancel empty state no longer asserts a negative from an unresolved fetch (HOUSE-R-163, HOUSE-R-175)
- identity: pending change-email tokens die on credential rotation; issue supersedes; escape the takeover notice; control-char email floor (HOUSE-R-146 review)
- runbook: the login is team@sterryk.com — finance@ has limited rights
- runbook: Step 1 named one scope where six are needed
- gates: a tooth that could not run is a FAILURE, not a skip — and a correction to HOUSE-R-172
- gates: bound the vitest worker pool — the shell suite was running 28 of its 404 assertions
- gates: a generated artifact is not a broken pointer — and file HOUSE-R-172 for the vitest OOM
- services: stop sentry re-wrapping every sync endpoint once per request
- release-os: give the health pass a wire settle budget, and stop a prod pass claiming to arm
- release-os: check Vonkara for REACHABILITY, not for a sha it can never report
- release-os: deploy_lag is ADVISORY — it asks a different question from the health pass
- gates: risk/RISK_REGISTER.md gets the diff-guard it was already annotated as having (HOUSE-R-170)
- money: HOUSE-R-154 hard revocation outranks grace + HOUSE-R-155 per-period seat tie-out
- gates: run the F14 per-route forward_auth walk on the REAL Caddyfiles (HOUSE-R-014)
- shell: scrub token URLs from rrweb replay capture + declare Referrer-Policy (HOUSE-R-144)
- identity: revoke-by-subject epoch, atomic registration guard, reset-issuance floor (HOUSE-R-164/150/144)
- gates: check_gate_teeth read role/DSN state PR #87 moved to gate_db_roles
- health: house_health --full gave every DB gate ONE DSN — six read red for the role, twelve for the absence
- web: trust.sterryk.com answered 200 to every path — HOUSE-R-147's disease on a second host
- tooling: local_ci --help died on a cp1252 console — the gate crashed on the box that needs it
- qua: HOUSE-R-152 — gates DECLARE known-bads and nothing re-ran them; execute the corpus
- auth: HOUSE-R-139 — a tab woken past expiry took the row's own symptom; single-flight reissue
- ci-guard: add -Windowless, so the hourly watchdog stops opening a console
- docs: CLAUDE.md's plan-of-record pointer targeted a deleted plan file
- i18n: drop orphaned feature_ai_analysis key after the O3 pull — feature_labels + i18n gates green
- registry: pull "AI analysis" from Heldaro Free (O3, owner-ruled)
- account: gate the Cancel-tab screen on pendingCancelAt (M4/F-041 residual)
- account: anonymous /account is no longer a dead end (M3/FLW-A-04)
- pricing: disclose the invite gate before the CTA click (H6)
- landing: CTA honesty while signup is closed (H6/CXO-A-05/FLW-A-06)
- account: route the support-email link text through a message key
- auth: LoginPage renders the session-expired banner (H5/E3 contract)
- identity: M5/F-052 — /account seats figure is the purchased seat block, not the member count
- account: activation-stall message now has an escape route
- auth: a refused invite code now shows why, keeps what you typed
- landing: topbar responsive at ~480px, Sign-up CTA no longer clipped
- directory: /directory drops banned system-ui + rogue accent, gates dead Office CSS
- shell: H1/FLW-A-03 House seam — a product CSS preload failure no longer kills the room
- auth: F-090 mount half — a transient /me failure at page load no longer deletes the stored token
- trust: security.html sub-processor table said AWS SES, mail moved to Google Workspace
- auth: H5/R-139b — an expired stored token now redirects to /login?next=<here>&reason=expired
- gateway: missing /assets/* chunk 404s instead of poisoning the client cache
- email: our mail had no Date and no Message-ID, which is why it hit spam
- email: the endpoint is the RELAY, not plain Gmail SMTP
- email: swap the transactional seam off SES to Google Workspace, AWS said no
- docs: SES runbook Step 5 still pointed at app 3, the wrong Coolify app
- identity: make a failed email say WHY, and correct two stale SES facts
- gateway: the `to` subdirective is a third way to name an upstream
- gateway: close the two holes in the gate I just wrote, record the RLS ordering
- gateway: gate the client-IP pin, and stop the trust flag outrunning it
- web: close two B1 escalations on merge; record B3's grown scope
- copy: apply the two S6 owner rulings — footer label + the PAIA gloss
- copy: close the five /code-review findings — bundle footnotes, hover-Escape, selftest crash
- ai-egress: correct overage price default 6->9, gate the drift
- parity: re-bless the standalone baseline after the audited Heldaro fix
- catalogue: close the five findings the review raised against the Office park
- legal: close S7's two open items per owner rulings; add S14 (refund queue)
- legal: attach the 14-day refund promise to the door that can keep it (F1)
- web: state per-tier features on the public pricing page (Paddle verification)
- identity: stop the checkout-nonce tests depending on a pristine database
- billing: repair the 6 DB-backed receiver tests broken by the R-155 split
- identity: repair the 41 DB-backed tests broken by the age attestation
- auth: make a closed signup navigable from both doors
- shell: ES-module worker format — Kragara's PGlite sandbox worker code-splits
- legal: Paddle domain review — 14-day unqualified refund policy + legal name in Terms
- finance: divergence anti-vacuity floor — 0 households is a state, not a misconfig
- finance: T4 item 10 ratified + implemented — identity-2 refund term gated on principal
- finance: pre-mortem findings 11-13 + real-shape revision recording
- finance: docs-sweep finding #10 — identity 5 compared fields adjusted_totals cannot carry
- finance: docs-sweep finding #9 — reversal flips the original adjustment's status
- finance: adjustment_item records on first observation only (sweep open item 1)
- finance: finding #8 completion — identity 3's totals term uses the posting-event snapshot
- finance: sweep finding #8 — tie-out expected side reads the posting event's snapshot
- finance: sweep findings 5-7 — payload-time state ordering, entity idempotence, retained_fee path
- finance: encode the CAO refund-basis ruling (sweep finding #4)
- finance: sweep findings 1-3 — dict money fields, per-event isolation, transaction.updated
- finance: 0003 — the writer's missing GRANT USAGE ON SCHEMA finance
- migrate: per-product mode creates the target schema before its ledger
- migrate-image: bake db/finance_v2 into house-migrate
- finance: fold Phase 3 wave-1 audit findings into the v2 proposal
- reconcile: distinguish empty-platform (exit 3) from misconfig; preprod opt-in grace
- billing: the sandbox customer-portal host was silently refused
- t3-1: suppress the purge selftest's redaction-pin fixture password
- t3: published falsehoods — the replay purge that never ran, dead legal links, an undisclosed storage set
- t2: the revenue path — entitlement key proof, seat floor 1, threaded 402, dunning honesty, public pricing
- t1b: the session/product-boot seam — T1-2..T1-5, with the gates that hold them
- t5-2: house_health.py review_due check — catch OPEN rows past review_by regardless of proof class
- t0: close the OAuth account takeover + the login enumeration oracle; gate the launch checklist
- billing: actually RUN the charge-after-cancel detector in prod
- shell: give an authenticated visitor a way in from the landing topbar — S3d §5.J
- billing: log WHY an outbound cancel failed + warn on a truncated Paddle key — S3d (checklist 5.N)
- identity: /me must not advertise a plan /_verify has stripped — S3d D10 (checklist 5.M)
- billing: an EMPTY Paddle base URL must not pass the pairing guard — S3d D9 (checklist 5.K)
- billing: a placeholder key must not crash the boot — S3d D9 follow-up (checklist 5.K)
- billing: treat a non-Paddle-shaped API key as absent — S3d D9 / HOUSE-R-109 (checklist 5.K)
- shell: stamp the landing gate from /account — S3d D8 (checklist 5.J)
- billing: a never-granted subscription can no longer claim the one-main slot — S3d D7 (checklist 5.I)
- billing: refuse an INVERTED BILLING_PRICE_MAP at boot — S3d D6 (checklist 5.H)
- checkout: S3d — the four sandbox-E2E defects (checklist §5.E-RESULT): one-plan enforced at the nonce, checkout-return logout, visible success, plan+cancel surface
- export: scope each product table by ITS declared predicate — closes the S4b §4b P1 503
- shell: carry the account/sign-out control to World2D (S1d follow-up)
- gates: two teeth made vacuous by the addon availability flip (S3b follow-up)
- billing: wire the 0013 cancel_request inbound closure (S3b-3)
- registry: re-sync baked events.json copies — S2d's first_value_reached was missed
- gate: a provenance ledger is made of hashes — scope the shape, not the file
- tools: room_probe hardcoded a password literal — generate it, and regenerate the changelog
- dev: NF-5 — failures in a mounted room now NAME themselves (3 fixes)
- paywall: a deep-linked office key checked out the WRONG PRODUCT (W0-2 residual)
- dev: the dev gateway could not start at all — build the real Caddy
- gate: the trophy pin was STALE, not wrong — and the test said so badly
- gate: check_lot_materials could not fail — the emissive check was unfailable
- gates: clear four pre-existing reds — and one was hiding a real bug
- identity: signup was closed at /register only — OAuth created accounts freely
- werf: the scale gate was checking four numbers no pixel depended on
- lot: declare the camera — it was an accident that hid five rooms
- gate: follow STRUCTURE_IS_ITS_OWN_SIGNATURE to its new home
- lot: the Garden and Tool Shed were not clickable at all
- werf: the proof route has been rendering at MIDNIGHT on every cold load
- tour: use the LOT's spirit motion law, on triggered paths (W1-1g)
- tour: one motion law for everything that moves (W1-1f)
- tour: the camera was cancelling her — lead in, HOLD, settle (W1-1e)
- tour: she TRAVELS — a timed journey, not a damped chase (W1-1d)
- waitlist: the endpoint accepted addresses and wrote NOTHING
- gateway: route /api/identity/waitlist as public, or the form is dead
- werf: only the manor carries a shaped gable
- werf: rebuild the gable properly - one roof, real parapet, aligned axis
- werf: owner's four corrections from the live proof
- paywall: quote the right SKU at every room door + UX audit of record
- i18n: notfound_back speaks House — EN aligned to the world-language (owner ruling)
- ai-egress: clamp Ask-the-docs question length (input-token cost guard)
- catalogue: canonical tier-key grammar (Math Board A3) + 2 known-bad teeth
- ai-egress: generalize the free-path gate off 'home' + wire Kragara through ai-egress in dev
- dr: make bootstrap_roles.py restore-clean on a truly fresh target (HOUSE-R-112)
- health: score gate launch-failure (rc 127) as unknown, not a false red
- compose: mount ./registry into reconcile-seats + reconcile-ai-cogs (crash on /registry/plans.json)
- gateway: route-wrap kragara/heldaro/vonkara (HOUSE-R-117 class hardening)
- gateway: route-wrap ai-egress to end the /health+/version 404 (HOUSE-R-117)
- gates: wire lot_clip/lot_materials into health_signals + raise the asset budget for Hearthfelt
- gates: re-bless Kragara's standalone entrypoint after W6a ingestion (rebaseline)
- gates: acknowledge tools/house_health.py in the module-budget allowlist (HOUSE-R-068)
- lot3d: the night world comes back — homes over the canopy (C-23) + the outbuildings lamplight (C-26)
- lot3d: the black arc dies (4 layers deep) + the live-shot verification harness
- lot3d: rose glow, window panes, treeline — all placed by measurement
- lot3d: the sky orb, the floating window glows, and the flat hill
- 3d: re-aim the postcard + room review cameras
- lot3d: dusk brightness floor raised + rose-window glow seated on the ring
- lot3d: GableWing rose-window end faces the camera; chimney seated as the library hearth
- identity: handle Microsoft personal-account id_tokens (no email_verified)
- identity: OAuth outcome lands on /login (was dropped on the landing)
Performance
- identity: pool the /_verify DB connections; close HOUSE-R-061