Skip to content

Fixes from the repo review (#1 to #47) - #49

Merged
TMHSDigital merged 32 commits into
mainfrom
review-fixes
Sep 26, 2026
Merged

TMHSDigital merged 32 commits into
mainfrom
review-fixes

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Fixes from the 2026-09-25 repo review (issues #1 to #47). One commit per issue or per interlocked group; each commit body says what changed and why. npm run check (tests, validate, build) passes.

CI

Build and checks

Tooling and docs

Site

Word-start search ranked by name and tags (#16), rows toggled instead of rebuilt (#17), focus kept after removing a filter (#18), h4 card titles and a full-sentence count (#19), contrast (#20), touch targets (#21), URL params validated (#22), deferred scripts (#23), visible per-file note on Commercial OK (#25), folding filters on phones (#26), back-to-results breadcrumb (#44), 404 suggestions (#46), sitemap link (#24).

Catalog

Not in this PR

#3 (branch protection, deferred), #36, #37 (canonical format list), #38, #40, #41 (remaining fields: sources do not state them), #42, #43, #45, #47. See the new section in docs/review-ledger.md.

After merge: submit sitemap.xml in Search Console and Bing Webmaster Tools.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ

TMHSDigital and others added 30 commits September 25, 2026 19:50
- Drop the push path filters. They left out stacks/**, so a stacks-only
  push was neither validated nor deployed until the Monday rebuild, and
  pages.yml also left out README.md, which the validator reads. The run
  takes seconds, so filtering saved nothing.
- Pages calls the CI workflow (workflow_call) instead of repeating its
  steps, then builds and deploys.
- Node 24 (current LTS) via .nvmrc for both; Node 20 is past end of life.
- checkout v7, setup-node v7, upload-pages-artifact v5, deploy-pages v5.
- ci.yml gets permissions: contents: read.
- Dependabot keeps the action versions current, monthly.

Fixes #1
Fixes #2

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
catalog/video/ has six entries, but the form's category dropdown stopped
at tools. The validator now checks the dropdown against the catalog
folders (next commit). The correction and new-source labels the forms
apply now exist in the repo.

Fixes #5

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
… loudly

Parser (lib/frontmatter.mjs, used by build and validate):
- build.mjs and validate.mjs each had a parser and they had drifted:
  validate kept \" escapes in ccmixter's attribution string, and its
  evidenceSection treated a following "## Extras" as Evidence.
- Flow lists split on commas inside quotes and never unquoted items;
  block lists read as null; a repeated key won silently. Now: quoted
  commas stay in one item, block lists parse, and a repeated key or a
  line that is not key: value is an error with its line number.
- A byte-order mark is ignored instead of hiding the entry.

Build:
- Summaries come from the page's own inline renderer with tags dropped,
  so underscores and # stay literal: "Rig_Medium", not "RigMedium", and
  "KHR_draco_mesh_compression". Five summaries change.
- An entry that cannot be read, or a missing index.html marker, fails
  the build instead of printing a warning and publishing a site with
  the entry missing. The exitCode = 0 line did nothing and is gone.

Checks:
- V16: url must be http(s). javascript: and data: URLs passed and were
  rendered as the "Go to source" link.
- verified, Evidence and walked dates must be real calendar dates;
  2025-13-01 passed and 2026-02-30 rolled over to 2 March.
- Evidence dates inside URLs no longer count, so a link to
  .../2026-09-20-notes cannot hide a bumped verified date. No entry's
  newest Evidence date changes.
- "In the future" means after tomorrow in UTC, so a contributor east of
  UTC can write their own today.
- V17: catalog folders, config.json categories and the new-source form
  must list the same categories. A folder missing from the config
  vanished from the homepage without a word.
- V18: a link fragment into a Markdown file must name one of its
  headings. All 13 in the repo resolve.
- The binary-file scan skips hidden folders and _scratch, which are not
  repo content (it failed on local git worktrees under .claude/).

Markdown renderer:
- Link hrefs keep one level of balanced parens (Foo_(bar)).
- Italic that would cross a bold boundary stays literal instead of
  producing <strong><em></strong></em>.
- Heading ids are unique on the page and avoid the template's own ids.

Tests: 21 lib assertions and 19 check assertions added.

Fixes #7
Fixes #8
Fixes #9
Fixes #10
Fixes #11
Fixes #12
Fixes #13
Fixes #14
Fixes #15
Fixes #30

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
- package.json (no dependencies) with test, validate, build, check (all
  of them in CI order), counts, new-entry and serve. The README's local
  checks now use it; before, they left out node site/lib/lib.test.mjs,
  which CI runs.
- node site/new-entry.mjs <category> <id> copies the template with the
  id, category and date filled in, refuses an id used anywhere in the
  catalog, starts at needs-review, and prints the remaining steps.
- node site/sync-counts.mjs rewrites both category count tables, the
  badge, "Browse N sources", "searches all N entries" and
  expectedEntryCount from the catalog. Adding an entry took about seven
  hand edits across three files; it now takes the entry, its README row
  and this command.
- V6 also checks "searches all N entries", which nothing checked.
- README layout lists stacks/, site/lib/, the two scripts and
  package.json; .gitignore ignores node_modules/.

Fixes #6
Fixes #29

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
- TEMPLATE.md: license_spdx is a real line. Copied as it was, the
  template failed V3 (CC0 maps to CC0-1.0, license_spdx absent).
- CONTRIBUTING: the steps use new-entry and sync-counts, and say what
  the validator enforces that was undocumented: attribution_string is
  required when attribution_required is true, verified may not be newer
  than the newest Evidence date (V8), deprecated entries need a
  "- Deprecated:" line (V9), url must be http(s), dates must be real,
  repeated keys and emoji are rejected.
- PR template: the category README row, sync-counts, stacks, and
  npm run check.
- The three design specs say implemented, not awaiting review.
- SECURITY.md: private vulnerability reporting is enabled; say so.

Fixes #27
Fixes #28
Fixes #31

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
r04 was a review-batch marker that leaked into the published tags of
15 entries. It is not a descriptive tag, so it is dropped. No other
field changes.

Fixes #35

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Data half of the subcategory cleanup:
- tiles -> tileset (the kept spelling in CONTRIBUTING)
- pixel-art -> pixel
- ir -> impulse-responses
- base-mesh -> base-meshes (the spelling CONTRIBUTING uses as its example)
- drop gui where ui is also set
- drop the 2d subcategory inside the 2d category
- drop public-domain as a subcategory: it is a licence, and each of the
  four entries already carries descriptive subcategories (archival,
  stock-footage, planetary, images, video, audio)

No README or config referenced the old values. The alias table in the
checks is left for a separate change.

Refs #34

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
- game-ok -> games-ok
- ps1 -> psx (psx is already in two entry names)
- godot rule: every Godot-specific entry carries godot; an entry that
  targets Godot 4 also carries godot-4. So the 19 godot-4 entries gain
  godot, and a godot filter now finds all Godot entries. The nine
  godot-only entries are unchanged (several are Godot 3 or mixed).
- drop cc0 from blenderkit and universal-lpc-generator (licence is
  varies) and public-domain from openclipart (licence is CC0), since
  those tags contradicted the licence field.

No licence fields changed. The wider licence/publisher tag question in
the issue is left open.

Refs #36

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
- JPEG -> JPG (nasa-image-video-library), matching texture-ninja
- godot-project -> Godot, the engine-target spelling CONTRIBUTING uses
- glTF KHR_draco -> glTF on google-draco (Draco is a glTF extension;
  the body already names KHR_draco_mesh_compression)
- GPL -> gpl-palette on lospec, so a GIMP palette no longer reads as
  a licence
- add glTF beside GLB where the entry shows GLB is what is offered
  (quaternius-universal-animation-library 1 and 2, and
  3dmodelscc0-melee-weapons, whose listing points at a GLB mirror).
  GLB is binary glTF. 3dmodelscc0-city and 3dmodelscc0-guns are left
  as they are: their bodies say the listing does not name a format.
- ktx and ktx2 on ktx-software are kept: KTX 1 and KTX 2 are distinct
  container formats and the tool handles both.

Refs #37 (the canonical format list and its check are still open)

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Each pair shares a rights-holding publisher, so the entries now group:
- pixabay-audio, pixabay-videos -> Pixabay
- sky3d, terrain3d -> TokisanGames
- ansimuz-sunnyland, ansimuz-industrial-parallax -> ansimuz

None of these publishers was already spelled another way in the
catalog. The license_spdx half of the issue is not touched here.

Refs #39

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
The repo moved from GDQuest to gdquest-demos. Checked 2026-09-25:
github.com/GDQuest/godot-3d-mannequin redirects to
github.com/gdquest-demos/godot-3d-mannequin, and the GitHub API reports
that full name (not archived). Only url changes; the Evidence section
does not link the old URL. The versioned zip and http-only URLs in the
issue are not touched here.

Refs #32

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
- V13 folded only a trailing "s", so base-mesh and base-meshes (two
  entries each) passed as different values. It now joins an -es or -ies
  plural to its singular when that singular is in use, and only after a
  sibilant for -es, so "shades" never meets a "shad".
- V19: site/value-aliases.json records the spellings the catalog
  metadata pass merged (tiles -> tileset, pixel-art -> pixel,
  ir -> impulse-responses, gui -> ui, base-mesh -> base-meshes, ps1 ->
  psx, game-ok -> games-ok, JPEG -> JPG, godot-project -> Godot), per
  field, and forbids public-domain as a subcategory. A tag shaped like
  an internal review marker (r04) is rejected.
- CONTRIBUTING names the kept spellings and the alias file.

Fixes #34
Fixes #35

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
site/check-links.mjs fetches every non-deprecated entry's url (8 at a
time, 20 s timeout, one retry) and reports dead links, sources that
moved to another domain or GitHub repository (the gdquest mannequin
move stayed on github.com and would have been missed otherwise), and
entries verified more than a year ago. 401/403/429 answers are listed
for a manual look but never raise the issue alone: on 2026-09-25 seven
sites refused the checker while serving people fine.

links.yml runs it every Monday and opens or updates a single issue
titled "Link check: N sources need a look", labelled correction. It
edits no entry. Local: npm run links. Today's run: 317 checked, none
dead, none moved, none stale.

Fixes #4

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
robots.txt is only read at a host's root, so the Sitemap line in
/Free-Game-Dev-Assets/robots.txt is never seen. The homepage now carries
<link rel="sitemap">, and site/README.md says the step that actually
gets it read: submitting it once in Search Console and Bing Webmaster
Tools, which only the maintainer can do.

Fixes #24

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
blender-ellie-poses and blender-human-base-meshes linked versioned zips
(v2.0.0, v1.4.1) that 404 once Blender replaces them. Both now point at
https://www.blender.org/download/demo-files/#assets, whose Asset
Bundles section lists both (read 2026-09-25), and which both entries
already cite. Only url changes.

With the gdquest-3d-mannequin move (earlier commit), this closes the
URL fixes. The http-only makehuman and cmu-mocap pass the new url check
(V16), and the sites that refuse robots are listed by the weekly link
check for a manual look.

Fixes #32

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Each query word now has to start a word in the entry's text, so "ui" no
longer finds "build" or "guide" and "art" no longer finds "earth"
(?q=ui drops from 106 to 52 entries). The plural fallback ("buttons"
finds the "button" tag) is kept.

Search text is split into three fields, normalised once at load: name
and tags, other metadata, summary. Under the default sort a search
ranks name and tag hits above metadata hits above summary-only hits,
then orders by name; the sort option now says so.

Fixes #16

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Filtering used to compute every entry's search text twice per keystroke
(once for the chip counts, once for the grid) and rebuild about 5,500
grid nodes through innerHTML. Now:

- the search text is normalised once at load (previous commit) and each
  change makes one pass over the catalog, shared by the chip counts and
  the grid;
- the grid adopts the prerendered rows and headings and keeps one node
  per entry and heading; deprecated entries, which the build leaves out,
  are rendered once. A change toggles `hidden` and moves nodes only when
  the order changes (another sort, or a ranked search);
- typing waits 120 ms for a pause; every other control applies at once.

A filter change now takes about 4 ms including layout in a desktop
Chromium, down from about 124 ms reported in the issue.

Fixes #17

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Removing a filter chip, "Clear all" or the empty-state reset re-renders
the button away, and focus fell back to the document body. Focus now
moves to the chip that took the removed one's place, or, when none is
left or everything was cleared, to the result count, which takes
programmatic focus (tabindex="-1") and shows a focus ring for keyboard
users.

Fixes #18

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Category headings and entry titles were both h3, so the catalog's
outline was flat. Entry titles are now h4 under the h3 category
headings, in the prerender (build.mjs, the title tag only) and in
app.js alike. A flat list (another sort, or one category) has no
category headings, so it gets a visually hidden h3, "Matching entries",
and the outline never skips a level.

The result count, which is the live region, now reads "52 of 319
entries shown" instead of "52 / 319". The prerendered no-script text
still uses the short form; that string lives in build.mjs outside the
heading markup and is left for a separate change.

Fixes #19

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
The chip counts were faded with opacity (0.7, and 0.45 for an empty
category), which took them to 2.92:1 in light and 4.25:1 in dark. They
now use the chip's solid text colour, the muted token: 5.29:1 light,
7.52:1 dark, measured in the browser on every count. The count is set in
the mono face so it still reads apart from the label, and an empty
category is marked by a dashed outline and its 0 instead of by fading.

Fixes #20

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Under pointer: coarse, "Open source" and "Entry and evidence" were about
17px tall inside the card-wide title link, so a near miss opened the
entry page. They now get 13px of padding cancelled by an equal negative
margin: a 45px hit area with no change to the card's layout (checked
with hit tests across the full height in a touch-emulated 360px
Chromium). Chips, checkboxes, the selects and the legend toggle get the
44px minimum they already had on narrow screens on every touch screen.

Fixes #21

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
readUrl() trusted the query string, so ?view=bogus or ?cat=nope showed
0 results with a blank select and ?sort=foo showed a blank sort and an
unsorted list. cat, sort and view are now checked against the category
keys, SORTS and the perspective list, and the boolean flags accept only
1 or 0. Anything else keeps its default, and the first apply() rewrites
the URL without it.

Fixes #22

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
data.js and app.js were parser-blocking at the end of the body. Both
are now deferred: they still run in order before DOMContentLoaded, and
the rows they hydrate are prerendered, so the page is complete before
they run. The legacy #entry-<id> redirect and hash jumps still work.

Google Fonts already loads with display=swap behind preconnect hints on
every page, so nothing changes there. Self-hosting the two families,
which the issue also suggests to drop the third-party request, is left
for a separate pass.

Fixes #23

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
"Commercial OK" deliberately keeps commercial: varies aggregators, but
the only on-page explanation was a hover-only title, which touch and
keyboard users never see. The title is gone. While the filter is on, a
note under the filters says it keeps per-file review sources and asks
the reader to check the licence of each file; the checkbox is described
by that note (aria-describedby), and its active-filter chip now reads
"commercial OK or per-file review".

A separate "include per-file sources" toggle was the other option in
the issue; the note keeps the filter's documented meaning unchanged.

Fixes #25

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
At 360px the filter panel was about 530px of chips and checkboxes
between the search box and the first entry. At 640px and below the
category chips and the status, terms, view and sort controls now fold
behind a "Filters" button (aria-expanded, aria-controls), which shows
how many filters are set, e.g. "Filters (2)". The search box, the
result count (the live region), the commercial note and the
active-filter chips stay visible. The folded panel is 163px tall at
360px. app.js does the folding, so a page without the script keeps the
panel open; wider screens never show the button.

The jump link the issue asks for is already in the hero ("Browse
catalog"), next to "Catalog" in the top nav and the skip link.

Fixes #26

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
"Catalog" in an entry page's breadcrumb went to ../../#catalog, which
dropped the reader's search and filters. The homepage now keeps its
current query string in sessionStorage whenever it rewrites the URL
(and clears it when nothing is set), and entry.js points the breadcrumb
link, marked data-back-to-results, at ../../?<query>#catalog. Without
the script or the storage the link stays the plain catalog link.

entry.js now loads on every entry page, not only on those with a
credit line to copy; the copy button still appears only where there is
one. The lib tests say so, and credit() loses its now unused script
flag.

Fixes #44

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
A mistyped address such as /entry/kenny-ui/ now gets up to five
suggestions ("Kenney UI Pack" first for that one) and a link to search
the catalog for the same words (?q=kenny%20ui). The new
site/public/not-found.js reads the missing path, compares it by letter
pairs with each entry's id and name, prefers live entries over
deprecated ones, and builds the list with DOM calls, never innerHTML.
With no close match only the search link appears; without the script
the page is as before.

build.mjs changes only in the 404 template: an empty #suggestions slot
and deferred data.js and not-found.js, loaded from the site root like
the page's stylesheet.

Fixes #46

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Before the script runs, the count said "317 / 319"; the script writes
"317 of 319 entries shown". The prerender now says the same, so
screen readers and no-script readers get the full sentence too.

Refs #19

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Three entries had attribution_required true although their licences
only require a licence or notice to travel with redistributed copies.
Each was re-read live on 2026-09-26; the vocabulary classes all three
licence values as "notice", so no waiver marker is needed.

- material-symbols (Apache-2.0): Google's README says "We'd love
  attribution in your app's *about* screen, but it's not required."
  Section 4(a) of LICENSE requires a copy of the licence with
  redistributed copies; the repository has no NOTICE file. Set false,
  dropped the credit string, added a Notes bullet on the notice duty.
- ms-building-footprints (CDLA-Permissive-2.0): section 2.1 only asks
  that the agreement text travel with shared Data, and 3.1 puts no
  obligation on Results. The README asks for no credit or citation.
  Set false, dropped the credit string, added a Notes bullet.
- microsoft-rocketbox (MIT): LICENSE.md requires the copyright and
  permission notice in all copies; the README's citation request is
  for research use only. Set false, dropped the credit string (it was
  a "keep LICENSE.md" instruction, now in Notes).

Each entry gets dated Evidence lines and verified 2026-09-26.

Fixes #33

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Swept the 2D entries lacking camera_perspective or grid_dimensions and
read each source page live on 2026-09-26. A value was set only where
the page says it in words.

- bondoki-rotating-gems: grid_dimensions 52x52. OpenGameArt page:
  "size per tile is 52x52 pixels".
- lpc-revised-basics: camera_perspective isometric_3_4. The submission
  names the author's GitHub repository as the home of the collection;
  its README says "a 32-pixel style, with a three-quarters (top-down)
  perspective". Recorded in Notes. No grid set: "32-pixel style" is
  not a stated frame or tile size for this pack.

Left unset because the page states no view or size: the Kenney card,
board game, puzzle and pixel vehicle packs (Kenney asset pages list
tags, file count and licence only), kenney-roguelike-characters and
ansimuz-sunnyland grids, sylly-gem-match-3, glitch-archive and
universal-lpc-generator. Left unset because no single value fits:
publisher and aggregator entries (opengameart, craftpix, penzilla,
pixel-frog, screaming-brain-studios grid, gameart2d-freebies),
sparklin-superpowers (platformer and top-down packs in one repo),
kenney-1-bit-pack (multi-perspective, per the review ledger), and the
palette entries lospec and paleto-vol01.

Refs #41

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
#48 fixed impossible dates (#10) independently. Keep its isRealDate,
which also handles years 0000-0099 and non-strings, and its messages
("is not a real YYYY-MM-DD date"); drop this branch's copy. Keep this
branch's evidenceDates (dates inside URLs ignored) and
latestAllowedDate. Both test suites pass together: 101 check and 296
lib assertions.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wc67NX9MM964uaVGn4bpZJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant