Compare commits

..

3 Commits

Author SHA1 Message Date
Levi Neuwirth d113671e96 epistemic redo 2026-04-11 19:40:58 -04:00
Levi Neuwirth b80fe2fee7 auto: 2026-04-11T23:21:47Z 2026-04-11 19:21:47 -04:00
Levi Neuwirth f7d972bf05 auto: 2026-04-11T23:09:55Z 2026-04-11 19:09:55 -04:00
9 changed files with 113 additions and 120 deletions

View File

@ -59,7 +59,7 @@ no-collapse: true # optional; disables collapsible h2/h3 sections
js: scripts/my-widget.js # optional; per-page JS file (see Page scripts) js: scripts/my-widget.js # optional; per-page JS file (see Page scripts)
# js: [scripts/a.js, scripts/b.js] # or a list # js: [scripts/a.js, scripts/b.js] # or a list
# Epistemic Effort — all optional; the entire section is hidden unless `status` is set # Epistemic profile — all optional; the entire section is hidden unless `status` is set
status: "Working model" # Draft | Working model | Durable | Refined | Superseded | Deprecated status: "Working model" # Draft | Working model | Durable | Refined | Superseded | Deprecated
confidence: 72 # 0100 integer (%) confidence: 72 # 0100 integer (%)
importance: 3 # 15 integer (rendered as filled/empty dots ●●●○○) importance: 3 # 15 integer (rendered as filled/empty dots ●●●○○)
@ -648,19 +648,26 @@ copies all JS files from `content/` to `_site/` automatically.
The epistemic footer section appears when `status` is set. All other fields The epistemic footer section appears when `status` is set. All other fields
are optional and are shown or hidden independently. are optional and are shown or hidden independently.
| Field | Compact display | Expanded (`<details>`) | | Field | Compact rows | Expanded `<dl>` |
|-------|----------------|------------------------| |-------|-------------|------------------|
| `status` | chip (always shown if present) | — | | *(trust score)* | bordered chip + small-caps "trust" label on the primary row | — |
| `confidence` | `72%` | — | | `status` | small-caps chip on the primary row, alongside the trust chip | — |
| `importance` | `●●●○○` | — | | `confidence` | `· 72% confidence` | — |
| `evidence` | `●●○○○` | — | | `importance` | `· ●●●○○ importance` | — |
| `evidence` | `· ●●○○○ evidence quality` | — |
| `scope` | `· average scope` (if set) | — |
| `novelty` | `· moderate novelty` (if set) | — |
| `practicality` | `· moderate practicality` (if set) | — |
| `stability` | — | auto-computed from git history | | `stability` | — | auto-computed from git history |
| `scope` | — | if set |
| `novelty` | — | if set |
| `practicality` | — | if set |
| `last-reviewed` | — | most recent commit date | | `last-reviewed` | — | most recent commit date |
| `confidence-trend` | — | ↑/↓/→ from last two `confidence-history` entries | | `confidence-trend` | — | ↑/↓/→ from last two `confidence-history` entries |
The **trust score** is auto-computed as `confidence × 0.6 + ((evidence 1) / 4) × 0.4`,
clamped 0100. It is deliberately narrow: it answers "how much should you trust the
central claim?" and nothing else. Importance, scope, novelty, and practicality are
*not* folded in — they are orientation signals shown alongside the chip so a high
trust score on a personal essay cannot be misread as broad significance.
**Stability** is auto-computed from `git log --follow` at every build. The **Stability** is auto-computed from `git log --follow` at every build. The
heuristic: ≤1 commits or age <14 days *volatile*; 5 commits and age <90 heuristic: ≤1 commits or age <14 days *volatile*; 5 commits and age <90
days → *revising*; ≤15 commits or age <365 days *fairly stable*; 30 days → *revising*; ≤15 commits or age <365 days *fairly stable*; 30

View File

