Skip to content

Commit 8b877c8

Browse files
Merge pull request #17 from pip-install-python/feat/sign-in-gate-pilot
Feat/sign in gate pilot
2 parents f472380 + b3c8a11 commit 8b877c8

55 files changed

Lines changed: 3374 additions & 243 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.env.example‎

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ DASH_LEAFLET2_BASE_URL=http://localhost:8050
5353
# SATELLITE_TRAFFIC_URL=https://2plot.ai/api/satellite/traffic
5454
# SATELLITE_REPORT_INTERVAL_S=3600
5555
# SATELLITE_REPORT_DELAY_S=90
56+
#
57+
# Live "active now" presence beacon (POST /api/satellite/active, URL derived
58+
# from SATELLITE_TRAFFIC_URL). Display-only and ephemeral hub-side; the
59+
# rollup above stays the source of the daily numbers. 0 disables; floor 30s.
60+
# SATELLITE_PRESENCE_INTERVAL_S=60
61+
# SATELLITE_PRESENCE_URL=https://2plot.ai/api/satellite/active
5662
# Behind Cloudflare the country header is already present, so the ip-api.com
5763
# fallback lookup is redundant latency; "0" disables it.
5864
# ANALYTICS_GEO_LOOKUP=0
@@ -101,6 +107,33 @@ DASH_LEAFLET2_BASE_URL=http://localhost:8050
101107
# Set this to work on the board locally without Clerk. NEVER set in production.
102108
# ALLOW_UNGATED_ADMIN=1
103109

104-
# --- Optional: page visibility ----------------------------------------------
105-
PAGE_DEFAULT_VISIBILITY=public
110+
# --- Optional: the interactive gate (lib/access.py) -------------------------
111+
# Baseline tier for pages whose frontmatter declares none:
112+
# public | auth | admin | hidden. `auth` puts a sign-in card in front of every
113+
# documentation page; `/`, /llms-small.txt and /llms-full.txt stay public
114+
# (pinned in run.py). PAGE_DEFAULT_VISIBILITY is the same knob under this
115+
# site's older name and is still read — set one, not both.
116+
#
117+
# Locally this does nothing visible without the CLERK_* keys above: with Clerk
118+
# unavailable every tier except `hidden` falls open, because documentation
119+
# must not brick over a missing credential. To see the gate, set the Clerk
120+
# keys, or read tests/test_access.py, which drives it with a fake session.
121+
PAGE_DEFAULT_TIER=public
122+
# PAGE_DEFAULT_VISIBILITY=public
123+
124+
# The SECOND axis: whether a gated page's MACHINE twin (/<page>/llms.txt, the
125+
# crawler document, the prerender) stays open anyway. Unset = open, which is
126+
# the current network posture — humans meet the sign-in card while agent and
127+
# crawler demand keeps being measured. Setting it to 0 is the phase-4 agent
128+
# flip and closes every page that did not pin `llms_public:` in frontmatter.
129+
# LLMS_PUBLIC_DEFAULT=0
130+
131+
# Where the control board writes its overrides. An override beats both the
132+
# frontmatter tier and PAGE_DEFAULT_TIER; only the hub's ceiling outranks it.
133+
# In production this points at a persistent disk so toggles survive a deploy.
106134
# PAGE_VISIBILITY_FILE=page_visibility.json
135+
136+
# Tiers for the two corpus documents, independent of PAGE_DEFAULT_TIER so
137+
# gating the interactive site never silently gates the corpus.
138+
# LLMS_SMALL_TIER=public
139+
# LLMS_FULL_TIER=public

‎CHANGELOG.md‎

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,83 @@ will move until v2 leaves alpha upstream.
1212
## [Unreleased]
1313

1414
The fleet's x402 instrumentation sync (1.3.x) — measurement only, no payment
15-
or gating code, per the network's "instrument first, price later" rule.
16-
Documentation site and network wiring only; no `dl2.*` component changed.
15+
code — followed by the **sign-in gate pilot**, which this site runs first for
16+
the network. Documentation site and network wiring only; no `dl2.*` component
17+
changed, and `pip install dash-leaflet2` is untouched by any of it.
18+
19+
### Added
20+
21+
- **The sitemap stopped lying.** Every entry used to claim the page changed
22+
today, regenerated on every crawl — a sitemap asserting that 27 pages change
23+
daily is one search engines learn to discard wholesale. Each page now
24+
publishes the real date its prose last changed, and a page that declares no
25+
date gets no date: truth or silence.
26+
27+
- **Google now sees this site's own icons.** The crawler document carried no
28+
favicon at all — browsers got six, Googlebot got zero, which is why search
29+
showed a generic globe. It also had no social image and described every
30+
documentation page as an untyped generic web page. All three now match what
31+
a browser gets. (Requires `dash-improve-my-llms` 2.6.0, which discovers the
32+
icons from `assets/favicon_io/` with nothing declared.)
33+
34+
- **A live "active now" figure** on the hub's dashboard, from a lightweight
35+
presence beacon alongside the existing hourly rollup. Display-only — the
36+
daily numbers still come from the rollup, which now reports every 15 minutes
37+
rather than hourly.
38+
39+
- **The network directory caught up with the fleet**: muicharts, flexlayout
40+
and llms.2plot.dev added, and pannellum/emojimart restored now that they
41+
resolve — twelve peers, no dead links.
42+
43+
- **A sign-in gate, shipped dark.** Documentation pages can now require an
44+
account. Nothing is gated yet: the site deploys with the gate wired and
45+
every verdict answering "allow", so the whole path runs in production
46+
before the single environment variable (`PAGE_DEFAULT_TIER=auth`) that
47+
turns it on — and setting that variable back is the entire rollback.
48+
49+
A signed-out visitor on a gated page gets a **sign-in card at HTTP 200**,
50+
not a redirect and not a 404: the URL stays shareable, and "Create free
51+
account" now carries the current page in its return trip, so a visitor
52+
lands back where they started instead of on the primary's home page. That
53+
return leak is the one user-visible bug this pass fixes today.
54+
55+
**Machine surfaces stay open.** `/<page>/llms.txt`, the crawler document
56+
and the prerender keep serving prose to agents and crawlers while humans
57+
meet the card — a deliberate 30-day posture, switched network-wide later
58+
with `LLMS_PUBLIC_DEFAULT=0` rather than per-page edits.
59+
60+
- **`GET /api/agent-key`** — the person-to-agent handoff. Copying a page's
61+
`llms.txt` URL while signed in now carries a key, so the link still
62+
resolves when it is pasted into an assistant, whose fetch arrives with no
63+
session cookie. Signed out, the copy button behaves exactly as before.
64+
65+
- **The network's page-tier ceiling.** 2plot.dev can now restrict a page
66+
across the network; this site may lock a page down further but can never
67+
open one the network gated. A hub outage changes nothing for a signed-in
68+
reader — sessions resolve locally — and resolves to "gated" for anyone
69+
else, never to publishing restricted prose and never to a dead site.
1770

1871
### Changed
1972

