Harden Worker, site shell, gate suite, and Loopy skill - #98
Open
trollbot2012 wants to merge 33 commits into
Open
Harden Worker, site shell, gate suite, and Loopy skill#98trollbot2012 wants to merge 33 commits into
trollbot2012 wants to merge 33 commits into
Conversation
check.mjs asserted on embedded \n and failed on core.autocrlf=true clones. Normalise CRLF on every text read and add .gitattributes so future checkouts stay LF. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- .dev.vars.example: OAUTH_CALLBACK_ORIGIN uses the live .com callback host, not the redirect-only .ai host - examples/loop.json: categoryLabel matches loop-schema's mapping for its category; AGENTS.md documents that requirement - README: publish checklist includes llms.txt; layout line names loop-library/scripts/ and loop-library/audits/ - seo-geo audit: stop-state heading dated and page count at capture noted - CHANGELOG: 2026-07-07 entry for popular sort, homepage shell fallback, .ai redirect docs, hardened harness checks Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…en node --check - Vote handler now calls TURNSTILE_RATE_LIMITER keyed on the verified viewer id (vote:<sub>) and returns the same 429 shape as the forms. - Atom feed <published>/<updated> use Z instead of a hardcoded -07:00, matching formatDate's UTC pin. - Remove unreferenced randomUrlSafe and latestModified. - package.json check covers loop-routes, catalog-store, render-loops, loop-schema. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…branch Adds four FormGuard/handleRequest tests: suggestions 10/day, weekly signups 5/hour and 10/day, and a suffix-allowed Origin that is still rejected by Turnstile hostname verification. Daily caps seed the guard's storage with 5h-old events rather than injecting a clock. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Instantiate the real classes with a node:sqlite DatabaseSync adapter so the schema, CHECK constraints, upsert and revision writes, and the export/restore contract are executed instead of substituted by in-memory namespaces. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
styles.css already named both families but nothing loaded them, so production rendered system fallbacks. Add @font-face rules (Inter variable wght 100-900 latin subset from rsms/inter v4.1; IBM Plex Mono 400/600/700 Latin1 split subsets from @ibm/plex-mono 2.5.0; both SIL OFL, licenses alongside), preload the sans face on the three shell pages, bump the styles.css cache token to 20260902-self-hosted-fonts (check.mjs pin and the Worker loop-page template updated in step), and drop the unused --violet token. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rm fail-closed - Worker reads VOTE_STORE totals when rendering the homepage and emits data-upvotes plus initial counts per row, so the client's first sort matches the post-/api/votes order. - vote-controls and share-actions get role="group"; vote, copy, and show-more labels carry the loop title so each control is distinct. - learn/ and agents/ pages gain twitter:card/title/description/image. - Form protection fails closed with a visible status when no Worker origin is configured. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Round 1 shipped the fonts but nothing went red when a woff2 was renamed. Assert every @font-face url() and every as="font" preload href resolves under site/, >= 4 @font-face blocks each with font-display: swap, and both OFL license files present. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Client sends form_elapsed_ms; Worker returns the honeypot fake-success
(202 {ok:true}) and writes nothing when it is missing, non-integer, or
below 1200 ms (suggestions) / 800 ms (weekly signups).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…validation, dev vars, node --check coverage, empty-tree whitespace check - check.mjs mirrors every skills/loopy/references file into skills/loop-library via readdir + sorted listing equality instead of three hand-listed files - gate SKILL.md -> references/audit.md and audit.md content fingerprints - validate examples/loop.json with normalizeLoopDocument and categoryLabel (categoryLabel fixed to Engineering; same one-word edit as P3) - assert .dev.vars.example uses signals.forwardfuture.com (same fix as P3) - assert package.json check covers every src/*.js; widen script (same line as P7) - replace vacuous post-npm-ci `git diff --check` with a diff from the empty tree so every tracked file is scanned; pinned identically in CI/AGENTS/README Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Assert the llms.txt publish phrase and loop-library/audits/ in README, the dated stop-state heading in the SEO audit, and that the newest CHANGELOG entry (2026-07-07) is the first heading. Wrap README line 301. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Homepage, loop detail, catalogs, llms.txt, sitemap, feed, and the public catalog API now send `public, max-age=60, stale-while-revalidate=600` instead of `no-store`. Nothing on those surfaces is per-viewer: vote controls render as hidden placeholders and counts load from /api/votes. Fallback 5xx homepages, admin, session, vote, and OAuth routes stay no-store. AGENTS.md read-back step notes the 60s window. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…il-closed, warn on vote-store failure Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… ready verdict - Canonicalize run.md's six receipt states across SKILL.md, audit.md, discover.md - Add untrusted-content clause to publish.md - Add 'Not ready' Loop Doctor verdict with Result guidance - check.mjs: fingerprint the new Verdict line, forbid 'stagnated', assert the preflight bullet, publish.md 'untrusted', and audit.md '| Not ready' - Mirrored byte-for-byte into skills/loop-library/references Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Missing-loop 404s (JSON and HTML) return to no-store so a slug probed before publish is not served stale afterwards. The injected homepage now copies only Content-Type, Content-Language, and Vary from the shell origin, so a shell Set-Cookie or WWW-Authenticate cannot land in a publicly cacheable response. The unreachable-shell 502 fallback is now pinned no-store by test. AGENTS.md read-back step tells maintainers to use a cache-busting query string. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The homepage uses U+2192 in two <option> labels; it was outside the Inter subset and unicode-range, so it fell back to the system font. Also trim the verbatim upstream trailing whitespace on line 21 of the IBM Plex Mono OFL so the repo-wide whitespace gate stays green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…eck.mjs - Alias body now matches loopy/SKILL.md except name/description/header - check.mjs: legacySkillSource joins the 'stagnated' loop; preflight bullet asserted on both trees via whitespace-tolerant regex so a re-wrap cannot break CI Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- openai.yaml (both skills): short_description leads with Find; default_prompt routes to a published loop before crafting instead of forcing the interview. - SKILL.md: 'Validate every crafted loop' no longer restates the design rules; it points at 'Design the feedback cycle' + 'Keep every workflow grounded' and keeps only the preflight-unique items (one-shot fallback, Not ready). - audit.md: 'Check for' bullets replaced by a pointer to the same normative list; run-evidence linkage and no-score/no-budget guidance unchanged. Mirrored byte-for-byte into skills/loop-library/references. - check.mjs: pin the new default_prompt phrase and 'Find,' prefix; move the P8 terminal-state preflight pin onto the normative bullet; pin the new preflight and audit pointer phrases. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…no-store headers, docs - script.js changed (required form_elapsed_ms, a11y, fail-closed) without a cache-bust; old cached scripts posted without the field and got the silent 202. Bump to 20260902-elapsed-a11y on all three shell pages, the Worker loop-page template (was stale 20260623-proxy-auth), and check.mjs pins. - check.mjs now asserts render-loops.js carries the same script token as index.html so Worker pages cannot drift from the shell again. - loop-routes.js: comment reflects embedded vote totals + 60s public cache; NO_STORE_HEADERS const replaces six inline literals. - index.js: drop foreign ponytail: comment prefix. - AGENTS.md: document per-account vote rate limit (30/min via TURNSTILE_RATE_LIMITER). CHANGELOG: 2026-09-02 entry; check.mjs first-heading pin moved to 2026-09-02. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… run A 13-piece fan-out met every per-piece check yet 9 pieces served a goal the operator had not asked for, because the piece list came from a whole-repo survey. Add one sentence to run.md step 2 (mirrored to the loop-library alias) and pin it in check.mjs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hardening pass over the Worker, site shell, gate suite, and the Loopy skill. Every change was built in its own branch and independently re-verified: full gate suite rerun, each new check mutated to prove it fails when the fix is reverted, and a written review before merge. Baseline gates were green before this work except one:
loop-library/scripts/check.mjsfailed on any Windows clone withcore.autocrlf=true(CRLF vs\nassertions).Worker tests: 52 → 72, passing on Node 22 and Node 24.
Worker
form_elapsed_ms, 1200 ms suggestions / 800 ms weekly), mirroring the honeypot's fake-success response. Previously client-only, so a direct POST skipped it./api/loops) sendpublic, max-age=60, stale-while-revalidate=600instead ofno-store. 404s, 5xx fallbacks, admin, session, vote and OAuth responses stayno-store. The homepage now copies only an allowlist of shell headers, so a shellSet-Cookiecan never land in a cached response.Z) instead of a hardcoded-07:00.LoopCatalogandVoteStoreagainst SQLite vianode:sqlite(both classes previously ran only behind in-memory mocks); tests for the 10/day and weekly 5/hour limits and the origin-suffix branch.npm run checknownode --checks every source file.Site
data-upvotes, so first paint is already in "Most popular" order instead of reshuffling after/api/votesreturns.role="group"with per-loop labels; copy/show-more buttons name the loop. Twitter card meta onlearn/andagents/. The form guard fails closed (buttons disabled, status shown) when the API origin is missing.font-display: swap); the CSS already named them but nothing loaded them.styles.cssandscript.js(the Worker-rendered pages were on a different, stalescript.jstoken; a new gate keeps them aligned).Gate suite and CI
.gitattributespins LF andcheck.mjsnormalises CRLF on read, so the documented pre-commit checks run on Windows.check.mjsnow mirrors everyskills/loopy/references/*file againstskills/loop-library/references/*by directory listing, gatesaudit.md, validatesexamples/loop.jsonwith the realnormalizeLoopDocument, checks.dev.vars.examplepoints at the.comcallback host, and asserts everysrc/*.jsis in thecheckscript.git diff --checkstep ran on a clean tree afternpm ciand inspected nothing; it is replaced withgit diff --check $(git hash-object -t tree /dev/null) HEAD, pinned identically in ci.yml, AGENTS.md, README.md and check.mjs.Loopy skill
publish.mdgets the untrusted-content clause the other paths already had.Not readyverdict for gaps that cannot be repaired from scoped evidence.agents/openai.yamladvertises Find first instead of forcing the crafting interview.Docs
.dev.vars.examplepointed OAuth at the redirect-only.aihost;examples/loop.jsoncarried acategoryLabelthe renderer never shows; README publish checklist lackedllms.txt; the SEO audit presented a June snapshot as current; CHANGELOG backfilled and extended.Not included
mainper AGENTS.md.Cache-Controlis undocumented; the headers are correct at the Worker boundary regardless.Test plan
node --check loop-library/site/script.jsnode loop-library/scripts/check.mjs(also on a freshcore.autocrlf=trueclone)npm --prefix loop-library/worker run checkon Node 24.18 and Node 22.23 (72/72)git diff --check, and the new repo-wide whitespace checkdiff -r skills/loopy/references skills/loop-library/referencesempty🤖 Generated with Claude Code