@ -306,13 +306,25 @@ confidenceTrendField = field "confidence-trend" $ \item -> do
lastTwo [a, b] = Just (a, b) lastTwo [a, b] = Just (a, b)
lastTwo (_ : rest) = lastTwo rest lastTwo (_ : rest) = lastTwo rest
-- | @$overall-score$@: weighted composite of confidence (50 %), -- | @$overall-score$@: weighted composite of confidence (60 %) and
-- evidence quality (30 %), and importance (20 %), expressed as an -- evidence quality (40 %), expressed as an integer on a 0100 scale.
-- integer on a 0100 scale. --
-- Returns @noResult@ when any contributing field is absent, so -- Importance is intentionally excluded from the score: it answers
-- "should you read this?", not "should you trust it?", and folding
-- the two together inflated the number and muddied its meaning.
-- It still appears in the footer as an independent orientation
-- signal — just not as a credibility input.
--
-- The 15 evidence scale is rescaled as @(ev 1) / 4@ rather than
-- plain @ev / 5@. The naive form left a hidden +6 floor (since
-- @1/5 = 0.2@) and a midpoint of 0.6 instead of 0.5; the rescale
-- makes evidence=1 contribute zero and evidence=3 contribute exactly
-- half, so a "true midpoint" entry (conf=50, ev=3) lands on 50.
--
-- Returns @noResult@ when confidence or evidence is absent, so
-- @$if(overall-score)$@ guards the template safely. -- @$if(overall-score)$@ guards the template safely.
-- --
-- Formula: raw = conf/100·0.5 + ev/5·0.3 + imp/5·0.2 (01) -- Formula: raw = conf/100 · 0.6 + (ev 1)/4 · 0.4 (01)
-- score = clamp₀₋₁₀₀(round(raw · 100)) -- score = clamp₀₋₁₀₀(round(raw · 100))
overallScoreField :: Context String overallScoreField :: Context String
overallScoreField = field "overall-score" $ \item -> do overallScoreField = field "overall-score" $ \item -> do
@ -320,16 +332,14 @@ overallScoreField = field "overall-score" $ \item -> do
let readInt s = readMaybe s :: Maybe Int let readInt s = readMaybe s :: Maybe Int
case ( readInt =<< lookupString "confidence" meta case ( readInt =<< lookupString "confidence" meta
, readInt =<< lookupString "evidence" meta , readInt =<< lookupString "evidence" meta
, readInt =<< lookupString "importance" meta
) of ) of
(Just conf, Just ev, Just imp) -> (Just conf, Just ev) ->
let raw :: Double let raw :: Double
raw = fromIntegral conf / 100.0 * 0.5 raw = fromIntegral conf / 100.0 * 0.6
+ fromIntegral ev / 5.0 * 0.3 + fromIntegral (ev - 1) / 4.0 * 0.4
+ fromIntegral imp / 5.0 * 0.2
score = max 0 (min 100 (round (raw * 100.0) :: Int)) score = max 0 (min 100 (round (raw * 100.0) :: Int))
in return (show score) in return (show score)
_ -> fail "overall-score: confidence, evidence, or importance not set" _ -> fail "overall-score: confidence or evidence not set"
-- | All epistemic context fields composed. -- | All epistemic context fields composed.
epistemicCtx :: Context String epistemicCtx :: Context String

View File

@ -134,9 +134,9 @@ Every essay and post on this site carries an **epistemic footer** — a structur
- **Evidence** — how well-evidenced the claims are, on the same 15 scale. An essay with high importance and low evidence is a speculative position and should be read accordingly. - **Evidence** — how well-evidenced the claims are, on the same 15 scale. An essay with high importance and low evidence is a speculative position and should be read accordingly.
- **Overall score** — a single 0100 integer derived automatically from the three quantitative fields above: confidence weighted at 50%, evidence at 30%, importance at 20%. It appears adjacent to the Epistemic link in the top metadata row and is not entered manually. - **Trust score** — a single 0100 integer derived automatically from confidence (weighted 60%) and evidence (weighted 40%, with the 15 scale rescaled so that evidence=1 contributes zero and evidence=5 contributes the full 40 points). It is deliberately *narrow*: it answers "how much should you trust the central claim?" and nothing else. It says nothing about how broadly the work matters, how novel it is, or how useful it is in practice — those are separate axes (see below) that are deliberately *not* folded into a composite, so a high trust score on a personal essay cannot be misread as "world-shaking." Following Gwern's lead, the orientations are presented in parallel rather than blended into a single index. The score is not entered manually and lives only in the epistemic footer.
- **Scope**, **Novelty**, **Practicality** — optional qualitative fields in the expanded footer. *Scope* ranges from *personal* to *civilizational*; *novelty* from *conventional* to *innovative*; *practicality* from *abstract* to *exceptional*. These are not ratings — they are orientations. - **Scope**, **Novelty**, **Practicality** — orientation fields shown as their own rows in the epistemic footer alongside confidence, importance, and evidence. *Scope* ranges from *personal* to *civilizational*; *novelty* from *conventional* to *innovative*; *practicality* from *abstract* to *exceptional*. These are not ratings — they are orientations, and they intentionally do not feed the trust score.
- **Stability** — auto-computed at every build from `git log --follow`. The heuristic: very new or barely-touched documents are *volatile*; actively-revised documents are *revising*; older documents with more commits settle into *fairly stable*, *stable*, or *established*. This requires no manual maintenance — the build reads the repository history and makes the inference. - **Stability** — auto-computed at every build from `git log --follow`. The heuristic: very new or barely-touched documents are *volatile*; actively-revised documents are *revising*; older documents with more commits settle into *fairly stable*, *stable*, or *established*. This requires no manual maintenance — the build reads the repository history and makes the inference.

View File

@ -145,7 +145,7 @@ Auto-derived at build time: `stability` (from `git log --follow`), `last-reviewe
**Bottom metadata footer:** **Bottom metadata footer:**
- **Version history** — three-tier priority: (1) frontmatter `history` list with authored notes → (2) git log dates (date-only) → (3) `date-created` / `date-modified` fallback. `make build` auto-commits `content/` before building, keeping git history current. - **Version history** — three-tier priority: (1) frontmatter `history` list with authored notes → (2) git log dates (date-only) → (3) `date-created` / `date-modified` fallback. `make build` auto-commits `content/` before building, keeping git history current.
- **Epistemic** (if `status` set) — compact: status chip · confidence % · importance dots · evidence dots; expanded `<details>`: stability · scope · novelty · practicality · last reviewed · confidence trend - **Epistemic** (if `status` set) — primary row: trust-score chip + status; labeled rows beneath: confidence · importance · evidence · scope · novelty · practicality (each shown only if its frontmatter field is set); always-visible `<dl>`: stability · last reviewed · confidence trend
- **Bibliography** — formatted citations + Further Reading - **Bibliography** — formatted citations + Further Reading
- **Backlinks** — auto-generated; each entry shows source title (link) + collapsible context paragraph - **Backlinks** — auto-generated; each entry shows source title (link) + collapsible context paragraph
@ -648,6 +648,7 @@ Implemented across `build/Stability.hs`, `build/Contexts.hs`, `templates/partial
| `$confidence$` | frontmatter `confidence` | via `defaultContext` | | `$confidence$` | frontmatter `confidence` | via `defaultContext` |
| `$importance-dots$` | frontmatter `importance` (15) | `●●●○○` rendered in Haskell | | `$importance-dots$` | frontmatter `importance` (15) | `●●●○○` rendered in Haskell |
| `$evidence-dots$` | frontmatter `evidence` (15) | same | | `$evidence-dots$` | frontmatter `evidence` (15) | same |
| `$overall-score$` | computed from `confidence` + `evidence` | trust score: `conf/100 · 0.6 + (ev1)/4 · 0.4`, clamped 0100. Importance/scope/novelty/practicality intentionally excluded — see colophon "Living Documents" for the rationale. |
| `$confidence-trend$` | frontmatter `confidence-history` list | ↑ / ↓ / → from last two entries | | `$confidence-trend$` | frontmatter `confidence-history` list | ↑ / ↓ / → from last two entries |
| `$stability$` | auto-computed via `git log --follow` | always resolves; never fails | | `$stability$` | auto-computed via `git log --follow` | always resolves; never fails |
| `$last-reviewed$` | most recent commit date | formatted "%-d %B %Y"; `noResult` if no commits | | `$last-reviewed$` | most recent commit date | formatted "%-d %B %Y"; `noResult` if no commits |

