Skip to content

feat(about): signpost the "Is this Shariah law?" answer where a skeptic will find it (#90) - #94

Merged
eaitbrahim merged 2 commits into
mainfrom
feat/shariah-framing-90
Aug 27, 2026
Merged

feat(about): signpost the "Is this Shariah law?" answer where a skeptic will find it (#90)#94
eaitbrahim merged 2 commits into
mainfrom
feat/shariah-framing-90

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

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.tsframing is 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

File Why
CompliancePage.astro framing section gains id="is-this-shariah-law", matching id="from-source" / id="open-source"
about.ts one FAQ item, three locales, four sentences, linking to that anchor
AboutPage.astro renders an optional link, href built with localePath
astro.config.mjs, src/i18n/config.ts two stale comments corrected

FaqItem gains an optional link {label, page, hash}. 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 — 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:

# keel/compliance/screen.py:33 — hardcoded, matched at :334, no config override
HARAM_SECTORS = frozenset({"gambling","casino","adult","alcohol",
                           "pork","tobacco","firearms","riba_yield"})

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|configurzero hits across all three locales.

Two stale comments

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 both ways: fr ships the full page set, es is not in locales at all. The second was found while fixing the first.

Verification

  • npm run check0 errors, 0 warnings
  • npm run build56 pages, complete
  • Anchor renders in dist/{en,ar,fr}/compliance/; FAQ link resolves in all three
  • Zero stale-banner occurrences on any About page; all five FR-8 markers at 2026-08-26.1

Reviewer attention

  1. Is third the right slot, or should it lead? The counter-argument is in the PR body and in The homepage says "Shariah" three times before the page that explains what that means #90 — I came down on "not defensive", but it is a judgment call about audience.
  2. Arabic and French reuse framing's exact terminology and their questions are verbatim the framing titles, so signpost and destination read as the same question. Worth a native check.
  3. FaqItem.link is a new optional field — it applies to openSourceFaq too, currently unused there.

🤖 Generated with Claude Code

https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW

eaitbrahim and others added 2 commits August 26, 2026 20:14
…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
@sonarqubecloud

Copy link
Copy Markdown

@eaitbrahim
eaitbrahim merged commit 782d8f5 into main Aug 27, 2026
2 checks passed
@eaitbrahim
eaitbrahim deleted the feat/shariah-framing-90 branch August 27, 2026 00:20
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>
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.

The homepage says "Shariah" three times before the page that explains what that means

1 participant