feat(about): signpost the "Is this Shariah law?" answer where a skeptic will find it (#90) - #94
Merged
Merged
Conversation
…ic will find it (#90) Closes #90. A Catholic friend of the maintainer opened a message with, in substance, "you prefer sharia, I oppose it" — friendly, well-disposed, and gone before anything explained what keel is. He is a representative reader, not an outlier. The site already wins this argument. `compliance.ts` → `framing` is titled "Is this 'Shariah law'?" and is good: it reframes the word doing the damage (*law* implies something imposed on others, while keel constrains one operator's own trading), it says no ruling is embedded in the software because the ruling is an input, and it notes the usury prohibition ran through Aquinas and the Third Lateran Council for a thousand years — "not a foreign import; a road not taken." That argument sits four scroll-lengths into a methodology page, behind a nav item a skeptical reader has no reason to open, after he has already decided. **This is placement, not content.** Nothing new is argued here. ### What changed - `CompliancePage.astro` — the framing section gains `id="is-this-shariah-law"` so it can be deep-linked, matching `id="from-source"` / `id="open-source"`. - `about.ts` — one FAQ item, all three locales, four sentences, linking to that anchor. Every substantive clause is a restatement of copy already shipped in `framing`. - `FaqItem` gains an optional `link {label, page, hash}`, and `AboutPage.astro` builds the href with `localePath`. Answers render as escaped plain text, and this repo never writes internal hrefs into copy files — `community.ts`, `compliance.ts` and `features.ts` all use structured link fields. Following that rather than injecting HTML or hardcoding three locale paths. ### Placed third, not first After the two existing "Is this…?" disambiguations, which are a matched pair about search-result collisions. That gives a run of three parallel questions ascending in importance, above the two longest items, so a scanner reaches it. Deliberately not first: leading the About FAQ with the objection reads as defensive, and prioritizes the skeptic over the audience keel is actually built for. #90 raises that trade-off; this is the answer to it. ### What is NOT claimed Not that keel is denomination-agnostic, works for any faith, or that another rule pack "would run on the same rails". That is **false today** — `keel/compliance/screen.py:33` is a hardcoded `frozenset` matched at `:334` with no config override anywhere. What is true, and all this says, is what the compliance page already said: the *ruling* is an operator input, so two operators of different schools get different results from identical code. The sector taxonomy is fixed in code. Rulings are pluggable; the vocabulary is not. A capability promise is the worst FR-9 violation because it is the hardest to walk back. Swept the diff for `denomination|any faith|catholic|usccb|agnostic|pack| configur` — zero hits in all three locales. ### Two stale comments, corrected `astro.config.mjs:7` and `src/i18n/config.ts:5` both still said "`fr` and `es` are reserved in routing but ship no pages until their phase." Wrong in both directions: `fr` ships the full page set, and `es` is not in `locales` at all. The second was found while fixing the first — same sentence, same defect, so both go together rather than leaving a known-false comment behind. ### Verification - `npm run check` — 0 errors, 0 warnings - `npm run build` — 56 pages, complete - Anchor renders in `dist/{en,ar,fr}/compliance/`; the FAQ link resolves to `/{locale}/compliance/#is-this-shariah-law` in all three - Zero `stale-banner` occurrences on any About page; all five FR-8 markers at `2026-08-26.1` Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
) Review nit, taken because it costs nothing and closes a silent failure. `hash?: string` accepted "is-this-shariah-law" without the leading `#`, which would have produced `/en/compliance/is-this-shariah-law` — a 404 that type-checks. `hash?: \`#\${string}\`` makes the compiler reject it. One call site today, so this is future-proofing rather than a fix. `npm run check` — 0 errors, 0 warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
|
eaitbrahim
added a commit
that referenced
this pull request
Aug 27, 2026
… to verify (#91) (#96) * fix(links): point the "verify this" links at the release they ask you to verify (#91) Closes #91. #85 pinned the docs pipeline to the latest published release tag. Hand-written links kept pointing at `main`, which is 17+ commits ahead of the newest tag. The serious half is `features.ts`. Each feature carries a "Verify in the repository" link — the mechanism by which this site asks to be checked rather than believed — and those landed on `keel/compliance/screen.py`, `keel/execution/guards.py` and `keel/agent.py` at `main`. A reader who takes the invitation was reading code that may not be in the release they run. That is worse than a broken link: a broken link announces itself, while a verification link that verifies the wrong thing does not. Not hypothetical for these exact files. `docs/operator-runbook.md` gained packaged-install text in keel `1d1799e`, on `main`, unreleased — so a v0.11.2 operator clicking "verify" read behaviour their build does not have. ### The scope was wider than the issue said Issue #91 listed the five component call sites and `features.ts`. It missed `compliance.ts`, which carries four links in each of three locales — twelve more, including `docs/fiqh-basis.md#scholarly-review-status`. That fragment is load-bearing: a helper that appended a path to a base URL would silently drop it and land the reader at the top of the document. ### One place the ref lives `src/lib/engine-url.ts` builds every engine URL from the ref in `data/docs-meta.json` — the one `scripts/fetch-engine-docs.mjs` resolved. Copy files carry a repo-relative `path` (plus optional `hash`), and the component builds the href, matching the convention `community.ts`, `compliance.ts`'s `links.items` and #94's `FaqItem.link` already follow. `grep -rn "blob/main" src/ | grep -v "src/content/"` returning nothing is now the lint that keeps it true. ### It fails the build rather than guessing `nav.ts`'s `FALLBACK_META` sets `ref: ""` — #92 made it empty precisely so a hard-coded branch could not become a false claim. `engineSourceUrl` throws when the ref is empty rather than emitting `blob//docs/...` or falling back to `main`, because a silent fallback restores exactly the skew this removes. Proven, not asserted: blanking `ref` in `data/docs-meta.json` makes `astro build` exit **1** with the message naming the path and the fix; restoring it exits **0**. ### FR-8: revs deliberately not bumped No translated prose changed — every `label` and `note` string is byte-identical, and only the href construction moved. #94's reviewer settled the same question for an `id` attribute: markup is not copy. The diff is 35 `href:` lines removed (33 links plus two type declarations) against 33 `path:` and 3 `hash:` lines added. ### Out of scope, deliberately `src/content/changelog/*.md` still contains `blob/main` links. That directory is gitignored and rewritten by `fetch-release.mjs` — those links are quotes from release notes as published, and the site must not rewrite what a release said. `docs/desktop-install.md` is pinned like the rest, but still walks a reader through downloading a `.dmg` v0.11.2 does not carry. That is #87. ### Verification - `npm run check` — 0 errors, 0 warnings - `npm run build` — `docs ref: v0.11.2`, 56 pages - `grep blob/main` in `src/` excluding `src/content/` — 0 - No `blob/main` in any built page outside the changelog - `#scholarly-review-status` resolves at `blob/v0.11.2/` - Verify links pinned in en, ar and fr - Empty ref → build exit 1; real ref → exit 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW * fix(links): make the "lint" real, and close the whitespace hole (#91) Independent review returned MERGE and confirmed the substance: all eleven pinned paths exist at v0.11.2, both fragments resolve to real headings, and a dist-vs-dist diff against main is exactly 154 hrefs removed and 154 added, 1:1, with the compliance and features pages byte-identical once the ref is substituted. Two findings were worth acting on. ### The PR claimed an enforcement that did not exist Both the PR body and `engine-url.ts`'s header said `grep blob/main` "is the lint that keeps it that way". It was not wired to CI, `npm run check`, or any script — it was a sentence. On a site with FR-9, claiming a guard that does not run is the wrong kind of wrong. Worse, the named pattern would not have caught two shapes this repo already contained before #91: `tree/main/packages` and `raw.githubusercontent.../keel/main/...`. So the sentence is now a program. `scripts/check-engine-refs.mjs` fails on any engine URL naming `main`, `master` or `HEAD` across `blob/`, `tree/`, `raw/` and raw.githubusercontent.com, run by `npm run check` and as its own CI step so the failure is legible in Checks. Proven by injecting all three shapes into `Footer.astro`: exit 1, all three reported by file and line; removed, exit 0. Two exceptions are allowlisted in the script with their reasons, not silently skipped: - `scripts/install.sh` — does not exist at v0.11.2 (`git cat-file -e` fails). It lives on the default branch only, so pinning it would turn the install page's primary command into a 404. - `src/content/` — fetched release-note prose whose links are quotes; rewriting them would edit what a release said. ### A whitespace ref shipped a malformed URL on a green build `if (!ref || !repo)` tested falsiness. A ref of `" "` passed it and produced `blob/ /keel/compliance/screen.py`. Reachable: `fetch-engine-docs.mjs:46` short-circuits on a hand-set manifest ref (`if (manifest.ref !== LATEST_RELEASE) return manifest.ref;`), returning it verbatim without `release-tag.mjs`'s `TAG_PATTERN` validation. Both values are trimmed before the guard now — a whitespace ref exits 1 like an empty one. ### Two corrections to the record `main` is 25 commits ahead of v0.11.2, not the "17+" the previous message said. `docs/desktop-install.md` is pinned like the rest, but the section containing it does not currently render at all — `InstallPage.astro:216` gates it behind `hasPlatformBundle`, and v0.11.2 ships none, so `grep -c desktop-install dist/en/install/index.html` is 0. The earlier note read as though that link were live to a reader today. It is not, which makes #87 the only thing standing between it and a reader. ### Verification - `npm run check` — 0 errors, 0 warnings (now runs the guard first) - `npm run build` — `docs ref: v0.11.2`, 56 pages - Guard: clean on HEAD; exit 1 on each injected shape - Empty ref exit 1, whitespace ref exit 1, real ref exit 0 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW --------- Co-authored-by: Claude Opus 5 (1M context) <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.



Closes #90.
A Catholic friend of the maintainer opened a message with, in substance, "you prefer sharia, I oppose it" — friendly, well-disposed, and gone before anything explained what keel is. A representative reader, not an outlier.
The site already wins this argument
compliance.ts→framingis titled "Is this 'Shariah law'?" and is good: it reframes the word doing the damage (law implies something imposed on others; keel constrains one operator's own trading), says no ruling is embedded because the ruling is an input, and notes the usury prohibition ran through Aquinas and the Third Lateran Council for a thousand years — "not a foreign import; a road not taken."That argument sits four scroll-lengths into a methodology page, behind a nav item a skeptic has no reason to open, after he has already decided.
This is placement, not content. Nothing new is argued.
Changes
CompliancePage.astroid="is-this-shariah-law", matchingid="from-source"/id="open-source"about.tsAboutPage.astrolink, href built withlocalePathastro.config.mjs,src/i18n/config.tsFaqItemgains an optionallink {label, page, hash}. Answers render as escaped plain text, and this repo never writes internal hrefs into copy files —community.ts,compliance.tsandfeatures.tsall use structured link fields. Following that rather than injecting HTML or hardcoding three locale paths.Placed third, not first
After the two existing "Is this…?" disambiguations, which are a matched pair about search-result collisions — giving a run of three parallel questions, above the two longest items.
Deliberately not first: leading the About FAQ with the objection reads as defensive and prioritizes the skeptic over the audience keel is built for. #90 raises that trade-off; this is the answer to it.
What is NOT claimed
Not that keel is denomination-agnostic, works for any faith, or that another rule pack "would run on the same rails". False today:
What is true — and all this says — is what the compliance page already said: the ruling is an operator input, so two operators of different schools get different results from identical code. The sector taxonomy is fixed. Rulings are pluggable; the vocabulary is not.
Swept the diff for
denomination|any faith|catholic|usccb|agnostic|pack|configur— zero hits across all three locales.Two stale comments
astro.config.mjs:7andsrc/i18n/config.ts:5both still said "frandesare reserved in routing but ship no pages until their phase." Wrong both ways:frships the full page set,esis not inlocalesat all. The second was found while fixing the first.Verification
npm run check— 0 errors, 0 warningsnpm run build— 56 pages, completedist/{en,ar,fr}/compliance/; FAQ link resolves in all threestale-banneroccurrences on any About page; all five FR-8 markers at2026-08-26.1Reviewer attention
framing's exact terminology and their questions are verbatim theframingtitles, so signpost and destination read as the same question. Worth a native check.FaqItem.linkis a new optional field — it applies toopenSourceFaqtoo, currently unused there.🤖 Generated with Claude Code
https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW