docs(readme): cut the ungated duplicate reference, fix what had drifted in it (#111)
The README was 787 lines, roughly 400 restating material the documentation
site generates. That copy had already drifted, which is the argument for
deleting it rather than re-typing it: it claimed a stock configuration writes
four firewall rules when it writes eight, credited an unban with a ~2 ms API
call that measured 1,155 ms against 22,000 entries before the id cache, and was
missing 22 config keys. The 72 defaults it did publish were all still correct -
checked against the generated schema - which is the point: nothing was keeping
them that way.
What stays is what gets someone from zero to a running bouncer, with every row
of the settings table verified against config-schema.json. 787 -> 416 lines.
Go Report Card removed: the service shut down 2026-07-01 and serves a badge
reading 'go report: retired'. Replaced with OpenSSF Scorecard, plus release and
downloads badges, all three confirmed rendering before being added.
repo-stats.mjs parsed the deleted benchmark table to feed the landing page; it
now reads the same figure from the benchmarking page, which states the hardware
and list size it was measured on.
Review fixes: corrected a claim that both the config reference and the rule
listing were CI-gated (only the first is; the second is single-sourced but
hand-maintained), documented that the metrics endpoints are unauthenticated on
0.0.0.0 by default, replaced a hard-coded version in the health example, and
pinned the Scorecard workflow's actions to SHAs since it is the one workflow
holding id-token: write.
feat(docs): new brand mark, CrowdSec indigo, four diagrams, and the i18n gate on the MDX AST (#95)
## Description
Phases 5 to 7 of the documentation plan, plus the technical debt that
had accumulated in the i18n gate, plus a new brand mark chosen from
twenty-nine candidates.
## Type of change
- [x] ✨ New feature (non-breaking change that adds functionality)
- [x] 📖 Documentation update
- [x] 🧪 Tests / tooling / CI
- [x] 🧹 Refactoring / code cleanup
## Changes
### The i18n parity gate is rewritten onto the MDX AST
It had produced **three defects in one area** — an HTML-comment
terminator that missed `--!>`, a chained-replace sanitisation that left
a bare `<!--` behind, and a one-character backtick delimiter that leaked
double-backtick spans. Two were found by CodeQL, one in review. Three
findings in one file say the approach is wrong, not that the patches
were bad; parsing makes those classes unreachable.
All four parser packages were **already resolved in the lockfile**, so
declaring them added nothing to install.
Verified by a **differential harness over all 56 corpus files across six
dimensions**, which caught a regression the rewrite introduced and
surfaced a genuine improvement: three multi-path `ConfigOption`
invocations that used to collapse into one indistinguishable bucket are
now keyed individually. Demonstrated: a Spanish page pointing at a
non-existent config path **passed** the old gate and fails the new one.
It also corrected a claim the old file asserted: an HTML comment closed
with `--!>` is **not** closed for the renderer. CommonMark ends an HTML
block only at `-->`, so the earlier "fix" was wrong in the other
direction.
### A new mark
The shield is gone. Rendered side by side at the sizes that matter it
was, unmistakably, **the WiFi glyph** — a shield containing concentric
arcs radiating from a dot is the standard signal icon at 104px and at
23px. Nobody noticed until the candidates were laid out and looked at.
For a network tool that is worse than generic; it is misleading.
What replaces it: four lanes meeting a rail, three crossing and
continuing, one stopping dead at it. The proportion is deliberate — a
firewall does not block everything, it blocks the exception. **Three
primitives, 282 bytes of geometry, no ids, no defs, no mask**, against
the 3.8 KB the shield needed.
Chosen from 29 candidates across two waves. The first wave's five
directions all came from the data side — list, chain, loop, flow — and
its winner drew a generic list; the siblings anchor on a git ref and an
open book, objects that only exist in their domains. The second wave
entered through the domain and beat it on all four judging lenses.
### The accent moves to CrowdSec's indigo
`#4d4a98` light, `#807dc0` dark — the same hue and saturation raised
until it clears 4.5:1 against the **surface** rather than merely the
page. The page-only value failed twice, on the terminal prompt glyph and
the sidebar pill, and the contrast gate caught both.
This is ecosystem alignment, not a return to the co-branding retired
earlier: that palette paired CrowdSec indigo *with* MikroTik teal,
implying endorsement by two vendors including the hardware one. This is
a CrowdSec bouncer, listed on their Hub. **Worth checking their brand
guidelines before a release goes out.**
The rail takes the accent because the boundary is what the product is.
Pass and stop are carried by **length before colour**: the accent and
the muted tone measure 1.19:1 apart, so a mark relying on that pair to
tell them apart would come very close to collapsing into one tone in
greyscale.
CrowdSec's amber moves to `--rb-status-warn`, where it does semantic
work rather than decorating.
### Four architecture diagrams, under one convention
The rule-placement ladder, the decision funnel in three swimlanes, the
reconciliation diff and the shutdown order. Solid is a write, dashed is
a read, carried on three channels — line pattern, then colour, then a
legend inside each diagram — so they survive greyscale, colour vision
deficiency and a printout.
Six accuracy defects in them were corrected against the Go source. One
claim was rewritten rather than deleted: entries whose comment does not
match the prefix were described as "never listed", but `ListAddresses`
queries on the list name alone and filters client-side, so they **are**
fetched every pass and only then dropped — which costs transfer on a
list an operator may be sharing.
### Navigation
Sidebar depth hierarchy, pagination that names its destination (two
entries were both labelled "Overview"), scroll-into-view, and a **mobile
theme toggle** — there was none, the header hid the control below 50rem.
It never writes `data-theme` or `localStorage` itself: it drives
Starlight's own select and reads state back via a MutationObserver,
because anything else desynchronises from the desktop control and the
before-paint script.
## Testing
- [x] `pnpm analyze` exits 0 — config schema check, brand raster check,
i18n parity, contrast, `astro check`, ESLint, Prettier, build,
`html-validate`
- [x] `go build ./...`, `go test -race ./...`, golangci-lint, gosec,
staticcheck, govulncheck all clean; markdownlint clean
- [x] Every gate mutation-tested in both directions, including the
parity gate's twelve behaviours and the new brand-raster check
- [x] Rendered SVGs inspected in `dist/` — all 62 diagram edges parse,
dashed edges carry a real `stroke-dasharray`, and the mermaid CSS
ordering was checked so the dotted class actually wins
- [ ] Tested against a real MikroTik router (not applicable — no
behavioural change ships here)
## Notes for review
Four claims **of my own** were wrong and are corrected in the last
commit: a stale contrast figure in all three copies of the mark, the
`prefers-contrast` block still pointing at the retired teal, a comment
describing lanes "cut by the rail" that are unbroken rectangles, and a
false provenance claim about the sibling status fills' saturation.
An intermittent `analyze` failure reported by three agents did not
reproduce — 8 clean builds out of 8 in isolation. The cause was
concurrent agents building into the same `dist/`.
https://claude.ai/code/session_01ENguejGi5gZcxoMbCKWFBy
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/95?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Introduced refreshed CrowdSec Indigo branding across the documentation
site, including responsive wordmark, icons, and social images.
* Added light/dark theme support for diagrams and documentation images.
* Added mobile theme switching and improved sidebar, header, pagination,
and navigation behavior.
* Added clearer architecture diagrams, flow explanations, and Grafana
dashboard imagery.
* **Documentation**
* Expanded English and Spanish guidance for decision filtering,
firewall-rule placement, reconciliation, shutdown behavior, and decision
lifecycles.
* Clarified read/write diagram conventions and operational edge cases.
* **Bug Fixes**
* Improved validation for localized documentation structure and
generated brand assets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->