Slice 7: §14 chrome + settings and admin neighborhoods

§14.1 richer landing, §14.2 /philosophy route (disk-backed), §14.3
persistent About link. /settings/notifications surfaces Slice 6's
preferences/quiet-hours/mute/watches endpoints. /admin home base
consolidates role management, the §6.2 write-mute, the audit-log
viewer, the permission-events log, and the §13.2 graduation queue.

Backend: backend/app/philosophy.py, backend/app/api_admin.py (seven
admin endpoints + user-search), GET /api/users/me/notification-mutes.
Frontend: Landing.jsx (deck), Philosophy.jsx, NotificationSettings.jsx,
Admin.jsx, App.jsx routing for the chrome surfaces.

Tests: backend/tests/test_chrome_vertical.py — 13 cases. Full suite
75/75 green.

Spec corrections: §14.2 (PHILOSOPHY.md source is a deployment-time
decision), §17 (admin block extended to name the seven new endpoints
+ user-search and notification-mutes read). §19.1 rewritten for
Slice 8 hardening; §19.2 grew four candidates (owner succession,
mute-from-actor, the "Following since <date>" disclosure, audit-log
row prose).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-05-24 23:40:49 -07:00
parent f67d0aa0db
commit 060fa408a2
14 changed files with 2722 additions and 158 deletions
+66
View File
@@ -0,0 +1,66 @@
"""§14.2 philosophy source.
The spec names PHILOSOPHY.md as the body the `/philosophy` route renders,
"sourced from the meta repo's main branch, cached and refreshed on the
same cadence as RFC bodies (§4)." Slice 7 picks the disk-first shape:
the file is checked into the app repo alongside SPEC.md, since it is
the framework's design document rather than an RFC entry, and reading
it from disk at process start (with a periodic re-read for hot edits)
puts the framework's mission in front of the reader without an extra
Gitea round-trip on the first hit.
If a downstream deployment hosts PHILOSOPHY.md in the meta repo
instead, the `PHILOSOPHY_PATH` env var can point at a working-tree
clone or a sync target; the loader does not care which.
"""
from __future__ import annotations
import logging
import os
import threading
from pathlib import Path
log = logging.getLogger(__name__)
_DEFAULT_PATH = Path(__file__).resolve().parents[2] / "PHILOSOPHY.md"
_lock = threading.Lock()
_cache: dict | None = None
def _resolved_path() -> Path:
override = os.environ.get("PHILOSOPHY_PATH", "").strip()
if override:
return Path(override).expanduser().resolve()
return _DEFAULT_PATH
def load(force: bool = False) -> dict:
"""Return the cached `{body, path, mtime}` payload, reading from disk
on first call or when `force=True`. The reconciler's sweep can call
this with `force=True` to pick up out-of-band edits.
"""
global _cache
with _lock:
if _cache is not None and not force:
return _cache
path = _resolved_path()
try:
text = path.read_text(encoding="utf-8")
mtime = path.stat().st_mtime
except FileNotFoundError:
log.warning("PHILOSOPHY.md not found at %s — serving placeholder", path)
text = (
"# PHILOSOPHY.md not found\n\n"
"The deployment is missing its philosophy document. Set "
"PHILOSOPHY_PATH or place PHILOSOPHY.md at the project root."
)
mtime = 0.0
_cache = {"body": text, "path": str(path), "mtime": mtime}
return _cache
def refresh() -> dict:
"""Force-reread from disk. Returns the new payload."""
return load(force=True)