fix(docs): the chunk sweep resolved nothing, and the write-up said otherwise (#110)
Two review findings on #109, both valid.
The chunk sweep reported the best of three interleaved rounds per size and
fitted a two-term cost model to those five points. Re-run with five rounds and
every sample retained, the interquartile range within a single chunk size
reaches 2.55s while the entire spread between sizes is 1.43s - the noise on one
arm is larger than the difference between arms, so the sweep resolves nothing,
and which size wins depends on the estimator (median and minimum pick 1000, the
mean picks 100). The per-entry coefficient survives at ~1.2-1.3 ms because it
dominates; the per-chunk term lands anywhere from ~1 to ~10 ms, which is 0.2s to
2.3s of scaffolding on a 22,000-entry import rather than the 0.23s published.
The conclusion is unchanged and never rested on the ranking - 100 stays - but it
now carries its uncertainty, in the code comment and both pages that repeated
it. The benchmarking page uses the episode to show why a single number without a
spread hides whether a comparison means anything.
Separately, a figure measured on RouterOS 7.24.1 with 22,857 entries had been
written into a table headed RouterOS 7.22.1 with ~28,700 IPs. The historical
table is restored intact and the current measurement gets its own, with its own
conditions.
Both locales; parity gate green.
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.
Prepare 1.4.0 tooling and review follow-ups (#24)
Prepare the 1.4.0 branch with dependency/tooling updates, docs validation, release metadata, and follow-up review fixes.
Summary:
- Add and document periodic reconciliation behavior, release references, and refreshed docs/tooling validation.
- Modernize Go and docs tooling, including static analysis, pnpm checks, GoReleaser, and workflow gating.
- Address review feedback across RouterOS error handling, metrics, config expansion, functional scripts, docs, templates, and CI.
fix(docs): the retired favicon, a broken home-page card, and a 1.61:1 print border — each with the gate that missed it (#96)
Closes the loose ends left over from the phase-5 work, plus the two
workstreams
that were still outstanding (W13 per-page OG cards, W14 icon/manifest
hygiene).
Three of the five things fixed here were **shipped defects nobody could
have
caught**, because in each case the pipeline had no check that joined the
two
halves involved. Each is now closed by a gate as well as by the fix.
### `favicon.ico` was the retired shield
Every icon is rendered from `logo-light.svg` — except the `.ico`, which
was last
written by the *July* logo redesign and carried the
shield-with-WiFi-arcs
through the whole mark change. It is the one asset the author never
looks at,
and the one Google's SERP fetcher and older Safari prefer.
Now packed from the same PNGs as everything else, at 16/32/48. Written
by hand:
sharp cannot encode ICO and an ImageMagick dependency would not survive
CI. The
container is a 6-byte header and one 16-byte entry per image. 15,086
bytes → 553.
### The home page's social card 404'd
The card URL is assembled in two places holding different ids for the
same page
— the endpoint reads the content collection, which calls the English
home page
`index`; the `Head` override sees Starlight's route, whose id for it is
empty.
They agreed on 55 pages and disagreed on the one most links point at,
which
shipped as `og/.png`. Starlight also synthesises a 404 route with an
entry and
no collection page behind it, so that page pointed at a card nothing
rendered.
Both now resolve through one `cardPath`, and membership in the
collection — not
the presence of an entry — decides whether a page has a card.
**`check-social-cards.mjs`
reads every `og:image` out of the rendered HTML and asks the filesystem
whether
it is there.** It found the 404 defect within a second of being written.
### The print stylesheet shipped a 1.61:1 boundary
`@media print` was exempt from the contrast gate because "paper is one
background and the palette does not reach it". The first half is true;
the
second does not follow. Browsers do not print background colours by
default, so
on paper the `pre` border is the only thing separating a code block from
the
prose around it — a graphical object required to understand the content,
so
1.4.11 applies. `#ccc` → `#8a8a8a`, 1.61:1 → 3.45:1.
### Also
- **A social card per page** (W13) — 56 pages shared one banner. Text is
set in
the mono face the site already uses, which makes wrapping exact
arithmetic
rather than a guess, since librsvg does not measure text.
- **The i18n gate invented one mismatch and missed two** — `path="a.b"`
vs
`path={"a.b"}` keyed apart (the self-test asserted this, so the bug was
pinned
by its own suite); `<Home section />` and `<Home />` keyed identically;
a stray
`<Foo-Bar />` was reported as `Foo`.
- **Manifest and browser chrome follow the palette** (W14) — three
`#0e1316`
literals matched the token by coincidence. `theme-color` is also now
split in
two, since one dark value painted a dark address bar above a white page
for
every light-theme reader. New maskable icon: without one Android does
not crop
to the launcher shape, it shrinks the mark onto a plain white tile.
### Verification
Every fix is mutation-tested — reverting it makes exactly one named
check fail.
The brand rasters are byte-identical after the `brand-assets.mjs`
refactor,
which is the evidence that separating logic from IO changed no output.
Also checked, and closed with no change needed: the `picomatch` lockfile
churn
(`--frozen-lockfile` is in sync), the 753 KB `grafana-dashboard.png`
(referenced
from the JSON-LD, not stray), and CrowdSec's brand terms — they publish
no
trademark policy, their MIT carries no trademark clause, and this repo
ships no
CrowdSec or MikroTik logo. The exposure is the name used descriptively,
which is
what every third-party bouncer on their Hub does.
https://claude.ai/code/session_01Lt5tP3miz9YCv21qWsjBUo
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/96?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. -->
<div id='description'>
<a href="https://bito.ai#summarystart"></a><h3>Summary by
Bito</h3><ul><li>Implemented per-page social cards generated at build
time, replacing the single shared image.</li>
<li>Updated browser theme colors and web manifest to dynamically follow
the site's color palette, improving accessibility and OS
integration.</li>
<li>Refactored the landing page to use a typed content contract,
ensuring consistency between human-readable text and machine-readable
structured data.</li>
<li>Fixed multiple documentation inaccuracies regarding binary behavior,
CLI paths, and configuration defaults by aligning them with the Go
source code.</li>
<li>Corrected broken binary download links and installation snippets by
dynamically resolving the latest release tag and fixing architecture
suffixes.</li>
</ul></div>
## Summary by Sourcery
Close remaining documentation and branding inconsistencies by generating
page-specific social assets, aligning browser metadata and content with
the product, and adding gates for the defects that previously escaped
validation.
New Features:
- Generate a distinct social card for each documentation page with
localized page titles and section labels.
- Add maskable app-icon support and synchronize browser and manifest
colors with the site palette.
Bug Fixes:
- Regenerate the legacy favicon from the current brand assets.
- Fix homepage and invalid-route social-card references so every
declared card resolves to a built file.
- Improve internationalization parity reporting for equivalent string
attributes, valueless attributes, and hyphenated component names.
- Correct print contrast for code-block borders and update inaccurate
documentation, installation commands, and download links.
Enhancements:
- Share brand and page-card content logic across raster generation and
build-time social-card rendering.
- Align architecture diagrams and landing-page content with the
documented and implemented product behavior.
CI:
- Add a build verification gate that checks all rendered social-image
references resolve to files.
Documentation:
- Refresh the changelog and user-facing documentation to reflect current
binary behavior, configuration, installation, and supported
functionality.
Tests:
- Strengthen contrast, manifest, internationalization, brand-asset, and
social-card validation, including mutation-oriented regression coverage.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added unique social cards for documentation pages, including localized
titles and branding.
- Added a maskable application icon and updated theme colors for light
and dark modes.
- Improved site metadata and branding across shared pages.
- **Bug Fixes**
- Fixed favicon generation and social-card routing.
- Improved print contrast for code blocks and links.
- Corrected internationalization component matching, including
hyphenated names.
- **Documentation**
- Documented social cards, architecture, firewall rules, logging,
configuration references, and updated branding.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
fix(docs): the retired favicon, a broken home-page card, and a 1.61:1 print border — each with the gate that missed it (#96)
Closes the loose ends left over from the phase-5 work, plus the two
workstreams
that were still outstanding (W13 per-page OG cards, W14 icon/manifest
hygiene).
Three of the five things fixed here were **shipped defects nobody could
have
caught**, because in each case the pipeline had no check that joined the
two
halves involved. Each is now closed by a gate as well as by the fix.
### `favicon.ico` was the retired shield
Every icon is rendered from `logo-light.svg` — except the `.ico`, which
was last
written by the *July* logo redesign and carried the
shield-with-WiFi-arcs
through the whole mark change. It is the one asset the author never
looks at,
and the one Google's SERP fetcher and older Safari prefer.
Now packed from the same PNGs as everything else, at 16/32/48. Written
by hand:
sharp cannot encode ICO and an ImageMagick dependency would not survive
CI. The
container is a 6-byte header and one 16-byte entry per image. 15,086
bytes → 553.
### The home page's social card 404'd
The card URL is assembled in two places holding different ids for the
same page
— the endpoint reads the content collection, which calls the English
home page
`index`; the `Head` override sees Starlight's route, whose id for it is
empty.
They agreed on 55 pages and disagreed on the one most links point at,
which
shipped as `og/.png`. Starlight also synthesises a 404 route with an
entry and
no collection page behind it, so that page pointed at a card nothing
rendered.
Both now resolve through one `cardPath`, and membership in the
collection — not
the presence of an entry — decides whether a page has a card.
**`check-social-cards.mjs`
reads every `og:image` out of the rendered HTML and asks the filesystem
whether
it is there.** It found the 404 defect within a second of being written.
### The print stylesheet shipped a 1.61:1 boundary
`@media print` was exempt from the contrast gate because "paper is one
background and the palette does not reach it". The first half is true;
the
second does not follow. Browsers do not print background colours by
default, so
on paper the `pre` border is the only thing separating a code block from
the
prose around it — a graphical object required to understand the content,
so
1.4.11 applies. `#ccc` → `#8a8a8a`, 1.61:1 → 3.45:1.
### Also
- **A social card per page** (W13) — 56 pages shared one banner. Text is
set in
the mono face the site already uses, which makes wrapping exact
arithmetic
rather than a guess, since librsvg does not measure text.
- **The i18n gate invented one mismatch and missed two** — `path="a.b"`
vs
`path={"a.b"}` keyed apart (the self-test asserted this, so the bug was
pinned
by its own suite); `<Home section />` and `<Home />` keyed identically;
a stray
`<Foo-Bar />` was reported as `Foo`.
- **Manifest and browser chrome follow the palette** (W14) — three
`#0e1316`
literals matched the token by coincidence. `theme-color` is also now
split in
two, since one dark value painted a dark address bar above a white page
for
every light-theme reader. New maskable icon: without one Android does
not crop
to the launcher shape, it shrinks the mark onto a plain white tile.
### Verification
Every fix is mutation-tested — reverting it makes exactly one named
check fail.
The brand rasters are byte-identical after the `brand-assets.mjs`
refactor,
which is the evidence that separating logic from IO changed no output.
Also checked, and closed with no change needed: the `picomatch` lockfile
churn
(`--frozen-lockfile` is in sync), the 753 KB `grafana-dashboard.png`
(referenced
from the JSON-LD, not stray), and CrowdSec's brand terms — they publish
no
trademark policy, their MIT carries no trademark clause, and this repo
ships no
CrowdSec or MikroTik logo. The exposure is the name used descriptively,
which is
what every third-party bouncer on their Hub does.
https://claude.ai/code/session_01Lt5tP3miz9YCv21qWsjBUo
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/96?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. -->
<div id='description'>
<a href="https://bito.ai#summarystart"></a><h3>Summary by
Bito</h3><ul><li>Implemented per-page social cards generated at build
time, replacing the single shared image.</li>
<li>Updated browser theme colors and web manifest to dynamically follow
the site's color palette, improving accessibility and OS
integration.</li>
<li>Refactored the landing page to use a typed content contract,
ensuring consistency between human-readable text and machine-readable
structured data.</li>
<li>Fixed multiple documentation inaccuracies regarding binary behavior,
CLI paths, and configuration defaults by aligning them with the Go
source code.</li>
<li>Corrected broken binary download links and installation snippets by
dynamically resolving the latest release tag and fixing architecture
suffixes.</li>
</ul></div>
## Summary by Sourcery
Close remaining documentation and branding inconsistencies by generating
page-specific social assets, aligning browser metadata and content with
the product, and adding gates for the defects that previously escaped
validation.
New Features:
- Generate a distinct social card for each documentation page with
localized page titles and section labels.
- Add maskable app-icon support and synchronize browser and manifest
colors with the site palette.
Bug Fixes:
- Regenerate the legacy favicon from the current brand assets.
- Fix homepage and invalid-route social-card references so every
declared card resolves to a built file.
- Improve internationalization parity reporting for equivalent string
attributes, valueless attributes, and hyphenated component names.
- Correct print contrast for code-block borders and update inaccurate
documentation, installation commands, and download links.
Enhancements:
- Share brand and page-card content logic across raster generation and
build-time social-card rendering.
- Align architecture diagrams and landing-page content with the
documented and implemented product behavior.
CI:
- Add a build verification gate that checks all rendered social-image
references resolve to files.
Documentation:
- Refresh the changelog and user-facing documentation to reflect current
binary behavior, configuration, installation, and supported
functionality.
Tests:
- Strengthen contrast, manifest, internationalization, brand-asset, and
social-card validation, including mutation-oriented regression coverage.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added unique social cards for documentation pages, including localized
titles and branding.
- Added a maskable application icon and updated theme colors for light
and dark modes.
- Improved site metadata and branding across shared pages.
- **Bug Fixes**
- Fixed favicon generation and social-card routing.
- Improved print contrast for code blocks and links.
- Corrected internationalization component matching, including
hyphenated names.
- **Documentation**
- Documented social cards, architecture, firewall rules, logging,
configuration references, and updated branding.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
fix(docs): the retired favicon, a broken home-page card, and a 1.61:1 print border — each with the gate that missed it (#96)
Closes the loose ends left over from the phase-5 work, plus the two
workstreams
that were still outstanding (W13 per-page OG cards, W14 icon/manifest
hygiene).
Three of the five things fixed here were **shipped defects nobody could
have
caught**, because in each case the pipeline had no check that joined the
two
halves involved. Each is now closed by a gate as well as by the fix.
### `favicon.ico` was the retired shield
Every icon is rendered from `logo-light.svg` — except the `.ico`, which
was last
written by the *July* logo redesign and carried the
shield-with-WiFi-arcs
through the whole mark change. It is the one asset the author never
looks at,
and the one Google's SERP fetcher and older Safari prefer.
Now packed from the same PNGs as everything else, at 16/32/48. Written
by hand:
sharp cannot encode ICO and an ImageMagick dependency would not survive
CI. The
container is a 6-byte header and one 16-byte entry per image. 15,086
bytes → 553.
### The home page's social card 404'd
The card URL is assembled in two places holding different ids for the
same page
— the endpoint reads the content collection, which calls the English
home page
`index`; the `Head` override sees Starlight's route, whose id for it is
empty.
They agreed on 55 pages and disagreed on the one most links point at,
which
shipped as `og/.png`. Starlight also synthesises a 404 route with an
entry and
no collection page behind it, so that page pointed at a card nothing
rendered.
Both now resolve through one `cardPath`, and membership in the
collection — not
the presence of an entry — decides whether a page has a card.
**`check-social-cards.mjs`
reads every `og:image` out of the rendered HTML and asks the filesystem
whether
it is there.** It found the 404 defect within a second of being written.
### The print stylesheet shipped a 1.61:1 boundary
`@media print` was exempt from the contrast gate because "paper is one
background and the palette does not reach it". The first half is true;
the
second does not follow. Browsers do not print background colours by
default, so
on paper the `pre` border is the only thing separating a code block from
the
prose around it — a graphical object required to understand the content,
so
1.4.11 applies. `#ccc` → `#8a8a8a`, 1.61:1 → 3.45:1.
### Also
- **A social card per page** (W13) — 56 pages shared one banner. Text is
set in
the mono face the site already uses, which makes wrapping exact
arithmetic
rather than a guess, since librsvg does not measure text.
- **The i18n gate invented one mismatch and missed two** — `path="a.b"`
vs
`path={"a.b"}` keyed apart (the self-test asserted this, so the bug was
pinned
by its own suite); `<Home section />` and `<Home />` keyed identically;
a stray
`<Foo-Bar />` was reported as `Foo`.
- **Manifest and browser chrome follow the palette** (W14) — three
`#0e1316`
literals matched the token by coincidence. `theme-color` is also now
split in
two, since one dark value painted a dark address bar above a white page
for
every light-theme reader. New maskable icon: without one Android does
not crop
to the launcher shape, it shrinks the mark onto a plain white tile.
### Verification
Every fix is mutation-tested — reverting it makes exactly one named
check fail.
The brand rasters are byte-identical after the `brand-assets.mjs`
refactor,
which is the evidence that separating logic from IO changed no output.
Also checked, and closed with no change needed: the `picomatch` lockfile
churn
(`--frozen-lockfile` is in sync), the 753 KB `grafana-dashboard.png`
(referenced
from the JSON-LD, not stray), and CrowdSec's brand terms — they publish
no
trademark policy, their MIT carries no trademark clause, and this repo
ships no
CrowdSec or MikroTik logo. The exposure is the name used descriptively,
which is
what every third-party bouncer on their Hub does.
https://claude.ai/code/session_01Lt5tP3miz9YCv21qWsjBUo
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/jmrplens/cs-routeros-bouncer/pull/96?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. -->
<div id='description'>
<a href="https://bito.ai#summarystart"></a><h3>Summary by
Bito</h3><ul><li>Implemented per-page social cards generated at build
time, replacing the single shared image.</li>
<li>Updated browser theme colors and web manifest to dynamically follow
the site's color palette, improving accessibility and OS
integration.</li>
<li>Refactored the landing page to use a typed content contract,
ensuring consistency between human-readable text and machine-readable
structured data.</li>
<li>Fixed multiple documentation inaccuracies regarding binary behavior,
CLI paths, and configuration defaults by aligning them with the Go
source code.</li>
<li>Corrected broken binary download links and installation snippets by
dynamically resolving the latest release tag and fixing architecture
suffixes.</li>
</ul></div>
## Summary by Sourcery
Close remaining documentation and branding inconsistencies by generating
page-specific social assets, aligning browser metadata and content with
the product, and adding gates for the defects that previously escaped
validation.
New Features:
- Generate a distinct social card for each documentation page with
localized page titles and section labels.
- Add maskable app-icon support and synchronize browser and manifest
colors with the site palette.
Bug Fixes:
- Regenerate the legacy favicon from the current brand assets.
- Fix homepage and invalid-route social-card references so every
declared card resolves to a built file.
- Improve internationalization parity reporting for equivalent string
attributes, valueless attributes, and hyphenated component names.
- Correct print contrast for code-block borders and update inaccurate
documentation, installation commands, and download links.
Enhancements:
- Share brand and page-card content logic across raster generation and
build-time social-card rendering.
- Align architecture diagrams and landing-page content with the
documented and implemented product behavior.
CI:
- Add a build verification gate that checks all rendered social-image
references resolve to files.
Documentation:
- Refresh the changelog and user-facing documentation to reflect current
binary behavior, configuration, installation, and supported
functionality.
Tests:
- Strengthen contrast, manifest, internationalization, brand-asset, and
social-card validation, including mutation-oriented regression coverage.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added unique social cards for documentation pages, including localized
titles and branding.
- Added a maskable application icon and updated theme colors for light
and dark modes.
- Improved site metadata and branding across shared pages.
- **Bug Fixes**
- Fixed favicon generation and social-card routing.
- Improved print contrast for code blocks and links.
- Corrected internationalization component matching, including
hyphenated names.
- **Documentation**
- Documented social cards, architecture, firewall rules, logging,
configuration references, and updated branding.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Prepare 1.4.0 tooling and review follow-ups (#24)
Prepare the 1.4.0 branch with dependency/tooling updates, docs validation, release metadata, and follow-up review fixes.
Summary:
- Add and document periodic reconciliation behavior, release references, and refreshed docs/tooling validation.
- Modernize Go and docs tooling, including static analysis, pnpm checks, GoReleaser, and workflow gating.
- Address review feedback across RouterOS error handling, metrics, config expansion, functional scripts, docs, templates, and CI.