Skip to content

Session Handoff [default]: Env File Rename in Develop, Secret Readers Next After Hub #3534 #493

Open

Description

@ptr727

Next steps, in priority order

  1. #553: carry the hub's secret readers. Step 1 is Declare host-secrets for Blog and Name It the Overlay's First Adopter ProjectTemplate#3534, which adds host-secrets to Blog's registry types. It is open and CLEAN into hub develop, and the maintainer merges and promotes it. Once it reaches hub main, from a feature worktree: run carry.py apply to carry lib/sh to lib/fleet/sh, then switch deploy/make-release.sh to require_secret and read_env_value instead of set -a; . "$ENV_FILE". The env file names are already the underscore form from Rename the Host Env Files to the Fleet's Underscore-Joined Form #557. The docs describing set -a sourcing (ENVIRONMENT.md, OPERATIONS.md "Configuration Layout", deploy/README.md, .secrets/example.env) change with it. Done means the hub's carried-trees check reads the copy as current and make-release.sh reads its env file only through the readers.
  2. #549: retire the media parser fuzz gate. Unchanged from round 36. Remove the script, its tests, its validate-action step, and every doc describing it, with the reference sweep a deletion owes. Keep the media gate's own metadata and damage checks.
  3. Promote develop to main when the maintainer asks. It holds resync Resync the Carried Instruction Set and Skills Tree With Hub f60f57d #556 and rename Rename the Host Env Files to the Fleet's Underscore-Joined Form #557. The promotion body lists Rename the Host Env Files to the Fleet's Underscore-Joined Form #550 as closing. No deploy is owed for either.
  4. Run the next monthly 404 pass on or after 2026-11-23, per OPERATIONS.md "Logs and Debugging", with start='2026-10-23T15:42'. It needs a production-log go-ahead, asked in a dialog. Done means a comment here with the date range, the count left after filtering, and each finding's disposition.
  5. #546 and #547, small conformance fixes, one pull request each.
  6. When the host side flips a VPS staging name to proxied, run the live check once with EXPECT_SITE_ENV and report on ptr727/HomeAutomation-Config#580. #495 waits on a proxied host that can take a test release.

External blockers

Internal dependencies

State

The parked decision queue

Empty. No open issue carries decision.

What the last round did

What not to repeat

  • Assuming carry.py apply can carry a tree a repository has not declared. It selects lib/sh by the registry's types, so a hub registry change comes before any Blog-side carry, and that change waits on a hub promotion.
  • Updating the hub's reports/blog/audit.md in a registry PR. A reviewer asked for it on #3534 and it was declined with evidence. The report is the 2026-08-05 run, already older than the python type, and a run replaces it whole from a hub-side audit.
  • Everything in earlier rounds' "What not to repeat" still applies.

New learnings

  • None beyond the two entries above, which are attempt-specific.

