Commit Graph

9 Commits

Author SHA1 Message Date
Levi Neuwirth 7ca937d98c Fix audit HIGHs/MEDs in build code
- ArchiveIndex: guard rawIndex/rawState with doesFileExist so a fresh
  clone (gitignored data/ JSONs absent) degrades to empty instead of
  crashing — the behavior the module doc already promised (AUDIT §1.2)
- Commonplace: decode YAML via encodeUtf8, not Char8.pack, which
  truncates codepoints above 0x7F (AUDIT §3.2)
- Stats: DayOfWeek is ISO-numbered (Mon=1..Sun=7); dowOf and weekStart
  assumed Mon=0..Sun=6, clipping every Sunday cell outside the heatmap
  viewBox and starting weeks on Sunday (AUDIT §3.1)
- Site: epistemicEntry now honors the proved/proven confidence sentinel
  like Contexts.overallScoreField (AUDIT §2.6)
- Contexts: affiliationField returns noResult instead of an empty list,
  so essays without affiliation no longer render an empty meta row
  (AUDIT §2.7)

Verified: full site build passes; proved page gets score=100 in
epistemic-meta.json; empty .meta-affiliation gone; heatmap rows
y=22..94 all inside the 104-high viewBox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:21:30 -04:00
Levi Neuwirth 154b47a4cb Marks II: broader monogram coverage + audit-marks tool
Extends the Phase-1 monogram mark system to every long-form content
type (essays, blog posts, poems, fiction, music) and introduces a
coverage audit so gaps are visible.

* build/Marks.hs gains hasMonogram (predicate), monogramSvgFieldFor +
  hasMonogramFieldFor (for explicit-path callers like the /build/ and
  /stats/ pages). Contexts.hs exports hasMonogramField as a siteCtx
  boolean so templates can conditionally render the slot without
  emitting an empty <div>.
* essay.html, blog-post.html, reading.html: hoist the frontmatter
  block out of <main id="markdownBody"> so the monogram + epistemic
  marks render as wrapper chrome rather than indexable prose; left
  + right mark slots are now unconditional (CSS handles the empty
  state) so the layout is grid-stable across pieces.
* templates/partials/item-card.html: optional monogram chip on cards
  (item-card--has-monogram modifier), gated on $has-monogram$ so
  monogram-less pieces stay flush.
* build/Stats.hs grows a "Marks coverage" telemetry section: per-type
  pieces / monogram / epistemic-figure counts + a coverage rollup,
  rendered between epistemic and output on /build/.
* tools/audit-marks.py: coverage report (ASCII table) walking
  content/**/*.md, plus a pre-commit hook at
  tools/hooks/pre-commit-marks.sh that runs the same scan against
  newly-staged .md files. New `make audit-marks` runs the report
  manually; the hook gates commits.
* static/css/marks.css: layout for the new frontmatter slots and the
  item-card monogram chip.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 12:05:08 -04:00
Levi Neuwirth 77e31efdae Add link archive system: snapshots, backlinks, link-rot
Preserve external works the site cites against link rot, host them at
permanent /archive/<slug>/ URLs in site chrome, and treat them as
first-class citizens of the backlinks and similar-pages indexes.
Curated, not crawled: the author adds one line to archive/manifest.yaml
and the build fetches, hashes, snapshots, and indexes the work.

* archive/manifest.yaml + tools/archive.py (fetch / refresh / wayback /
  check / gc) — PDFs downloaded directly, HTML pages snapshotted with a
  vendored monolith (tools/bin/monolith @ 2.10.1) into a single
  self-contained file with the archive CSP and a noarchive robots meta
  injected. Per-entry PROVENANCE.json committed; gitignored .txt
  sidecars regenerated from the artifact's SHA-256.
* build/Archive.hs + build/ArchiveIndex.hs + build/Filters/Archive.hs
  — Hakyll rules for /archive/ and /archive/<slug>/, a body Pandoc
  filter that appends an archive affordance to live citations and
  flips dead ones to the local copy on archive.py check's asymmetric
  hysteresis (rotted needs 3 fails over >= 14 days; one ok recovers).
* build/Backlinks.hs — keeps archived external URLs through pass 1 and
  canonicalises them to /archive/<slug>/ in pass 2, producing a
  "Referenced by" section grouped by the fragment each citation
  targets. build/Stats.hs gains a "Link archive" telemetry block on
  /build/ (count, total size, median age, by-status / by-quality /
  by-visibility, orphans).
* Integrity: archive.py fetch and build/Archive.hs (via sha256sum)
  both re-hash every committed artifact, so a tampered file halts the
  build even with cabal invoked directly or no .venv present. refresh
  refuses to replace an uncommitted prior snapshot and rolls back
  atomically on any exit path. removed.yaml is honoured by fetch,
  wayback, and check using canonical-form (tracking-stripped,
  arXiv-canonicalised) comparison.
* visibility: private keeps an entry in-repo but undeployed.
  nginx/archive.conf emits X-Robots-Tag: noindex, noarchive for raw
  artifacts that cannot carry meta directives.

The full design, phase plan (1-5), and three refinement passes live
in ARCHIVE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 10:06:33 -04:00
Levi Neuwirth 725fa17f6a Tighten partial patterns and switch to strict file reads in build/
- Stats.hs: median uses (!!) directly after the empty-case equation,
  dropping the unreachable empty-fallback arm.
- Stats.hs + BibExtras.hs: switch lazy readFile to strict readFile'
  (System.IO). Lazy IO leaves handles open until the value is forced;
  errors surface at unpredictable points and the em-dash fallback in
  Stats can hide real I/O failures. Strict reads fail at the read.
- Stability.hs: stabilityFromDates uses 'last dates' directly, since
  the (newest:_) pattern guarantees non-empty input.
  versionHistoryRangeField and versionHistoryRangeEndField bind the
  matched list as 'es' and call 'last es', dropping the
  reconstruction of (newest : more) just to call last on it.
- Tags.hs: parentOf is a 3-arm case (\[\], \[_\], segs) instead of a
  length-based guard around 'init segs'.
- Catalog.hs: renderGroup re-orders so the structurally-guaranteed
  (e:_) arm is matched first; the empty arm stays as a coverage stub
  with a comment noting it's unreachable per groupBy's contract.
- Utils.hs: trim uses dropWhileEnd instead of double-reverse.

All sites were runtime-safe before; the changes make the safety
structural and shorter to read.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:08:47 -04:00
Levi Neuwirth 6585573dae States/Context/Embeddings fixes 2026-04-26 11:22:57 -04:00
Levi Neuwirth a358c8b246 audit: Haskell build system correctness + Patterns.hs + Stats blaze rewrite 2026-04-10 17:41:13 -04:00
Levi Neuwirth 9a3a5b62b6 type annotations for stats integers 2026-04-03 20:33:56 -04:00
Levi Neuwirth 728afd4c68 affiliation, cabal helper script 2026-03-26 08:14:50 -04:00
Levi Neuwirth 26c067147a Build telemetry 2026-03-19 15:27:12 -04:00