View File

@ -627,15 +627,6 @@ nav.site-nav {
text-decoration: underline; text-decoration: underline;
text-underline-offset: 2px; text-underline-offset: 2px;
} }
/* When the score box is present, suppress the link-level underline and
restore it only on the label text leaves the gap and box undecorated. */
.meta-pagelinks a:has(.meta-overall-score):hover {
text-decoration: none;
}
.meta-pagelinks a:has(.meta-overall-score):hover .ep-link-label {
text-decoration: underline;
text-underline-offset: 2px;
}
.meta-pagelinks a + a::before { .meta-pagelinks a + a::before {
content: " · "; content: " · ";
color: var(--border); color: var(--border);
@ -644,6 +635,19 @@ nav.site-nav {
white-space: pre; white-space: pre;
} }
/* Top-of-page parallel tag strip surfaces the full epistemic profile
inline so a reader sees status, trust score, and every orientation
axis at a glance, without scrolling to the footer. The trust chip
anchors the left edge; status sits next to it; the labeled rows
follow with their leading centerdot separators. Wraps freely. */
.meta-epistemic-strip {
display: flex;
flex-wrap: wrap;
align-items: baseline;
justify-content: center;
gap: 0.35rem 0.55rem;
}
/* ============================================================ /* ============================================================
BOTTOM METADATA FOOTER BOTTOM METADATA FOOTER
@ -808,15 +812,6 @@ details[open] > .backlink-summary::before {
with an expandable <details> for the full profile. with an expandable <details> for the full profile.
============================================================ */ ============================================================ */
/* Compact row — chips laid out inline */
.ep-compact {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.35rem 0.55rem;
margin-bottom: 0.5rem;
}
/* Status chip */ /* Status chip */
.ep-status { .ep-status {
font-family: var(--font-sans); font-family: var(--font-sans);
@ -826,15 +821,18 @@ details[open] > .backlink-summary::before {
color: var(--text-muted); color: var(--text-muted);
} }
/* Confidence percentage */ /* Every labeled row beneath the primary line shares one class so new
.ep-confidence { epistemic fields can be added in the template without touching CSS.
Used by confidence, importance, evidence, scope, novelty, practicality. */
.ep-row {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 0.72rem; font-size: 0.72rem;
color: var(--text-faint); color: var(--text-faint);
} }
.ep-confidence::before { content: "·\00a0"; color: var(--border); } .ep-row::before { content: "·\00a0"; color: var(--border); }
/* Dot scale (importance / evidence) */ /* Dot scale (importance / evidence) only ever used nested inside an
.ep-row wrapper, which already supplies the centerdot separator. */
.ep-dots { .ep-dots {
font-size: 0.55rem; font-size: 0.55rem;
letter-spacing: 0.12em; letter-spacing: 0.12em;
@ -842,34 +840,30 @@ details[open] > .backlink-summary::before {
line-height: 1; line-height: 1;
vertical-align: 0.15em; vertical-align: 0.15em;
} }
.ep-dots::before { content: "·\00a0"; color: var(--border); font-size: 0.72rem; vertical-align: 0; } .ep-row .ep-dots::before { content: none; }
/* Expandable detail block */ /* Trust chip on the primary row bordered numeric chip plus a small-caps
.ep-details { "trust" label, mirroring .ep-status typography so the two sit together. */
margin-top: 0.1rem; .ep-trust {
}
.ep-summary {
font-size: 0.68rem;
font-family: var(--font-sans); font-family: var(--font-sans);
color: var(--text-faint); font-size: 0.72rem;
cursor: pointer; font-variant-caps: all-small-caps;
list-style: none; letter-spacing: 0.05em;
user-select: none; color: var(--text-muted);
} }
.ep-score {
.ep-summary::-webkit-details-marker { display: none; } font-family: var(--font-sans);
font-size: 0.72rem;
.ep-summary::before { font-variant-caps: normal;
content: "▸\00a0"; font-variant-numeric: tabular-nums;
font-size: 0.6em; letter-spacing: 0.03em;
vertical-align: 0.1em; color: var(--text-muted);
border: 1px solid var(--border-muted);
border-radius: 2px;
padding: 0.05em 0.5em;
margin-right: 0.25em;
} }
details[open] > .ep-summary::before { content: "▾\00a0"; }
.ep-summary:hover { color: var(--text-muted); }
/* Definition list for expanded profile */ /* Definition list for expanded profile */
.ep-expanded { .ep-expanded {
display: grid; display: grid;
@ -894,24 +888,6 @@ details[open] > .ep-summary::before { content: "▾\00a0"; }
} }
/* Overall score percentage in the top metadata nav (adjacent to Epistemic link).
Renders as a compact numeric chip: "72%" in small-caps sans, separated from
the link text by a faint centerdot. */
.meta-overall-score {
font-family: var(--font-sans);
font-size: 0.68rem;
font-variant-numeric: tabular-nums;
letter-spacing: 0.03em;
color: var(--text-muted);
display: inline-block;
text-decoration: none;
border: 1px solid var(--border-muted);
border-radius: 2px;
padding: 0.05em 0.5em;
margin-left: 0.5em;
vertical-align: 0.05em;
}
/* ============================================================ /* ============================================================
PAGINATION NAV PAGINATION NAV
============================================================ */ ============================================================ */

View File

@ -641,9 +641,12 @@
return html; return html;
} }
/* Epistemic jump link reads the #epistemic section already in the DOM /* Epistemic jump link pulls the parallel-tag strip from the top of
and renders a compact summary: status/confidence/dots + expanded DL. the page (which holds the author-declared orientation tags) and
All ep-* classes are already styled via components.css. the expanded DL from the #epistemic footer section (which holds
the git-derived stability/last-reviewed/trend). The popup combines
both so a reader hovering the link mid-page sees the full profile
without scrolling.
Returns a DocumentFragment instead of an HTML string so the popup Returns a DocumentFragment instead of an HTML string so the popup
receives cloned nodes (defense in depth if a future change ever receives cloned nodes (defense in depth if a future change ever
@ -651,25 +654,21 @@
would still see exactly the same already-rendered DOM rather than would still see exactly the same already-rendered DOM rather than
a re-parsed string). */ a re-parsed string). */
function epistemicContent() { function epistemicContent() {
var section = document.getElementById('epistemic');
if (!section) return Promise.resolve(null);
var wrap = document.createElement('div'); var wrap = document.createElement('div');
wrap.className = 'popup-epistemic'; wrap.className = 'popup-epistemic';
var compact = section.querySelector('.ep-compact'); var strip = document.querySelector('.meta-epistemic-strip');
if (compact) { if (strip) {
var compactClone = compact.cloneNode(true); wrap.appendChild(strip.cloneNode(true));
wrap.appendChild(compactClone);
} }
var expanded = section.querySelector('.ep-expanded'); var section = document.getElementById('epistemic');
var expanded = section ? section.querySelector('.ep-expanded') : null;
if (expanded) { if (expanded) {
var expandedClone = expanded.cloneNode(true); wrap.appendChild(expanded.cloneNode(true));
wrap.appendChild(expandedClone);
} }
if (!compact && !expanded) return Promise.resolve(null); if (!strip && !expanded) return Promise.resolve(null);
return Promise.resolve(wrap); return Promise.resolve(wrap);
} }

View File

@ -7,7 +7,7 @@
<div class="library-controls-options" role="group" aria-label="Sort order"> <div class="library-controls-options" role="group" aria-label="Sort order">
<button class="library-sort-btn" data-sort="date">date</button> <button class="library-sort-btn" data-sort="date">date</button>
<button class="library-sort-btn" data-sort="title">title</button> <button class="library-sort-btn" data-sort="title">title</button>
<button class="library-sort-btn" data-sort="score">epistemic effort</button> <button class="library-sort-btn" data-sort="score">trust</button>
</div> </div>
</div> </div>

View File

@ -17,9 +17,21 @@
$for(affiliation-links)$$if(affiliation-url)$<a href="$affiliation-url$">$affiliation-name$</a>$else$$affiliation-name$$endif$$sep$ · $endfor$ $for(affiliation-links)$$if(affiliation-url)$<a href="$affiliation-url$">$affiliation-name$</a>$else$$affiliation-name$$endif$$sep$ · $endfor$
</div> </div>
$endif$ $endif$
$if(status)$
<div class="meta-row meta-epistemic-strip" data-pagefind-ignore="all">
$if(overall-score)$<span class="ep-trust" title="Trust score: $overall-score$/100 (confidence × 0.6 + evidence × 0.4)"><span class="ep-score">$overall-score$%</span> trust</span>$endif$
<span class="ep-status">$status$</span>
$if(confidence)$<span class="ep-row" title="Confidence">$confidence$% confidence</span>$endif$
$if(importance-dots)$<span class="ep-row" title="Importance: $importance$/5"><span class="ep-dots">$importance-dots$</span> importance</span>$endif$
$if(evidence-dots)$<span class="ep-row" title="Evidence quality: $evidence$/5"><span class="ep-dots">$evidence-dots$</span> evidence quality</span>$endif$
$if(scope)$<span class="ep-row" title="Scope">$scope$ scope</span>$endif$
$if(novelty)$<span class="ep-row" title="Novelty">$novelty$ novelty</span>$endif$
$if(practicality)$<span class="ep-row" title="Practicality">$practicality$ practicality</span>$endif$
</div>
$endif$
<nav class="meta-row meta-pagelinks" aria-label="Page sections"> <nav class="meta-row meta-pagelinks" aria-label="Page sections">
<a href="#version-history">History</a> <a href="#version-history">History</a>
$if(status)$<a href="#epistemic">$if(overall-score)$<span class="ep-link-label">Epistemic</span><span class="meta-overall-score" title="Overall score: $overall-score$/100">$overall-score$%</span>$else$Epistemic$endif$</a>$endif$ $if(status)$<a href="#epistemic">Epistemic</a>$endif$
$if(bibliography)$<a href="#bibliography">Bibliography</a>$endif$ $if(bibliography)$<a href="#bibliography">Bibliography</a>$endif$
$if(backlinks)$<a href="#backlinks">Backlinks</a>$endif$ $if(backlinks)$<a href="#backlinks">Backlinks</a>$endif$
$if(repository)$<a href="$repository$">Repository</a>$endif$ $if(repository)$<a href="$repository$">Repository</a>$endif$

View File

@ -35,23 +35,11 @@
$if(status)$ $if(status)$
<div class="meta-footer-section meta-footer-epistemic" id="epistemic"> <div class="meta-footer-section meta-footer-epistemic" id="epistemic">
<h3><a href="/colophon.html#living-documents">Epistemic</a></h3> <h3><a href="/colophon.html#living-documents">Epistemic</a></h3>
<div class="ep-compact">
<span class="ep-status">$status$</span>
$if(confidence)$<span class="ep-confidence" title="Confidence">$confidence$%</span>$endif$
$if(importance-dots)$<span class="ep-dots" title="Importance: $importance$/5">$importance-dots$</span>$endif$
$if(evidence-dots)$<span class="ep-dots" title="Evidence quality: $evidence$/5">$evidence-dots$</span>$endif$
</div>
<details class="ep-details">
<summary class="ep-summary">detail</summary>
<dl class="ep-expanded"> <dl class="ep-expanded">
<dt>Stability</dt><dd>$stability$</dd> <dt>Stability</dt><dd>$stability$</dd>
$if(scope)$<dt>Scope</dt><dd>$scope$</dd>$endif$
$if(novelty)$<dt>Novelty</dt><dd>$novelty$</dd>$endif$
$if(practicality)$<dt>Practicality</dt><dd>$practicality$</dd>$endif$
$if(last-reviewed)$<dt>Last reviewed</dt><dd>$last-reviewed$</dd>$endif$ $if(last-reviewed)$<dt>Last reviewed</dt><dd>$last-reviewed$</dd>$endif$
$if(confidence-trend)$<dt>Confidence trend</dt><dd>$confidence-trend$</dd>$endif$ $if(confidence-trend)$<dt>Confidence trend</dt><dd>$confidence-trend$</dd>$endif$
</dl> </dl>
</details>
</div> </div>
$endif$ $endif$