Activity

  1. added
    handoffA link in the session handoff chain, one open issue per track
    on Oct 23, 2026
  2. ptr727 commented on Oct 23, 2026

    @ptr727
    OwnerAuthor

    Round 25, closed 2026-10-23: Session Handoff [default]: Periodic 404 log review, monthly from 2026-11-23

    Next steps, in priority order

    1. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the whole procedure. Run it from the repository rather than rebuilding it by hand.
      • Use the window block in "Reading a 404 list without being fooled by it" with start='2026-10-23T15:42', where this pass ended. It runs checks/log-review.jq over the joined window.
      • Cross-check the 403s with "A 403 is CrowdSec's until shown otherwise", and check any crawler 403 or 404 by forward-confirmed DNS.
      • Run "Checking that search engines can index both sites". A 404 on /news-sitemap.xml is a regression, and so is one on viljoen.family/robots.txt, /sitemap.xml, /tag/review, /viljoen-family, or /20180811_172609507_ios.
      • A routerless https 404 cluster beside 502s is the edge restarting. Leave it alone, per the new paragraph under "The log is three tiers".
      • When a new scanner shape crowds the list, add it to checks/log-review.jq in the same change that records the pass.
      • Done for a pass means a comment on this issue with the date range, the count left after filtering, and each finding's disposition.
    2. After that pass, close this lane out if it found nothing new. Otherwise write the next link with the next monthly date.

    External blockers

    • Production log reads and CrowdSec reads need the maintainer's go-ahead. Ask once per session in a dialog before the first SSH or archive read. A past session's approval does not carry over.
    • Search Console is the maintainer's. A Googlebot-UA client fetched the blog's sitemap.xml once this window, where the previous window saw none. Whether both sitemaps are submitted in Google Search Console is visible only there.
    • The cleartext redirect is temporary (302/307) on both sites. Host-side, filed as ptr727/HomeAutomation-Config#1077, and that session left it in its backlog.
    • The home-network CrowdSec allowlist is still ptr727/HomeAutomation-Config#893. Until it lands, keep production probes to a handful per pass.

    Internal dependencies

    • None. Each pass stands alone.

    State

    The parked decision queue

    Zero issues carry decision. This round asked four questions as it went, all answered: run the pass early with the production-read go-ahead, the news-sitemap redirect and the route-loss note, the #489 merge, and the #490 merge and release.

    What the last round did

    • Ran the 404 pass early, on the maintainer's call, covering 2026-10-15 21:03 UTC through 2026-10-23 15:42 UTC. The pass is recorded in a comment on this issue. 711 survivors, one finding.
    • #489 redirects /news-sitemap.xml to /sitemap.xml through a @news_sitemap class (contract now 956 URLs), names /sitemap.xml among the sampled fixed destinations, and records in OPERATIONS.md that a routerless https 404 beside 502s is the edge restarting. Merged into develop.
    • #490 promoted it. Copilot's two scope findings read the three-dot compare view, declined with the two-dot tree diff as evidence. Released as 1.0.258 and deployed to production and the local production mirror.
    • The sample now sits at exactly its 30-path budget. The next render, redirect, or destination class fails --print-sample until SAMPLE_MAX_PATHS in check-live-urls.sh and MAX_PATHS in its test move together, or a class is folded.

    What not to repeat

    • Hand-editing deploy/maps/slugs.map. capture/build-redirects.py rewrites it from the capture, and its filter never emits a one-slash key, so a fixed root-file redirect goes in the Caddyfile as its own exact-path class, the way /atom.xml and now /news-sitemap.xml do. The first strict review pass caught this after a staging check had already passed, since staging cannot see a future regeneration.
    • Dropping a sitemap or feed name as noise without a Wayback check. Round 1 dropped /news-sitemap.xml that way, and it was served for two years. Run the CDX query before dropping any name a real crawler polls.
    • Touching a line that holds a pre-existing over-long sentence. The sentence-length gate reads every sentence on a changed line, so appending a short sentence to OPERATIONS.md's routerless paragraph flagged its two existing 38- and 44-word sentences. Put the new text on its own line instead.
    • Writing the three sampled-destination sentences from one. checks/README.md, deploy/README.md, and OPERATIONS.md each describe SAMPLE_DESTINATIONS, and Copilot found the first while the strict review found the other two. A change to that array edits all three.
    • Everything in Session Handoff [log-review]: Periodic 404 Log Review, Monthly From 2026-11-15 #474's, Session Handoff [log-review]: Periodic 404 Log Review, Daily Through 2026-10-11 Then Monthly #461's and Session Handoff [log-review]: Periodic 404 Log Review, Daily Through 2026-10-11 Then Monthly #455's "What not to repeat" still applies.

    New learnings

    • A routerless https 404 on a served hostname beside 502s is the edge restarting nightly or during a daytime host-side push, per the maintainer, and needs no action. Recorded in OPERATIONS.md "The log is three tiers".
    • pieter.viljoen.name is a registrar-level redirector that forwards its path to the blog, so a probe against it lands on the blog as a referer-bearing 404. Nothing to fix here, and the referer is the tell.
    • The gh-write-guard hook refuses a git -C "$var" and a git commit -F "$var" shape even in a linked worktree. Write the path out in full, or put the probe in a script run with bash <path>.
  3. changed the title [-]Session Handoff [default]: Periodic 404 log review, monthly from 2026-11-23[/-] [+]Session Handoff [default]: Promote the Cache Lifetimes, Then the Monthly 404 Pass From 2026-11-23[/+] on Oct 23, 2026
  4. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    viljoen.family went behind the Cloudflare proxy at 2026-10-24T01:47Z (ptr727/HomeAutomation-Config#580). The blog hostnames are still DNS-only and flip later.

    Zone settings applied before the flip, per the host side: SSL Full (strict), Browser Cache TTL "Respect Existing Headers", and Always Use HTTPS, Automatic HTTPS Rewrites, Browser Integrity Check, Bot Fight Mode, Rocket Loader, Email Address Obfuscation, Hotlink Protection, and edge HSTS all off.

    Step 3 is done for the family pilot. checks/check-live-urls.sh ran against production at 2026-10-24T01:49Z with SAMPLE_CONTRACT=1 and EXPECT_SITE_ENV=production, from develop at 070b7ab. It passed 33 sampled URLs. The family pages answered server: cloudflare with X-Blog-Env: production.

    • For the first two minutes this machine's resolver still answered with the origin address while DNS over HTTPS already answered with Cloudflare's. Before a run counts as measured through the proxy, confirm that server: cloudflare and a cf-ray header are present.
    • Production still runs the release from before Name a Cache Lifetime on Every Response Ahead of an Edge Proxy #492. The family pages therefore carry no Cache-Control yet, and Cloudflare reports them DYNAMIC. crest.svg keeps its week and reports MISS on the first request. The cache lifetimes arrive with promotion Promote the Edge Proxy Cache Lifetimes #494.
    • The next monthly 404 pass reads ClientHost on viljoen.family lines as a forwarded chain. checks/log-review.jq already keeps its last element. A cached file type there is answered at the edge, so its count is a floor.
  5. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    Round 26, closed 2026-10-23: Session Handoff [default]: Promote the Cache Lifetimes, Then the Monthly 404 Pass From 2026-11-23

    Next steps, in priority order

    1. Promote develop to main and release when the maintainer wants the cache headers live. #492 changed deploy/Caddyfile, so this is a deploy, not a docs-only promotion: open the develop -> main promotion PR, release, deploy VPS production, and run make-release.sh against the local production mirror. Until then production and the local production mirror serve no Cache-Control.
    2. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the whole procedure. Run it from the repository rather than rebuilding it by hand.
      • Use the window block in "Reading a 404 list without being fooled by it" with start='2026-10-23T15:42', where the last pass ended. It runs checks/log-review.jq over the joined window, which now rewrites ClientHost to the last forwarded address, so a proxied line reads correctly without a hand step.
      • Cross-check the 403s with "A 403 is CrowdSec's until shown otherwise", whose snippet reads the last forwarded address the same way, and check any crawler 403 or 404 by forward-confirmed DNS.
      • Run "Checking that search engines can index both sites". A 404 on /news-sitemap.xml is a regression, and so is one on viljoen.family/robots.txt, /sitemap.xml, /tag/review, /viljoen-family, or /20180811_172609507_ios.
      • A routerless https 404 cluster beside 502s is the edge restarting. Leave it alone, per "The log is three tiers".
      • When a new scanner shape crowds the list, add it to checks/log-review.jq in the same change that records the pass.
      • Done for a pass means a comment on this issue with the date range, the count left after filtering, and each finding's disposition.
    3. After the family site is proxied through Cloudflare, which ptr727/HomeAutomation-Config#580 pilots first, run checks/check-live-urls.sh against production once with EXPECT_SITE_ENV set, and read cached media counts in the next 404 pass as a floor, per the new paragraph under "The log is three tiers". Nothing here flips the proxy, and the Blog's readiness findings are a comment on that issue.

    External blockers

    • Production log reads and CrowdSec reads need the maintainer's go-ahead. Ask once per session in a dialog before the first SSH or archive read. A past session's approval does not carry over.
    • Search Console is the maintainer's. Whether both sitemaps are submitted in Google Search Console is visible only there.
    • The Cloudflare proxy flip is host-side, ptr727/HomeAutomation-Config#580, pilot on the family site per the maintainer's 2026-09-30 decision there. Its timing is that session's. The settings to keep off for the Blog's gates (Bot Fight Mode, Browser Integrity Check, Rocket Loader, Email Obfuscation) are listed in the Blog comment on it.
    • The home-network CrowdSec allowlist is still ptr727/HomeAutomation-Config#893. Until it lands, keep production probes to a handful per pass. ptr727/HomeAutomation-Config#894 and #1077 are closed, so the next pass checks that the cleartext redirect answers 301 rather than carrying the old finding forward.

    Internal dependencies

    • Step 3 waits on step 1 only in that a proxied production without the cache headers would take Cloudflare's extension defaults, two hours on media and three minutes on a media 404. Promote before the pilot flips the blog, or accept that window.

    State

    The parked decision queue

    Zero issues carry decision. This round asked one question as it went, the #492 merge into develop with cleanup, answered yes. One judgment call is recorded rather than asked: the media lifetime is one hour, chosen so a redacted image leaves every copy within the hour without a purge step, and a longer value is a one-line change in deploy/Caddyfile if origin revalidation ever matters.

    What the last round did

    • Reviewed readiness for the Cloudflare proxy on both sites from the Blog side, reading the HomeAutomation-Config checkout on disk rather than its tracker, found ptr727/HomeAutomation-Config#580 already open with a pilot decision, and commented the findings there instead of filing a duplicate.
    • #492: every blog response names a Cache-Control, no-cache for pages, feeds, sitemaps, index.json, robots.txt, redirects, and both error pages, a year immutable for the fingerprinted assets, an hour for media and the root icons, and no-cache on the family pages. checks/log-review.jq keeps the last element of ClientHost. OPERATIONS.md names Cloudflare as a tier above Traefik and what it hides, and deploy/README.md gained "Cache lifetimes". Three local staging releases, five local strict review passes (seven findings fixed across them, none left open), one Copilot round whose single finding moved the baseline header ahead of the redirects. Squash-merged into develop.

    What not to repeat

    • Placing a baseline header after the redirect handlers in the route block. A redir ends the route, so a header after it never reaches a redirect response. Copilot caught it after three local passes had read the block.
    • Writing an edit script that assumes how a hard-wrapped README paragraph is broken into lines. Two attempts failed on mismatched wrapping. Locate the paragraph's first line by content and replace a line range, or read it with cat -A first.
    • A $var word anywhere in gh pr merge, and a >/dev/null tail on any gh write. The guard refuses both before anything runs. Read the SHA in its own call and write it out literally, and let a write print its result.
    • Running a hub script that imports a sibling module with python3 -I. pr_review.py imports gh_graphql from its own directory, and -I drops that path. Reserve -I for a script that reads untrusted downloads.
    • Null guards on a field Traefik always writes. The strict review flagged the ClientHost guards as hardening against input the deployment never produces. Check what the producer guarantees before guarding.
    • Everything in the previous rounds' "What not to repeat" still applies: no hand edits to deploy/maps/slugs.map, no dropping a sitemap or feed name without a Wayback check, no appending to a line holding a pre-existing over-long sentence, and the three sampled-destination sentences move together.

    New learnings

    • Traefik's access logger sets ClientHost to the whole X-Forwarded-For header when one survives the entry point's trust filter, so behind Cloudflare it is a chain whose last element is the address Cloudflare saw. Recorded in OPERATIONS.md "The log is three tiers".
    • Cloudflare caches by file extension only, never HTML, XML, JSON, or text by default, caches a 404 on a cacheable extension for three minutes, caches robots.txt, and stores nothing marked no-cache while Origin Cache Control is off. The free plan shows aggregates and a sample, never a per-request log.
    • In Caddy a header inside route keeps file order and its default operation replaces an earlier value, and a header in handle_errors overrides whatever lifetime a matched class gave the request, verified on the local staging mirror.
    • gh issue list --search on a sibling repository finds a standing issue a fresh request would duplicate. Search before filing, and comment instead.
  6. changed the title [-]Session Handoff [default]: Promote the Cache Lifetimes, Then the Monthly 404 Pass From 2026-11-23[/-] [+]Session Handoff [default]: Proxied-Run Check in OPERATIONS.md, Then the Monthly 404 Pass From 2026-11-23[/+] on Oct 24, 2026
  7. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    blog.insanegenius.com went behind the Cloudflare proxy at 2026-10-24T14:26:46Z (ptr727/HomeAutomation-Config#580). The two VPS staging names are still DNS-only.

    The host side applied these insanegenius.com zone settings before the flip: SSL Full (strict), Browser Cache TTL "Respect Existing Headers", and Caching Level Standard. Always Use HTTPS, Automatic HTTPS Rewrites, Browser Integrity Check, Bot Fight Mode, Rocket Loader, Email Address Obfuscation, Hotlink Protection, and edge HSTS are all off.

    Step 3 is done for this hostname. This machine's resolver kept answering with the origin until 14:30:40Z, about four minutes after the flip. Once server: cloudflare and cf-ray appeared, checks/check-live-urls.sh ran against production at 14:30Z, from develop at f35ec08, with SAMPLE_CONTRACT=1 and EXPECT_SITE_ENV=production. It passed 33 sampled URLs, against release 20261024-135159-40099784378-1 (1.0.259).

    Cloudflare cache status per class, read once each after the run:

    Request Cache status
    / and /feed.xml DYNAMIC
    /robots.txt REVALIDATED
    /favicon.ico MISS
    A media file, first request MISS
    The same media file, second request HIT
    The same media file with a fresh ?live-check= query MISS

    The last row is #496's per-run query doing its job: the edge copy cannot answer for a media file a release lost.

    For the next monthly 404 pass, both production hostnames are now proxied. ClientHost on their lines is a forwarded chain, which checks/log-review.jq already reads by its last element, and counts on cached file types are a floor.

  8. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    New next step, ranked first: #497. The blog site block sends no HSTS, nosniff, or Referrer-Policy, while the family block sends all three. The host side found it while measuring blog.insanegenius.com through the proxy, and a live read confirms it. Add the three headers to the blog baseline with the family values, verify every class on local staging, and release. Done means #497 is closed with the headers live on production.

  9. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    Round 27, closed 2026-10-24: Session Handoff [default]: Proxied-Run Check in OPERATIONS.md, Then the Monthly 404 Pass From 2026-11-23

    Next steps, in priority order

    1. Record the proxied-run confirmation in OPERATIONS.md. A live check counts as measured through Cloudflare only once the target answers server: cloudflare with a cf-ray header. Right after the viljoen.family flip, this machine's resolver still answered with the origin for about two minutes while DNS over HTTPS answered with Cloudflare. Add that sentence where OPERATIONS.md describes hand runs against production, in a small docs PR. Done means it is merged into develop. It needs no release on its own.
    2. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the whole procedure. Run it from the repository rather than rebuilding it by hand.
      • Use the window block in "Reading a 404 list without being fooled by it" with start='2026-10-23T15:42', where the last pass ended. checks/log-review.jq keeps the last element of ClientHost, so a proxied viljoen.family line reads correctly without a hand step.
      • viljoen.family is proxied since 2026-10-24T01:47Z. A cached file type there is answered at the edge, so its count is a floor, per "The log is three tiers".
      • Cross-check the 403s with "A 403 is CrowdSec's until shown otherwise", and check any crawler 403 or 404 by forward-confirmed DNS.
      • Run "Checking that search engines can index both sites". A 404 on /news-sitemap.xml is a regression, and so is one on viljoen.family/robots.txt, /sitemap.xml, /tag/review, /viljoen-family, or /20180811_172609507_ios.
      • A routerless https 404 cluster beside 502s is the edge restarting. Leave it alone.
      • When a new scanner shape crowds the list, add it to checks/log-review.jq in the same change that records the pass.
      • Done for a pass means a comment on this issue with the date range, the count left after filtering, and each finding's disposition.
    3. When the host side flips a blog hostname to proxied, run checks/check-live-urls.sh against it once with EXPECT_SITE_ENV set (SAMPLE_CONTRACT=1 for production), after confirming the proxy headers per step 1. Report the result to the HomeAutomation-Config session on ptr727/HomeAutomation-Config#580.
    4. #495: measure no-transform behind Cloudflare once a proxied host can serve a test release. Add it to the page classes only if a client that does not accept Brotli receives a body it can read.

    External blockers

    • Production log reads and CrowdSec reads need the maintainer's go-ahead. Ask once per session in a dialog before the first SSH or archive read. A past session's approval does not carry over.
    • Search Console is the maintainer's. Whether both sitemaps are submitted in Google Search Console is visible only there.
    • Every Cloudflare zone setting and proxy flip is host-side, ptr727/HomeAutomation-Config#580. The blog hostnames stay DNS-only until that session declares the insanegenius.com and insanegenius.net zone settings. It was told the Blog follow-up is in production, and that Caching Level must not be "Ignore Query String". Email Address Obfuscation must stay off until Measure no-transform Behind Cloudflare Before the Page Classes Carry It #495 settles no-transform. Bot Fight Mode cannot be written through the API on the family zone, so the dashboard toggle is the fix if it drifts.
    • The home-network CrowdSec allowlist is still ptr727/HomeAutomation-Config#893. Until it lands, keep production probes to a handful per pass. The host side measured that CrowdSec strips the query before classing a path static, so the live check's ?live-check= query does not touch the crawl budget.

    Internal dependencies

    • Step 3 needs step 1's confirmation, so a run made while the local resolver still points at the origin is not reported as a proxied measurement.
    • Step 4 needs a proxied host that can take a test release, which no host offers today: production is proxied but carries real readers, and the staging family host is DNS-only.

    State

    The parked decision queue

    Zero issues carry decision. This round asked four questions as it went, each answered: drive #494 to merge and release, do the follow-up PR in this session, drop no-transform past the edit budget and file it as #495, and merge and release #494 although its last Copilot round stated no coverage.

    What the last round did

    What not to repeat

    • Adding no-transform on the strength of the Email Obfuscation doc alone. The third strict pass found that Cloudflare's compression doc leaves undefined what happens for a client that does not accept Brotli. It cost a fourth pass and a revert. Measure no-transform Behind Cloudflare Before the Page Classes Carry It #495 holds the measurement.
    • A cache-busting helper that branches on an existing ?. No input reaches that branch, since the media list holds no query and Caddy's redir @uploads drops one. The second pass flagged it as dead code.
    • Writing a doc sentence that no-cache keeps a response "from being stored". It allows storage and requires revalidation. Copilot caught it on Defeat the Edge Cache in the Media Check and Name the Zone Settings #496.
    • A new inline link in deploy/README.md. That file now uses reference-style links, per the fleet rule. Only AGENTS.md, GOVERNANCE.md, OPERATIONS.md, and the Copilot file keep inline ones.
    • Reading a promotion's ccr-overview-v2 headline as a finding list. On Promote the Edge Proxy Cache Lifetimes #494 both rounds named concerns with no file or line. Answer each against the head with pr_review.py comment, then ask the maintainer about the unstated coverage.
    • Everything in the previous rounds' "What not to repeat" still applies, including the baseline header ahead of the redirects and no $var in gh pr merge.

    New learnings

    • Cloudflare's default cache key includes the query string at the default Standard caching level, a new zone's Browser Cache TTL of 4 hours replaces a shorter origin lifetime, and Email Address Obfuscation skips no-transform. Recorded in deploy/README.md "Cache lifetimes" and Measure no-transform Behind Cloudflare Before the Page Classes Carry It #495.
    • Behind Cloudflare, Caddy's client_ip is the leftmost forwarded address, which a client can write. Recorded in OPERATIONS.md and deploy/README.md "Trusting the proxy".
    • CrowdSec's http-logs parser strips the query before deriving the file extension, measured by the host side. This line is its only record here, since the Blog depends on it only through the live check's query.
  10. changed the title [-]Session Handoff [default]: Proxied-Run Check in OPERATIONS.md, Then the Monthly 404 Pass From 2026-11-23[/-] [+]Session Handoff [default]: Monthly 404 Pass From 2026-11-23, Then Header Assertions (#500)[/+] on Oct 24, 2026
  11. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    Round 28, closed 2026-10-24: Session Handoff [default]: Monthly 404 Pass From 2026-11-23, Then Header Assertions (#500)

    Next steps, in priority order

    1. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the whole procedure. Run it from the repository rather than rebuilding it by hand.
      • Use the window block in "Reading a 404 list without being fooled by it" with start='2026-10-23T15:42', where the last pass ended.
      • Both production names are proxied: viljoen.family since 2026-10-24T01:47Z, blog.insanegenius.com since 2026-10-24T14:26Z. ClientHost on their lines is a forwarded chain, which checks/log-review.jq reads by its last element. A cached file type is answered at the edge, so its count is a floor, per "The log is three tiers".
      • Cross-check the 403s with "A 403 is CrowdSec's until shown otherwise", and check any crawler 403 or 404 by forward-confirmed DNS.
      • Run "Checking that search engines can index both sites". A 404 on /news-sitemap.xml is a regression, and so is one on viljoen.family/robots.txt, /sitemap.xml, /tag/review, /viljoen-family, or /20180811_172609507_ios.
      • A routerless https 404 cluster beside 502s is the edge restarting. Leave it alone.
      • When a new scanner shape crowds the list, add it to checks/log-review.jq in the same change that records the pass.
      • Done for a pass means a comment on this issue with the date range, the count left after filtering, and each finding's disposition.
    2. #500: assert the security headers in checks/check-live-urls.sh. Its comment adds a second part: print server and cf-ray from the preflight, so a hand run shows whether it went through Cloudflare. If that lands, shorten the OPERATIONS.md "Deploying" probe paragraph to point at the preflight line. Done means a unit case fails on a missing header and the live check passes on staging.
    3. #501: survey what blog posts load before a blog CSP. Try any policy as Content-Security-Policy-Report-Only on local staging first. Whether to enforce it is the maintainer's call, so ask before shipping one.
    4. When the host side flips a VPS staging name to proxied, run the OPERATIONS.md "Deploying" probe first, then checks/check-live-urls.sh once with EXPECT_SITE_ENV, and report on ptr727/HomeAutomation-Config#580.
    5. #495: measure no-transform behind Cloudflare once a proxied host can take a test release.

    External blockers

    • Production log reads and CrowdSec reads need the maintainer's go-ahead. Ask once per session in a dialog before the first SSH or archive read.
    • Search Console is the maintainer's. Only he can see whether both sitemaps are submitted.
    • Every Cloudflare zone setting and proxy flip is host-side, ptr727/HomeAutomation-Config#580. That issue holds the 1.0.260 release note and asks for a re-measure of both proxied names. Email Address Obfuscation stays off until Measure no-transform Behind Cloudflare Before the Page Classes Carry It #495 settles no-transform. Edge HSTS stays off, per deploy/README.md "Security headers".
    • The home-network CrowdSec allowlist is still ptr727/HomeAutomation-Config#893. Until it lands, keep production probes to a handful per pass.

    Internal dependencies

    • Step 4 depends on the host side, and step 5 needs a proxied host that can take a test release, which none offers today.
    • Step 2's preflight print would replace the hand probe step 4 uses, so if step 2 lands first, step 4 uses the preflight line.

    State

    The parked decision queue

    Zero issues carry decision. This round asked four questions, and each was answered: squash-merge #498 and #499, squash-merge #503, merge and release #502, and post the release note on ptr727/HomeAutomation-Config#580.

    What the last round did

    What not to repeat

    New learnings

    • Both sites' security-header and cache posture, with the reason for each difference, is recorded in deploy/README.md "Security headers" and "Cache lifetimes".
    • How to confirm that a hand run went through Cloudflare is recorded in OPERATIONS.md "Deploying".
  12. changed the title [-]Session Handoff [default]: Monthly 404 Pass From 2026-11-23, Then Header Assertions (#500)[/-] [+]Session Handoff [default]: Settle the Staging Crawl Ban (#510), Then Deploy 1.0.263 and the 404 Pass From 2026-11-23[/+] on Oct 24, 2026
  13. ptr727 commented on Oct 24, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 29 close: one issue, #510. Put to the maintainer, who answered: decide later, since the route is for HomeAutomation-Config and the VPS deployment to decide, with Blog as one party, and the site should not get trapped by CrowdSec where Cloudflare covers the same protection. Filed as ptr727/HomeAutomation-Config#1374, and that repository's session was messaged. Step 1 therefore waits on #1374's outcome rather than on a Blog-side choice, and #510 keeps its decision label until then.

  14. ptr727 commented on Oct 25, 2026

    @ptr727
    OwnerAuthor

    Round 29, closed 2026-10-24: Session Handoff [default]: Settle the Staging Crawl Ban (#510), Then Deploy 1.0.263 and the 404 Pass From 2026-11-23

    Next steps, in priority order

    1. #510: settle how the VPS staging deploy avoids the CrowdSec crawl ban, then deploy 1.0.263 or later to VPS staging and production. The maintainer chooses between a host-side exemption and sampling VPS staging, as the issue sets out. If sampling wins, set SAMPLE_CONTRACT=1 for VPS staging in the deploy hook and update OPERATIONS.md "Deploying", which says staging proves the whole contract. A host-side exemption goes to ptr727/HomeAutomation-Config. Done means a VPS staging deploy passes, then production deploys and its sampled check passes through Cloudflare.
    2. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the procedure. Use the window block in "Reading a 404 list without being fooled by it" with start='2026-10-23T15:42', where the last pass ended. Both production names are proxied, so ClientHost is a forwarded chain that checks/log-review.jq reads by its last element. Cached file types are answered at the edge, so their counts are a floor. Cross-check 403s with "A 403 is CrowdSec's until shown otherwise", and run "Checking that search engines can index both sites". Done means a comment on this issue with the date range, the count left after filtering, and each finding's disposition.
    3. #501: survey what blog posts load before a blog CSP. Try any policy as Content-Security-Policy-Report-Only on local staging first. Adding a blog CSP means adding its row to checks/security-headers.txt, since the sync case refuses a Caddyfile header the file lacks. Whether to enforce it is the maintainer's call.
    4. When the host side flips a VPS staging name to proxied, run the check by hand once with EXPECT_SITE_ENV and read its <host> proxied line, then report on ptr727/HomeAutomation-Config#580.
    5. #495: measure no-transform behind Cloudflare once a proxied host can take a test release.

    External blockers

    Internal dependencies

    State

    The parked decision queue

    One issue carries decision: #510, filed this round, and put to the maintainer at this close.

    What the last round did

    What not to repeat

    • A hand-written reader for a structured format. A line regex, then a nesting-aware tokenizer for the Caddyfile, each drew another round of missed forms (path matchers, matcher-scoped blocks, match { status }, scoped deletions). Running caddy adapt and walking its JSON ended it. CODESTYLE "Parsing Structured Formats" already says this.
    • Telling the maintainer a release deploys. It does not. deploy-site.yml is a separate dispatch per environment.
    • Re-dispatching a release without checking for a bot run. A Dependabot auto-merge to main makes the merge bot dispatch its own release, which supersedes a manual one mid-publish. Read gh run list for a newer run on a later main before dispatching again.
    • Re-running the VPS staging deploy to win the crawl race. It lost twice, with checks of 34 and 41 seconds against 24 before this change. Keep the VPS Staging Deploy Check From Racing the CrowdSec Crawl Ban #510 is the fix.
    • Acting on a reviewer's claim about tool behavior unchecked. Copilot claimed the Caddy image sets an ENTRYPOINT, and a local pass claimed %header{} joins repeated headers. Both were false: docker image inspect shows no entrypoint, and curl 8.14 prints only the first copy.
    • Everything in the previous rounds' "What not to repeat" still applies.

    New learnings

  15. changed the title [-]Session Handoff [default]: Settle the Staging Crawl Ban (#510), Then Deploy 1.0.263 and the 404 Pass From 2026-11-23[/-] [+]Session Handoff [default]: Crawl Exemption Live, 1.0.263 Deployed Everywhere, 404 Pass From 2026-11-23 Next[/+] on Oct 25, 2026
  16. 9 remaining items

  17. ptr727 commented on Oct 25, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 33 close: empty, with no open issue carrying decision. Two questions were put to the maintainer this round and answered. The every-fetch gate extends the CSP gate, recorded on #529. Promotion #534 was to be merged, released, and deployed, which is done: 1.0.271 runs on all four sites.

    🤖 Generated with Claude Code

  18. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Round 33, closed 2026-10-25: Session Handoff [default]: Self-Hosted Fonts and Every-Fetch CSP Gate Live in 1.0.271, 404 Pass From 2026-11-23 Next

    Next steps, in priority order

    1. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the procedure. Use the window block with start='2026-10-23T15:42'. Both production names are proxied, so ClientHost is a forwarded chain that checks/log-review.jq reads by its last element, and counts for cached file types are a floor. 1.0.271 moved the blog's font to /fonts/lexend/ and dropped the Google links, so a 404 under /fonts/ is new, and so is a reader hitting an old Google URL. The pass needs a production-log go-ahead, asked in a dialog. Done means a comment here with the date range, the count left after filtering, and each finding's disposition.
    2. #535: leave /search/ out of a browser check run over another URL list, so a family-only run passes on its own pages. Done means check-csp-browser.py --urls over /en/ and /af/ against the family mirror passes.
    3. #532: one shared loader for a hyphenated sibling check, replacing the three copies in checks/.
    4. When the host side flips a VPS staging name to proxied, run the live check once with EXPECT_SITE_ENV and report on ptr727/HomeAutomation-Config#580. #495 waits on a proxied host that can take a test release.

    External blockers

    Internal dependencies

    • Steps 2 and 3 both touch checks/, in different files, so they can land in either order.
    • Step 4 needs the host side to flip a staging name first.

    State

    The parked decision queue

    Empty, with no open issue carrying decision. #513's label came off this round once the maintainer's Drive held all 95 originals. Two questions were asked and answered in the session: the gate's design, recorded on #529, and #534's scope, merge, release, and deploy.

    What the last round did

    What not to repeat

    • A Caddy path matcher with a wildcard mid-path, such as /fonts/*.woff2, matches nothing, and the files silently keep the default no-cache. Use a prefix, /fonts/*, and read Cache-Control back from the mirror rather than trusting the matcher.
    • Leaving the session's working directory inside a worktree when running pr_review.py cleanup. The remote branch deletes, then the local half stops on a locked directory. cd out first, then rerun cleanup.
    • Passing --arg to gh --jq. gh has no such flag and reads it as a subcommand. Interpolate the value into the expression instead.
    • A browser check run over the family pages with --urls. It also requests /search/ and fails there (Leave /search/ Out of a Browser Check Run Over Another URL List #535). Read only the family pages' own results.
    • Everything in earlier rounds' "What not to repeat" still applies.

    New learnings

  19. changed the title [-]Session Handoff [default]: Self-Hosted Fonts and Every-Fetch CSP Gate Live in 1.0.271, 404 Pass From 2026-11-23 Next[/-] [+]Session Handoff [default]: Fleet snake_case Python Names and Browser Check URL Lists in 1.0.273, 404 Pass From 2026-11-23 Next[/+] on Oct 26, 2026
  20. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 34 close: empty. #538 was put to the maintainer and answered: keep checks/ and scripts/, since they differ by Python profile. Recorded on #538, which is closed with its decision label removed. The body's step list does not change.

  21. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Round 34, closed 2026-10-26: Session Handoff [default]: Fleet snake_case Python Names and Browser Check URL Lists in 1.0.273, 404 Pass From 2026-11-23 Next

    Next steps, in priority order

    1. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the procedure. Use the window block with start='2026-10-23T15:42'. Both production names are proxied, so ClientHost is a forwarded chain that checks/log-review.jq reads by its last element, and counts for cached file types are a floor. 1.0.271 moved the blog's font to /fonts/lexend/, so a 404 under /fonts/ is new, and so is a reader hitting an old Google Fonts URL. The pass needs a production-log go-ahead, asked in a dialog. Done means a comment here with the date range, the count left after filtering, and each finding's disposition.
    2. #539: every Python script answers --help and refuses an unknown argument, and so does deploy/make-release.sh. Start with make-release.sh, which reads --help as its deploy root and starts a release. Done means each script on the issue's list answers -h and --help before any read, and a test covers it.
    3. #540: resync the carried instruction set per the hub's RESYNC.md. Blog's CODESTYLE.md lacks the file-name and command-line rules that Rename Every Python File to the Fleet's snake_case Names #537 and Answer --help and Refuse Unknown Arguments in Every Python Script #539 apply. Done means the audit's findings are applied and its report is filed hub-side.
    4. Add a "Disproved Claims" entry to .github/copilot-instructions.md for E402, through copilot-instructions-keeper. On Promote the Browser Check's URL Lists and the snake_case Python Names to Main #541, Copilot claimed ruff refuses an import after sys.path.insert. Blog's ruff config does not select E402, and every test now uses that pattern, so the claim will recur. Fold it into step 3 if that lands first.
    5. When the host side flips a VPS staging name to proxied, run the live check once with EXPECT_SITE_ENV and report on ptr727/HomeAutomation-Config#580. #495 waits on a proxied host that can take a test release.

    External blockers

    Internal dependencies

    • Step 4 edits a carried file, so it rides with step 3 where both are open at once.
    • Step 2's --help handling follows the command-line rule, which step 3 brings into this repository's own CODESTYLE.md. Neither blocks the other.
    • Step 5 needs the host side to flip a staging name first.

    State

    The parked decision queue

    One issue, #538: whether checks/ and scripts/ converge on one directory. The hub session's view, recorded there, is to keep the split, because the two directories differ by Python profile rather than by purpose. The recommendation is to keep both and close #538 on that reason.

    What the last round did

    What not to repeat

    • Running a script with --help before reading its usage header. deploy/make-release.sh --help started a release against the local production environment from the primary checkout. It stopped during the build when the pipe closed, and installed nothing (Answer --help and Refuse Unknown Arguments in Every Python Script #539).
    • Running ruff check --fix or ruff format over capture/. That directory is not declared, it is not ruff-clean, and the fix rewrote pre-existing code. Lint only the declared checks/ and scripts/.
    • Solving a fleet rule's symptom locally. A shared loader for hyphenated modules was a workaround, where the fleet rule removes the cause. Check the hub's CODESTYLE.md before inventing a helper, since Blog's carried copy is stale (Resync the Carried Instruction Set, Starting With CODESTYLE.md's General Rules #540).
    • Everything in earlier rounds' "What not to repeat" still applies.

    New learnings

  22. changed the title [-]Session Handoff [default]: Fleet snake_case Python Names and Browser Check URL Lists in 1.0.273, 404 Pass From 2026-11-23 Next[/-] [+]Session Handoff [default]: Script --help Handling in 1.0.276, 404 Pass From 2026-11-23 Next[/+] on Oct 26, 2026
  23. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 35 close: empty, with no open issue carrying decision. Four questions were put to the maintainer this round and answered. #542 was to be squash-merged into develop, and #545 merged and released, which is done as 1.0.276 with no deploy owed. The #542 cleanup ran, and the sweep found nothing. The hub was to get an issue for a carried CLI-usage harness, filed as ptr727/ProjectTemplate#3502.

  24. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Round 35, closed 2026-10-26: Session Handoff [default]: Script --help Handling in 1.0.276, 404 Pass From 2026-11-23 Next

    Next steps, in priority order

    1. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the procedure. Use the window block with start='2026-10-23T15:42'. Both production names are proxied, so ClientHost is a forwarded chain that checks/log-review.jq reads by its last element, and counts for cached file types are a floor. 1.0.271 moved the blog's font to /fonts/lexend/, so a 404 under /fonts/ is new, and so is a reader hitting an old Google Fonts URL. The pass needs a production-log go-ahead, asked in a dialog. Done means a comment here with the date range, the count left after filtering, and each finding's disposition.
    2. #540: resync the carried instruction set per the hub's RESYNC.md. Blog's CODESTYLE.md lacks the file-name and command-line rules that Rename Every Python File to the Fleet's snake_case Names #537 and Answer --help and Refuse Unknown Arguments in Every Script #542 now apply. Done means the audit's findings are applied and its report is filed hub-side.
    3. Add a "Disproved Claims" entry to .github/copilot-instructions.md for E402, through copilot-instructions-keeper. On Promote the Browser Check's URL Lists and the snake_case Python Names to Main #541, Copilot claimed ruff refuses an import after sys.path.insert. Blog's ruff config does not select E402, and the tests use that pattern, so the claim will recur. Fold it into step 2.
    4. When the host side flips a VPS staging name to proxied, run the live check once with EXPECT_SITE_ENV and report on ptr727/HomeAutomation-Config#580. #495 waits on a proxied host that can take a test release.

    External blockers

    Internal dependencies

    • Step 3 edits a carried file, so it rides with step 2.
    • Step 4 needs the host side to flip a staging name first.

    State

    The parked decision queue

    Empty. No open issue carries decision.

    What the last round did

    What not to repeat

    • Gating a script's test on a third-party module. checks/ CI runs bare uvx coverage, with no Pillow or PyYAML, so a find_spec skip there would have skipped redact_media.py and clean_content.py on every run. The fix was in the scripts: parse before reporting a missing module.
    • A try import that leaves names unbound for pyright. Setting a flag in the except branch made pyright report every Pillow name as possibly unbound. The except branch now parses and exits itself, so every path that continues has the names bound.
    • Checking an argument count before looking for --help. Copilot caught check-live-urls.sh extra --help refused as an extra argument. Scan every argument for help first.
    • Everything in earlier rounds' "What not to repeat" still applies.

    New learnings

    • The hub's own CLI test accepts a script with a required positional refusing on the missing argument first, provided a run that supplies it names the unknown flag. Blog's BEFORE_FLAG follows that.
  25. changed the title [-]Session Handoff [default]: Script --help Handling in 1.0.276, 404 Pass From 2026-11-23 Next[/-] [+]Session Handoff [default]: Fleet Resync in 1.0.277, Fuzz Gate Retirement and 404 Pass Next[/+] on Oct 26, 2026
  26. ptr727 commented on Oct 26, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 36 close: empty, with no open issue carrying decision. Questions put to the maintainer this round, and their answers:

    The env-file naming question was settled on the hub side as ptr727/ProjectTemplate#3503, with Blog's rename tracked in #550.

    🤖 Generated with Claude Code

  27. ptr727 commented on Oct 27, 2026

    @ptr727
    OwnerAuthor

    Round 36, closed 2026-10-26: Session Handoff [default]: Fleet Resync in 1.0.277, Fuzz Gate Retirement and 404 Pass Next

    Next steps, in priority order

    1. #549: retire the media parser fuzz gate. The maintainer ruled that Blog follows the carried GOVERNANCE.md "Trust Boundaries and Hardening Effort" rule, since every media input is the maintainer's own, and fuzzing has cost far more than it returned. Remove the script, its tests, its validate-action step, and every doc describing it, with the reference sweep a deletion owes. Keep the media gate's own metadata and damage checks. Done means Retire the Media Parser Fuzz Gate, Since Its Inputs Are Trusted #549 is closed with the gate gone and CI green.
    2. Run the next monthly 404 pass on or after 2026-11-23. OPERATIONS.md "Logs and Debugging" carries the procedure. Use the window block with start='2026-10-23T15:42'. Both production names are proxied, so ClientHost is a forwarded chain read by its last element, and counts for cached file types are a floor. A 404 under /fonts/ is new since 1.0.271. The pass needs a production-log go-ahead, asked in a dialog. Done means a comment here with the date range, the count left after filtering, and each finding's disposition.
    3. #546 and #547, small conformance fixes the resync surfaced. Let the Read Be the Check in the checks/ Gates That Probe First #546 lets the read be the check in the checks/ gates that probe first. Remove the Incidental Counts From OPERATIONS.md #547 removes incidental counts from OPERATIONS.md. They touch different files and can ride one pull request each.
    4. #550: rename the host env files to blog_<server>_<environment>.env. It is blocked until Apply One Naming Convention to Every Env and Secret File, Host-Side Files Included ProjectTemplate#3503 writes the rule into the hub's CODESTYLE.md. Then it lands in the resync that carries that rule, and the pull request lists the host-side rename as the maintainer's step.
    5. When the host side flips a VPS staging name to proxied, run the live check once with EXPECT_SITE_ENV and report on ptr727/HomeAutomation-Config#580. #495 waits on a proxied host that can take a test release.

    External blockers

    Internal dependencies

    State

    The parked decision queue

    Empty. No open issue carries decision.

    What the last round did

    What not to repeat

    • Rewording policy prose round after round under local review. The "Trust Boundaries" subsection drew new findings against each previous round's wording, through four rounds. What ended it was deleting the local exception and letting the carried section govern. Prefer deletion over new wording once a second pass finds the first fix's text.
    • Assuming ruff's default rule set. Ruff 0.17.2's defaults hold no E402, while older documentation lists E4 as a default. The E402 entry names its ruff version for that reason. Read ruff check --show-settings before citing a default.
    • Opening a dependent pull request before its rules land. The config branch cited exception numbers the carried GOVERNANCE.md only gained in Resync the Carried Instruction Set and Skills Tree With the Hub #548. Merge the instruction set first, then merge develop into the dependent branch.
    • Everything in earlier rounds' "What not to repeat" still applies.

    New learnings

    • A resync applies an intent file by git applying the hub's own diff since the copy's last resync revision, which keeps local sections by construction. That held again here for CODESTYLE.md, WORKFLOW.md, and the Copilot runbook's hunks. A hunk touching the hub's own ledger entries is carried by hand instead.
  28. changed the title [-]Session Handoff [default]: Fleet Resync in 1.0.277, Fuzz Gate Retirement and 404 Pass Next[/-] [+]Session Handoff [default]: Env File Rename in Develop, Secret Readers Next After Hub #3534[/+] on Oct 27, 2026
  29. ptr727 commented on Oct 27, 2026

    @ptr727
    OwnerAuthor

    Parked decision queue at the round 37 close: empty, with no open issue carrying decision. Questions put to the maintainer this round, and their answers:

    🤖 Generated with Claude Code

  30. ptr727 commented on Oct 27, 2026

    @ptr727
    OwnerAuthor

    State update after the round 37 close: the cleanup dialog was answered. The #557 worktree, its local branch, and origin/chore/env-file-underscore-names are removed, and git worktree list shows only the primary checkout.

  31. ptr727 commented on Oct 27, 2026

    @ptr727
    OwnerAuthor

    State update after the round 37 close: the maintainer asked for a promotion, then for merge and release. Promotion #558 merged into main as c8e5bba and closed #550. publish-release run 40600286491 published 1.0.280 from c8e5bba. No deploy is owed, since nothing the server sends changed. Next steps 3 (promote) is done. #553 still waits on ptr727/ProjectTemplate#3534 reaching hub main. The list-only cleanup sweep reported no problems, and the primary checkout is clean on develop at b885743.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    handoffA link in the session handoff chain, one open issue per track

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions