From 71df81e9ddaeaaada0a303fe7fda29a694f2a703 Mon Sep 17 00:00:00 2001 From: Dirty REdOG Date: Sat, 4 Jul 2026 22:39:09 -0500 Subject: [PATCH] status md --- STATUS.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 STATUS.md diff --git a/STATUS.md b/STATUS.md new file mode 100644 index 0000000..75fd2bb --- /dev/null +++ b/STATUS.md @@ -0,0 +1,59 @@ +# Le Daily Squirrel — Project Status + +**Date:** 2026-07-04 +**Repo:** `AutomationWise/leDailySquirrel` on Forgejo (`gf.automationwise.com`) +**Production:** https://news.opelousas.org (Cloudflare Pages, project `news-opelousas-org`) + +A satirical daily newspaper for Opelousas — vintage faded-newsprint aesthetic, edition-based publishing, self-hosted GitOps pipeline, with AI journalist agents planned as the content authors. + +--- + +## Architecture + +| Piece | Where | Notes | +|---|---|---| +| Git forge (Forgejo 9) | `kiln` (Fedora), rootless Podman Quadlet | HTTP `127.0.0.1:3000` behind Caddy at `gf.automationwise.com`; SSH on host port `3022` (LAN only, blocked at edge) | +| Reverse proxy | Caddy on `kiln` | Owns 80/443, auto TLS; also fronts Vaultwarden and Tuwunel | +| CI runner | `kiln`, Podman Quadlet (`forgejo-runner` 3.4.1) | Org-level runner `kiln-worker`, label `ubuntu-latest:docker://node:20-bookworm`, uses host Podman socket (`UserNS=keep-id`, `SecurityLabelDisable=true`, socket path identical inside/outside container) | +| Static site generator | Eleventy v3.1.6 | Input `content/`, includes `../_includes`, output `dist/` | +| Hosting | Cloudflare Pages, Direct Upload mode | Deployed via `wrangler pages deploy dist --project-name=news-opelousas-org --branch main` from `.forgejo/workflows/deploy.yml` on push to `main` | +| Dev box | `anvil` | Git remote over SSH: `ssh://git@gf.automationwise.com:3022/...` with `~/.ssh/config` host override to kiln's LAN IP (NAT hairpin workaround) | + +**Secrets:** `CF_ACCOUNT_ID` + `CF_API_TOKEN` in Forgejo repo Actions secrets. Token permissions: Account→Cloudflare Pages→Edit, Account→Workers Scripts→Edit, User→User Details→Read, scoped to the account. + +## Site mechanics + +- **Editions** live at `content/editions/YYYY-MM-DD/index.md`; URLs are `/editions/YYYY-MM-DD/`. +- **Front matter:** `layout: edition`, `edition_number` (int), `volume` (int — must be a number, the `roman` filter converts; storing "I" breaks it), `date`, `status: draft|published`, `title`. +- **Collections** (`eleventy.config.js`): `publishedEditions` (all published, newest first), `currentEdition` (newest one only). +- **Homepage** (`content/index.njk`): paginates over `currentEdition` (size 1) and renders it at `/` — render, not redirect. `content/index.11tydata.js` maps `title`, `date`, `edition_number`, `volume` up from the paginated item. +- **Filters:** `newsDate` (UTC-forced long date — fixes the CST off-by-one-day), `roman` (int → Roman numeral). +- **404:** `content/404.md` → `dist/404.html`. Required — without it Cloudflare Pages SPA-fallbacks every unknown path to `/` with a 200 (this was the "every URL shows the current edition" bug). Todo → more Squirreliness. +- **Masthead:** inline SVG (Inkscape export, single path, mm-scale coordinates, `viewBox="0 0 381 170"`). Fill flows from `fill="var(--ink)"` on the `` (path's inline `fill` style removed). CSS `squirrel-flip` animation rotates it 180° on a 50/50 duty cycle (~24s period), with a `prefers-reduced-motion` opt-out. +- **Lifecycle tooling:** `make publication` (scaffolds next edition, enforces one open draft, creates `edition//open` branch), `make publish` (seds `status: draft` → `published`), `make build` / `make serve`. + +## Hard-won gotchas (do not relearn these) + +- Quadlet units can't be `systemctl enable`d — the `[Install]` block in the `.container` file handles boot; just `daemon-reload` + `start`. Lingering is enabled for the user on kiln. +- Rootless Podman + SELinux: never `:Z` a socket mount; socket path must match host↔container when the runner asks the host to mount it into job containers. +- Wrangler CI deploys need `--branch main` or they land as Preview, not Production. +- Eleventy config must be a **single** `module.exports`; run builds from repo root only. +- Front matter beats directory data files (`editions.json`) — data bugs hide there. + +## Current status + +**Working end-to-end:** push to `main` → runner builds → Cloudflare production deploy. Volume renders as Roman numerals, archive URLs serve the correct historical edition, fake URLs 404, custom domain live, SVG masthead in place with periodic flip. + +**In development / not yet done:** + +1. **Edition immutability (freeze-at-publish)** — designed, not implemented. Plan: `make publish` builds once, snapshots rendered HTML to committed `frozen/editions//`, marks source `frozen: true`; `editions.11tydata.js` returns `permalink: false` for frozen editions; `addPassthroughCopy({ "frozen/editions": "editions" })` serves snapshots verbatim. Homepage stays dynamic; only `/editions//` freezes. Past editions from the pre-freeze era are expendable (still in dev). +2. **Archive ledger** — no `/archive/` (or `/editions/`) index page listing past editions yet. +3. **AI journalist pipeline** — the actual point of the project. Agents ingest daily material, write articles in the three-column structure, and open PRs against the open `edition//open` draft branch. Likely `imp` (OpenClaw on liminal) via NadirClaw routing, following the spec-first handoff pattern. Not started. +4. **Maintenance-mode toggle** — deferred; plan is a Cloudflare Page Rule redirect to a `/maintenance/` page. +5. **Masthead spacing polish** — minor viewBox/padding nudges deferred. + +## Suggested next steps, in order + +1. Implement the freeze-at-publish flow while there's only throwaway content to test against (touching `publish.sh`, `eleventy.config.js`, new `content/editions/editions.11tydata.js`). +2. Build the archive index page off `collections.publishedEditions`. +3. Define the agent contract: article markdown format, column assignment, front-matter rules, PR-to-draft-branch workflow — then wire the first agent.