From 52fca5287719c2cbaffbc0bab4af7abb1550ceaa Mon Sep 17 00:00:00 2001 From: Joe Petrucelli Date: Sat, 24 Oct 2026 10:16:44 -0400 Subject: [PATCH] fix(content): Waypost and Framegrade source is public, with licence --- CLAUDE.md | 2 +- content/framegrade.md | 9 +++-- content/waypost.md | 9 +++-- data/releases/framegrade.json | 4 +- data/releases/waypost.json | 4 +- data/systems.json | 2 + scripts/test_framegrade_page.py | 13 +++--- scripts/test_systems_contract.py | 68 ++++++++++++++++++++++++++++++-- scripts/verify-claims.js | 5 ++- static/llms.txt | 6 +-- 10 files changed, 97 insertions(+), 25 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d1abfd2..1cdebb0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -82,7 +82,7 @@ There is no predictions-scraper stack in this repo. Gitignored local leftovers ( - **Retired (`/releases/`)**: Gone — `static/_redirects` 301s `/releases/*` to `/rigscore/`, and release notes live on each project's GitHub releases page (`CONTENT_GUIDELINES.md` says the same). On-site version truth stays data-driven instead: the current version is `data/rigscore.json`'s `version` field, never a literal on a page — one rule among several in `scripts/verify-facts.js`, the gate that fails the build whenever hand-written prose stops agreeing with the data behind it (`data/rigscore.json`, `data/systems.json`) or with the product's real surface. It gains a rule per drift class as one is found, so read the script's header comment for the current set rather than trusting a list here. Its scan roots are `content/` + `themes/`, wider for exactly one rule (the product-count gate also reads `layouts/` and `static/`) — and never this file, so nothing lints what CLAUDE.md claims. - **Retired (`/docs/` and children)**: Gone — the boutique redesign put each system's documentation ON its own page. rigscore's manual, command reference, supported-clients matrix and verify recipe all live in `/rigscore/`'s Documentation section; the other systems carry an honest repository pointer via `{{< system-docs >}}`. `static/_redirects` 301s `/docs/` and `/docs/*` to `/#software`, with every named `/docs/` sent to `/rigscore/#documentation`; the drift sentinel probes `/rigscore/` for the live version. - **About (`/about/`)**: Short first-person identity, design approach and the one canonical explanation of the Headless Mode / Back Road Creative relationship; aliases `/cv/`. Inventory and contact instructions stay on their own surfaces rather than repeating here. -- **Driftless (`/driftless/`)**: Product page, off the home roster (`"homepage": false`) and reachable by direct URL only. Its `/demo/driftless/` link opens a committed static bundle generated by Driftless itself from its fixed fictional seed: the pages `manifest.json` lists (its `pages` count and `source` commit are the record) at a pinned as-of, with scripts, sign-in and every form/button removed, internal links rewritten to sibling files, and a `manifest.json` carrying source provenance. Never hand-edit that bundle; regenerate it with `bin/driftless-showcase.py` in the Driftless repo. Regeneration and production-smoke tracking for that bundle live in this repo's own `bin/` (`driftless-bundle-regen.sh`, `driftless-prod-smoke.sh`), tested by `scripts/test_driftless_bin.py`. `scripts/test_driftless_demo.py` is wired into local validation, PR CI and deploy and reads the bundle's own `manifest.json` as the contract (page count, script/stylesheet references, per-file sha256) rather than restating it, failing stale provenance, missing pages, live controls or escaped links, and runs an offline structural a11y pass over every page in the manifest (reds are upstream generator fixes, held as strict `xfail`s until then); the nine preview-shots pages are also gated by pa11y and Lighthouse (`.pa11yci.json`, `.lighthouserc.json`). `scripts/drift_probe_demo.py` extends that check post-deploy, run daily by `drift-sentinel.yml` against the live site. `/demo/*` is kept out of search by the `noindex, nofollow` meta that every demo page carries and the site test asserts; robots.txt deliberately stays `Allow: /` (decision 2026-09-02). The source went public under Apache-2.0 on 2026-08-03. GrantPath and GrantBridge were consolidated into one product, Grant Platform, in a **private** repository; the site was updated on 2026-09-01 — both pages deleted, `content/grant-platform.md` written in their place, and `/grantbridge/` and `/grantpath/` redirected to it by that page's `aliases`. Its entry carries no `repo` key and its page asserts no licence and no repository URL, because there is no public source to point at; it therefore writes its own Documentation section rather than calling `{{< system-docs >}}`, which errors loudly on an entry with nothing to link. It keeps `shipped: null` — the repository holds no tag and no release, and a month inferred from anything else would be an invented business fact. Only driftless now asserts a licence and a repository URL among the product pages: if that repo is ever renamed or taken private, `content/driftless.md`, `content/rigscore.md`, `static/llms.txt` and the `repo` key in `data/systems.json` all go stale together. +- **Driftless (`/driftless/`)**: Product page, off the home roster (`"homepage": false`) and reachable by direct URL only. Its `/demo/driftless/` link opens a committed static bundle generated by Driftless itself from its fixed fictional seed: the pages `manifest.json` lists (its `pages` count and `source` commit are the record) at a pinned as-of, with scripts, sign-in and every form/button removed, internal links rewritten to sibling files, and a `manifest.json` carrying source provenance. Never hand-edit that bundle; regenerate it with `bin/driftless-showcase.py` in the Driftless repo. Regeneration and production-smoke tracking for that bundle live in this repo's own `bin/` (`driftless-bundle-regen.sh`, `driftless-prod-smoke.sh`), tested by `scripts/test_driftless_bin.py`. `scripts/test_driftless_demo.py` is wired into local validation, PR CI and deploy and reads the bundle's own `manifest.json` as the contract (page count, script/stylesheet references, per-file sha256) rather than restating it, failing stale provenance, missing pages, live controls or escaped links, and runs an offline structural a11y pass over every page in the manifest (reds are upstream generator fixes, held as strict `xfail`s until then); the nine preview-shots pages are also gated by pa11y and Lighthouse (`.pa11yci.json`, `.lighthouserc.json`). `scripts/drift_probe_demo.py` extends that check post-deploy, run daily by `drift-sentinel.yml` against the live site. `/demo/*` is kept out of search by the `noindex, nofollow` meta that every demo page carries and the site test asserts; robots.txt deliberately stays `Allow: /` (decision 2026-09-02). The source went public under Apache-2.0 on 2026-08-03. GrantPath and GrantBridge were consolidated into one product, Grant Platform, in a **private** repository; the site was updated on 2026-09-01 — both pages deleted, `content/grant-platform.md` written in their place, and `/grantbridge/` and `/grantpath/` redirected to it by that page's `aliases`. Its entry carries no `repo` key and its page asserts no licence and no repository URL, because there is no public source to point at; it therefore writes its own Documentation section rather than calling `{{< system-docs >}}`, which errors loudly on an entry with nothing to link. It keeps `shipped: null` — the repository holds no tag and no release, and a month inferred from anything else would be an invented business fact. Driftless, Waypost and Framegrade assert a licence (Apache-2.0, MIT, Apache-2.0) and a repository URL among the product pages, each with a `repo` key in `data/systems.json` and a `scripts/verify-claims.js` licence row: if one of those repos is ever renamed, relicensed or taken private, its content page, `static/llms.txt`, its `repo` key and its `data/releases/.json` `source_repo` all go stale together (`content/rigscore.md` likewise for rigscore). - **Tool demo pages (`/redactcam/`, `/sun-track/`)**: One page per open tool that has something to show running. Each is a single `content/*.md`; the tool's own README on GitHub is still the manual. - **Quiet Corners (`/quiet-corners/`)**: Census/USDA-driven rural-county dashboard, reached from its stanza in the home roster. `content/quiet-corners.md` renders once in the normal-flow `#documentation` section below the dashboard; the compact dashboard header carries the page's one `

`, the systems-ledger chip and one-line, and links once back to Headless Mode and once to that methodology section. It is the page's only header — `scripts/qcm/layout.test.mjs` holds the map to 420px from the top of the document at 390x844, half the phone screen, so a second introduction cannot be stacked above it again. The page owns vertical scrolling—there is no nested dashboard or results scrollbar, with one bounded exception: at 1024px and up the four panels are a dock column left of the map (`#qc-map-container` is a two-column grid, the open panel the dock's one scroller, the map column at least 480px — `scripts/qcm/dock-layout-browser.test.mjs`), and below 1024px they share one bottom sheet that resizes the map rather than covering it or growing the page underneath it — half is 45% of the fixed-height stage (the map keeps the rest), expanded is the whole stage, and the open panel is the sheet's one scroll region. The stage clips at its bottom edge (`overflow: clip`, so nothing inside it can scroll it either), which means whatever sits inside must fit: the sheet shrinks to what the surface caption and the print-area strip leave it rather than run past that edge, and the open place finder is no taller than the room the stage has left below where it opens (what the cap leaves over scrolls inside the box, so the Census notice under an address answer is never clipped away), is placed again when a phone turns with it open, and closes when Tab or Shift+Tab moves focus out of it, so focus does not land on a control it still covers; a map drag leaves it open (`scripts/qcm/panel-shell-browser.test.mjs`, `scripts/qcm/find-and-scale.test.mjs`). The layer list itself never scrolls inside the panel — the open panel is the one scroller, and the Map key sits above the list (QUX-04c). `scripts/qcm/layout.test.mjs` also measures how much map is left. County and candidate tables paginate at 10 rows, while the desktop map stays at a useful viewport height and the mobile map remains in normal stacked flow. Data lives in `static/data/quiet-corners/` (~4MB, machine-generated by an external pipeline on each regeneration — never hand-edit; treat as a build artifact). **One exception: `states.json` is a hand-written tombstone, not pipeline output** — see "Deleting a published data file" below. Map rendering uses `themes/headlessmode/static/vendor/` (Leaflet, topojson-client, MapLibre GL JS) — third-party code, not site-authored; see `NOTICE` for licenses. diff --git a/content/framegrade.md b/content/framegrade.md index bf6a4b7..579005b 100644 --- a/content/framegrade.md +++ b/content/framegrade.md @@ -6,9 +6,10 @@ draft: false tags: ["creator-tools", "video-pipeline", "photo-develop", "automation"] --- -> **Access.** Framegrade is pre-release. The source is private and there is no installer or -> versioned release. It is available through a studio engagement; [contact me](/contact/) -> for setup. +> **Access.** Framegrade is pre-release. The source is public under Apache-2.0 at +> [Back-Road-Creative/framegrade](https://github.com/Back-Road-Creative/framegrade), and there is no +> installer or versioned release. It is available through a studio engagement; +> [contact me](/contact/) for setup. Framegrade is the engine that turns raw video and photos into finished files. It does the picture work only: it does not title, schedule or publish anything. [Waypost](/waypost/) runs it @@ -43,4 +44,4 @@ holds no brand name of its own. ## Documentation -The source and its documentation are private. +{{< system-docs name="Framegrade" >}} diff --git a/content/waypost.md b/content/waypost.md index 28588dd..2dad9e9 100644 --- a/content/waypost.md +++ b/content/waypost.md @@ -6,9 +6,10 @@ draft: false tags: ["creator-tools", "video-pipeline", "self-hosted", "automation"] --- -> **Access.** Waypost is pre-release. The source is private and there is no installer or -> versioned release. It is available through a studio engagement; [contact me](/contact/) -> for setup. +> **Access.** Waypost is pre-release. The source is public under MIT at +> [Back-Road-Creative/waypost](https://github.com/Back-Road-Creative/waypost), and there is no +> installer or versioned release. It is available through a studio engagement; +> [contact me](/contact/) for setup. **[Open the read-only demo →](/demo/waypost/)** — a fixed fictional console for a made-up brand, frozen at 2026-09-01. The forms and buttons are removed, so it shows a saved example and @@ -63,4 +64,4 @@ backup is a setup step. Console login by token is optional. ## Documentation -The source and its documentation are private. +{{< system-docs name="Waypost" >}} diff --git a/data/releases/framegrade.json b/data/releases/framegrade.json index c916c69..6e3b7fd 100644 --- a/data/releases/framegrade.json +++ b/data/releases/framegrade.json @@ -2,7 +2,7 @@ "product": "framegrade", "name": "Framegrade", "release_source": "manual", - "source_repo": null, + "source_repo": "Back-Road-Creative/framegrade", "version": null, "released_at": null, "release_url": null, @@ -10,5 +10,5 @@ "assets": {}, "demo": null, "media_source": null, - "notes": "Framegrade has no product repository or tag to release against, and no demo bundle. The page asserts no version, date or availability." + "notes": "Framegrade's repository is public but has no release or tag to read, and there is no demo bundle. The page asserts no version, date or availability." } diff --git a/data/releases/waypost.json b/data/releases/waypost.json index 418ad42..c8a343d 100644 --- a/data/releases/waypost.json +++ b/data/releases/waypost.json @@ -2,7 +2,7 @@ "product": "waypost", "name": "Waypost", "release_source": "manual", - "source_repo": null, + "source_repo": "Back-Road-Creative/waypost", "version": null, "released_at": null, "release_url": null, @@ -16,5 +16,5 @@ "pages": 5 }, "media_source": null, - "notes": "waypost has no product repository to tag a release against. The demo bundle's manifest.json 'source' (62f9408) is honestly a SITE commit (PR #331) that built the bundle, not a product ref." + "notes": "Waypost's repository is public but has no release or tag to read. The demo bundle's manifest.json 'source' (62f9408) is honestly a SITE commit (PR #331) that built the bundle, not a product ref." } diff --git a/data/systems.json b/data/systems.json index d4d7518..db0b8eb 100644 --- a/data/systems.json +++ b/data/systems.json @@ -192,6 +192,7 @@ "access": "engagement", "blurb": "A console on your own computer that runs a creator's video, photo and SEO work and queues posts for YouTube, Instagram and Facebook, one tab per brand", "link": "/waypost/", + "repo": "https://github.com/Back-Road-Creative/waypost", "shipped": null, "homepage_rank": 5, "homepage_image": "waypost/home.jpg", @@ -210,6 +211,7 @@ "access": "engagement", "blurb": "The media engine under Waypost: it grades video and photos, checks each finished file before delivery, and builds route films from GPS tracks", "link": "/framegrade/", + "repo": "https://github.com/Back-Road-Creative/framegrade", "shipped": null, "homepage_rank": 6, "homepage_image": "framegrade/home.svg", diff --git a/scripts/test_framegrade_page.py b/scripts/test_framegrade_page.py index ef90657..14accd8 100644 --- a/scripts/test_framegrade_page.py +++ b/scripts/test_framegrade_page.py @@ -5,9 +5,9 @@ content/waypost.md, data/releases/framegrade.json. Framegrade is the media engine Waypost runs underneath. It is a pre-release -product with no repository and no dated release, so the page may describe what -the engine does and must carry no price, count, date or availability promise -(business facts come only from the owner). +product with a public repository (Apache-2.0) and no dated release, so the page +may describe what the engine does and must carry no price, count, date or +availability promise (business facts come only from the owner). Run: pytest scripts/test_framegrade_page.py -v """ @@ -42,8 +42,9 @@ def test_framegrade_is_a_product_row_with_no_invented_facts() -> None: assert row["link"] == "/framegrade/" assert row["shipped"] is None assert not row["blurb"].endswith("."), "blurb carries no closing period" - for key in ("download", "install", "store", "repo"): - assert key not in row, f"no {key!r}: nothing public to point at" + for key in ("download", "install", "store"): + assert key not in row, f"no {key!r}: no installer or release exists" + assert row["repo"] == "https://github.com/Back-Road-Creative/framegrade" def test_framegrade_rank_is_unique_among_products() -> None: @@ -80,6 +81,8 @@ def test_framegrade_release_record_is_honest() -> None: rec = json.loads(RELEASE.read_text(encoding="utf-8")) assert rec["product"] == "framegrade" and rec["name"] == "Framegrade" assert rec["release_source"] == "manual" and rec["notes"] + assert rec["source_repo"] == "Back-Road-Creative/framegrade" + assert "no product repository" not in rec["notes"] assert rec["version"] is None and rec["released_at"] is None assert rec["demo"] is None and rec["assets"] == {} diff --git a/scripts/test_systems_contract.py b/scripts/test_systems_contract.py index 511c3e0..24254a7 100644 --- a/scripts/test_systems_contract.py +++ b/scripts/test_systems_contract.py @@ -633,12 +633,74 @@ def test_llms_waypost_says_tiktok_is_a_manual_handoff(): def test_llms_quiet_corners_links_its_public_repository(): """github.com/Back-Road-Creative/quiet-corners is public, so llms.txt must link it the way the other open entries do ("Source: github.com/...") and - must not claim there is nothing to link. Grant Platform's and Waypost's - source stay private, and the Products paragraph must keep saying so.""" + must not claim there is nothing to link. Grant Platform's source stays + private, and the Products paragraph must keep saying so.""" text = LLMS.read_text() assert "Source: github.com/Back-Road-Creative/quiet-corners." in _llms_line("Quiet Corners") assert "no repository" not in text.lower() - assert "neither Grant Platform's source nor Waypost's is public" in text + assert "Grant Platform's source is private" in text + + +PUBLIC_PRODUCTS = { + "Waypost": ("waypost", "MIT"), + "Framegrade": ("framegrade", "Apache-2.0"), +} + + +@pytest.mark.parametrize("name", sorted(PUBLIC_PRODUCTS)) +def test_llms_states_waypost_and_framegrade_source_is_public(name): + """Both repositories are public (MIT and Apache-2.0), so llms.txt must say + so with the repository URL and licence and must not call either private.""" + repo, spdx = PUBLIC_PRODUCTS[name] + text = LLMS.read_text() + assert f"Source: github.com/Back-Road-Creative/{repo}." in _llms_line(name) + assert f"{name} is public under {spdx} at github.com/Back-Road-Creative/{repo}" in text + assert f"{name}'s is public" not in text + assert f"nor {name}'s" not in text + + +@pytest.mark.parametrize("name", sorted(PUBLIC_PRODUCTS)) +def test_waypost_and_framegrade_entries_carry_their_public_repo(name): + """Like Driftless, a public engagement product names its repository in + data/systems.json (the system-docs shortcode and the sheet's source link + read it); the link stays the on-site page.""" + repo, _ = PUBLIC_PRODUCTS[name] + entry = next(s for s in json.loads(SYSTEMS.read_text())["systems"] if s["name"] == name) + assert entry["repo"] == f"https://github.com/Back-Road-Creative/{repo}" + assert entry["link"] == f"/{repo}/" + assert entry["access"] == "engagement" and entry["shipped"] is None + rec = json.loads((ROOT / "data" / "releases" / f"{repo}.json").read_text()) + assert rec["source_repo"] == f"Back-Road-Creative/{repo}" + assert "no product repository" not in rec["notes"] + + +@pytest.mark.parametrize("name", sorted(PUBLIC_PRODUCTS)) +def test_waypost_and_framegrade_pages_state_public_source_and_licence(name): + """The Access note names the public source, URL and licence while keeping + the business facts (pre-release, no release, studio engagement); the + Documentation section points at the repository README.""" + repo, spdx = PUBLIC_PRODUCTS[name] + text = (ROOT / "content" / f"{repo}.md").read_text() + access = text.split("> **Access.**", 1)[1].split("\n\n", 1)[0] + flat = re.sub(r"\s+(?:>\s*)?", " ", access) + assert f"The source is public under {spdx}" in flat + assert f"https://github.com/Back-Road-Creative/{repo}" in flat + assert "pre-release" in flat and "no installer or versioned release" in flat + assert "studio engagement" in flat + assert "source is private" not in text + assert "documentation are private" not in text + docs = text.split("\n## Documentation\n", 1)[1] + assert f'{{{{< system-docs name="{name}" >}}}}' in docs + + +def test_verify_claims_re_verifies_waypost_and_framegrade_licences(): + """The drift sentinel must re-check the licence each page now asserts.""" + src = (ROOT / "scripts" / "verify-claims.js").read_text() + for name, (repo, spdx) in PUBLIC_PRODUCTS.items(): + assert ( + f"page: 'content/{repo}.md', owner: 'Back-Road-Creative', repo: '{repo}', spdx: '{spdx}'" + in src + ) def _ledger_order(entries): diff --git a/scripts/verify-claims.js b/scripts/verify-claims.js index 06365ff..7ba93c9 100644 --- a/scripts/verify-claims.js +++ b/scripts/verify-claims.js @@ -42,11 +42,14 @@ const ROOT = path.join(__dirname, '..'); const SYSTEMS_FILE = path.join(ROOT, 'data', 'systems.json'); const TOKEN = process.env.GITHUB_TOKEN || ''; -// Grounded 2026-09-01 by reading the page: it states Apache-2.0. +// Grounded by reading each page: driftless states Apache-2.0 (2026-09-01); waypost +// states MIT and framegrade states Apache-2.0, both matching the live repositories. // Grant Platform is deliberately absent: its repository is private, so there is no // public licence file to probe and its page makes no licence claim to re-verify. const LICENSE_CLAIMS = [ { page: 'content/driftless.md', owner: 'Back-Road-Creative', repo: 'driftless', spdx: 'Apache-2.0' }, + { page: 'content/waypost.md', owner: 'Back-Road-Creative', repo: 'waypost', spdx: 'MIT' }, + { page: 'content/framegrade.md', owner: 'Back-Road-Creative', repo: 'framegrade', spdx: 'Apache-2.0' }, ]; const rows = []; diff --git a/static/llms.txt b/static/llms.txt index baf0d8a..820a57b 100644 --- a/static/llms.txt +++ b/static/llms.txt @@ -17,12 +17,12 @@ Source is public for all of these; each on-site page's Documentation section say - [push-guard](https://github.com/Back-Road-Creative/push-guard): A client-side hook that blocks direct pushes to protected branches so changes go through pull requests. ## Products -Driftless is public under Apache-2.0 at github.com/Back-Road-Creative/driftless. It is not listed on the homepage; its detail page carries release and source status. Driftless, Grant Platform and Waypost are acquired through the studio; Quiet Corners is used directly in the browser, and its source is public; neither Grant Platform's source nor Waypost's is public. +Driftless is public under Apache-2.0 at github.com/Back-Road-Creative/driftless. It is not listed on the homepage; its detail page carries release and source status. Waypost is public under MIT at github.com/Back-Road-Creative/waypost and Framegrade is public under Apache-2.0 at github.com/Back-Road-Creative/framegrade. Driftless, Grant Platform, Waypost and Framegrade are acquired through the studio; Quiet Corners is used directly in the browser, and its source is public; Grant Platform's source is private. - [Driftless](https://headlessmode.com/driftless/): Manages portfolios, programs and projects, computing status, forecasts and reports from data entered once. - [Quiet Corners](https://headlessmode.com/quiet-corners/): Scores rural U.S. counties on stability, remoteness, sprawl risk and affordability using Census and USDA data. Source: github.com/Back-Road-Creative/quiet-corners. - [Grant Platform](https://headlessmode.com/grant-platform/): Runs grant work end to end on one platform — funder award administration and compliance, and recipient discovery, applications, reporting and closeout. -- [Waypost](https://headlessmode.com/waypost/): Runs a creator's video, photo, SEO, comment and scheduling pipelines from one locally run console, with a tab per brand. Drive to published slot on YouTube, Instagram and Facebook, with TikTok a manual handoff scheduled in TikTok Studio; runs on Framegrade and fronts keycut, redactcam, pycube-lut and sun-track. Driftless is a different product (project scheduling), not part of it. -- [Framegrade](https://headlessmode.com/framegrade/): Grades video and photos from measurements of the picture, checks each finished file, and builds route films from GPS tracks. Pre-release; the media engine Waypost runs underneath. It does not title, schedule or publish. +- [Waypost](https://headlessmode.com/waypost/): Runs a creator's video, photo, SEO, comment and scheduling pipelines from one locally run console, with a tab per brand. Drive to published slot on YouTube, Instagram and Facebook, with TikTok a manual handoff scheduled in TikTok Studio; runs on Framegrade and fronts keycut, redactcam, pycube-lut and sun-track. Driftless is a different product (project scheduling), not part of it. Source: github.com/Back-Road-Creative/waypost. +- [Framegrade](https://headlessmode.com/framegrade/): Grades video and photos from measurements of the picture, checks each finished file, and builds route films from GPS tracks. Pre-release; the media engine Waypost runs underneath. It does not title, schedule or publish. Source: github.com/Back-Road-Creative/framegrade. - [Band Coach](https://headlessmode.com/band-coach/): Runs an adaptive practice plan for 26 instruments, grading what you play by microphone, MIDI or on-screen keys and tracking progress over time. Shipped 2026-09, v1.9.0, a single downloadable HTML file for Windows, Mac, Linux and Chromebook. Source: github.com/Back-Road-Creative/band-coach. ## Project