73+
- **One access system instead of two.** `tier:` and `visibility:` in a page's
74+
frontmatter were independent fields naming the same four values, so a page
75+
could declare one tier and be enforced at another, with a control-board row
76+
that quietly disagreed. `tier:` is now canonical, `visibility:` is an
77+
accepted alias, and one declared value feeds both. `PAGE_DEFAULT_TIER` is
78+
likewise the canonical spelling of `PAGE_DEFAULT_VISIBILITY`, which is
79+
still read so the running service does not change posture underneath a
80+
deploy.
81+
82+
The control board keeps everything it did — live toggles, four tiers, and
83+
overrides that outlive a deploy — and its override is still the most
84+
authoritative local word on a page. What moved out of it is the decision
85+
itself, into `lib/access.py`.
86+
87+
- **Admin surfaces now fail closed everywhere.** Documentation still falls
88+
open when Clerk is unavailable — it must never brick over a missing
89+
credential — but the retired resolver fell open for admin pages too. Only
90+
`/admin/control-board`'s own double gate stopped that mattering.
91+
2092
- **Analytics: Gen-1 single-module tracker retired for the boilerplate's
2193
trio.** `lib/analytics_tracker.py` (per-request JSON ledger),
2294
`lib/traffic_rollup.py` (the hub's own daily v2+v3 definitions — its

‎CLAUDE.md‎

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,39 @@ The site de-risks; the package is the durable artifact. Keep both working.
3636
boilerplate's trio; it replaced the Gen-1 single-module tracker in the
3737
1.3.x instrumentation sync — `traffic_rollup._SKIP` must stay byte-identical
3838
to the boilerplate's) · `lib/auth.py` → Clerk satellite of 2plot.ai ·
39-
`lib/page_visibility.py` + `pages/control_board.py` → `/admin/control-board`,
40-
four tiers re-checked every render. Full reference in `DEPLOYMENT.md`. These
41-
are shared drop-in modules — when fixing a bug in `ad_client.py` or the
42-
analytics trio, the fix probably belongs in the other satellites too
43-
(canonical source: `../dash-documentation-boilerplate`).
39+
`lib/access.py` (+ `page_tiers` / `hub_client` / `gate_layouts` / `agent_key`)
40+
→ the gate · `lib/page_visibility.py` + `pages/control_board.py` →
41+
`/admin/control-board`. Full reference in `DEPLOYMENT.md`. These are shared
42+
drop-in modules — when fixing a bug in `ad_client.py` or the analytics trio,
43+
the fix probably belongs in the other satellites too (canonical source:
44+
`../dash-documentation-boilerplate`).
45+
46+
## The gate (this repo is the fleet's pilot)
47+
48+
`lib/access.py` is the enforcement engine; `lib/page_visibility.py` was demoted
49+
to the control board's **override store + UX** and no longer resolves access or
50+
wraps layouts. A verdict resolves from three inputs, in order: the board's
51+
override (most local, wins — that is what a live toggle is), the frontmatter
52+
registration in `page_tiers`, then the hub's ceiling, which only ever restricts.
53+
54+
Two lanes, deliberately different: `resolve_page_access` answers what a BROWSER
55+
gets (`gate_layouts` renders the card), `check` answers what a MACHINE fetch
56+
gets (`/<page>/llms.txt`, crawler HTML, prerender) and honours `?key=` plus the
57+
`llms_public` axis. A key never unlocks a layout.
58+
59+
Frontmatter: `tier:` is canonical, `visibility:` is an accepted alias for the
60+
same four values, and ONE declared value feeds both ledgers — they were
61+
independent keys before this pass, which let a page declare one tier and be
62+
enforced at another.
63+
64+
Two postures that look like bugs and are not: docs fall **open** without Clerk
65+
(documentation must not brick over a missing credential) while admin fails
66+
**closed**; and a hub failure resolves to `gated`, never `allow`, never `deny`.
67+
68+
Shipped **dark**: `run.py` wires the policy with `force=True` even though every
69+
tier is public, so the verdict path (and the prerender's use of it) runs in
70+
production before `PAGE_DEFAULT_TIER=auth` turns it on. That env flip is the
71+
whole change, and flipping it back is the rollback.
4472

4573
## Commands
4674

@@ -140,6 +168,14 @@ race fixed there. Its `clerk-backend-api<8` cap (widened in 1.0.1) is what lets
140168
is hand-maintained (registers `_js_dist`); everything else in `dash_leaflet2/` is generated.
141169
- **Showcase JS** (`assets/leaflet2_maps.js`): a new example = one `DEMOS` entry + one
142170
`docs/<slug>/{<slug>.md, example.py}` pair (`example.py` exports `component`). JS→Python uses `toStore()` (hardened `set_props` with retry — don't bypass it).
171+
- **`lastmod:` rides the prose.** Every `docs/<slug>/<slug>.md` declares a
172+
sitemap date; `dash-improve-my-llms` >= 2.6.0 emits it verbatim and omits the
173+
tag when absent. Edit a page's prose → bump its `lastmod` in the SAME commit.
174+
Never script these from file mtimes (they reset on every Docker build, which
175+
re-creates the every-page-changed-today sitemap the 2.6.0 floor exists to
176+
end). The initial values came from `git log -1 --format=%cs -- <file>`.
177+
`tests/test_seo_icons.py` fails if the sitemap ever emits a date no page
178+
declared, and if crawler-head icon discovery comes back empty.
143179

144180
## More detail
145181

0 commit comments

Comments
 (0)