Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
d0a652d
scripts: survey_tooling.mjs, a before-and-after measure of the tooling
KubaO Sep 25, 2026
9062484
book: delete four superseded pdf-lib shims that only perf/ loaded
KubaO Sep 25, 2026
26eefee
perf: say that the book build loads detach-pages.js
KubaO Sep 25, 2026
86a7010
builder: PLAN-TOOLING-REVIEW.md, strategy and decisions for the review
KubaO Sep 25, 2026
e0d127f
wisdom: close the blockquote fence in a Len.md staging section
KubaO Sep 25, 2026
bb2bf38
builder: the tooling review at fe9ce12b, with its evidence
KubaO Sep 25, 2026
671e6f1
builder: record the review's decisions in PLAN-TOOLING-REVIEW.md
KubaO Sep 25, 2026
d66aaa8
builder: add the tooling review's commit plan to PLAN-TOOLING-REVIEW.md
KubaO Sep 25, 2026
6d85e40
docs: state the dependency pinning policy, and correct Builder.md's list
KubaO Sep 25, 2026
b0612a4
scripts: compare_trees.mjs, the built trees before and after a change
KubaO Sep 25, 2026
767f72c
builder: record compare_trees' A/A and detection runs in the plan
KubaO Sep 25, 2026
186f0ec
scripts: check_ci_workflows.mjs, the workflows against the wrappers' …
KubaO Sep 25, 2026
582ab01
ci: one composite action for the gates both workflows run
KubaO Sep 25, 2026
9cb0efe
lint: Biome, correctness rules only, and the fixes it finds
KubaO Sep 25, 2026
f5f1d9d
deps: update js-yaml, ws, linkify-it and immutable past their advisories
KubaO Sep 25, 2026
0d42ab3
scripts: check_lint.mjs, a lint gate in test.bat and CI
KubaO Sep 25, 2026
0ffd7e9
scripts: convert_em_dash_separators exits 2 on a crash
KubaO Sep 25, 2026
982047b
githooks: a pre-commit hook that runs Biome on the staged files
KubaO Sep 25, 2026
3a80006
deps: declare picocolors and pako, which the code imports directly
KubaO Sep 25, 2026
746cb63
scripts: move census_attributes.mjs out of builder/
KubaO Sep 25, 2026
d1d0a55
scripts: census_attributes finds the install through tb-install
KubaO Sep 25, 2026
2014cde
lib: move markdown-files.mjs to a top-level lib/
KubaO Sep 25, 2026
b6b84fe
builder, eval: decide what is an output tree with isOutputTree
KubaO Sep 25, 2026
50982b4
builder: delete what the retired diff tools left behind
KubaO Sep 25, 2026
62add2f
builder: refuse a --dest that overlaps the source tree
KubaO Sep 25, 2026
90ea1e6
builder, wisdom: delete precomputeSeo and schemas.mjs; unexport kramd…
KubaO Sep 25, 2026
f9458a7
scripts: tbrun recognises all five failed-build shapes
KubaO Sep 25, 2026
8e274b8
scripts: harness CLIs reject a missing value; tbbuild finds its project
KubaO Sep 25, 2026
1cacbe4
builder, scripts: a command-line error exits outside the link bitmask
KubaO Sep 25, 2026
57cdaa1
docs, builder: correct render.mjs's export table and plugin chain
KubaO Sep 25, 2026
6eecf5b
wip: the marked-sample counts as of 2026-09-25
KubaO Sep 25, 2026
3d87253
builder: schedule tbrun's erased-log check as C25a; settle C70's ques…
KubaO Sep 25, 2026
4de7b5c
builder: cut the tooling plan's landed entries to what later work needs
KubaO Sep 25, 2026
3136827
scripts: close the browser on every exit path, through lib/browser.mjs
KubaO Sep 25, 2026
0ba4246
a11y: validate --theme and --viewport wherever a matrix is built
KubaO Sep 25, 2026
8b6f5ea
builder: the Gantt chart draws every task, or the build fails naming it
KubaO Sep 25, 2026
d3271ee
scripts: crawl_check follows every link attribute the build checks
KubaO Sep 25, 2026
394f3b5
scripts: crawl_check sets its exit code instead of calling process.exit
KubaO Sep 25, 2026
a39f4e2
builder: serve.bat redirects a folder URL to its trailing slash
KubaO Sep 26, 2026
371a5f3
docs: Builder.md's task sections match the chart and the task graph
KubaO Sep 26, 2026
54b08df
scripts: crawl_check retries a request that fails before any response
KubaO Sep 26, 2026
f882a0a
docs: Pipeline-Stages.md's task sections match the chart and the task…
KubaO Sep 26, 2026
2659076
docs: export tables for counts.mjs and page-baseline.mjs
KubaO Sep 26, 2026
520de1a
builder: tbdocs.mjs's task-graph comment points to TASKS and the docs
KubaO Sep 26, 2026
a1c8c32
builder: delete counts.mjs's unused COUNT_NAMES
KubaO Sep 26, 2026
a2f570f
scripts: crawl_check reports a page whose body cannot be read
KubaO Sep 26, 2026
f2fc6ce
scripts: crawl_check's --timeout covers a page's body
KubaO Sep 26, 2026
f4352d0
scripts: check_examples restores the registry after a spawn failure
KubaO Sep 26, 2026
c08a496
scripts: tb-operate stops on an afterReveal timeout
KubaO Sep 26, 2026
1efa761
scripts: tbbuild always tidies; correct tb-registry's -Command note
KubaO Sep 26, 2026
01aa235
scripts: tbbuild refuses a named IDE that is not there
KubaO Sep 26, 2026
7b2c9ae
scripts: tb-launch.ps1 reports why a launch failed, in plain text
KubaO Sep 26, 2026
9e6f866
scripts: launchIde under --show reports a spawn that fails
KubaO Sep 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Git hooks stay LF even where core.autocrlf checks files out CRLF. Git for
# Windows runs a CRLF hook without trouble, but a POSIX Git -- WSL on a
# Windows checkout, say -- hands the hook to the kernel, which reads the
# carriage return after #!/bin/sh as part of the interpreter's name.
.githooks/* text eol=lf
11 changes: 11 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh
# Lints the scripts this commit stages with the pinned Biome, through
# scripts/check_lint.mjs --staged: the check test.bat and both CI workflows
# run over the whole scope, on the files being committed. It runs nothing
# else, and a commit that stages no script returns before Biome starts.
#
# Enable it in a clone: git config core.hooksPath .githooks
#
# Git runs a hook from the top of the working tree. .gitattributes keeps this
# file LF in every checkout, for a POSIX Git's sake: see the reason there.
exec node scripts/check_lint.mjs --staged
180 changes: 180 additions & 0 deletions .github/actions/run-gates/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# The gate steps both workflows run, in their order, after the build.
#
# checks.yml runs them on every pull request, before a merge; tbdocs-gh-pages.yml
# runs them on every push to `staging`, before it deploys -- which makes that
# the one place a change pushed straight to `staging`, or a manual dispatch,
# meets them. One list serves both, so a gate cannot be added to one workflow
# and forgotten in the other; scripts/check_ci_workflows.mjs checks this list
# against test.bat and check.bat. Each gate is its own step, shown as its own
# group in the job's log.
#
# Needs the repository checked out, dependencies installed, Chromium
# installed, and the site built into docs/_site*, as both workflows do before
# calling it.
name: Run the gates
description: The gate steps both workflows share, checked against test.bat and check.bat by check_ci_workflows.mjs.
runs:
using: composite
steps:
# The build is the only pass over the site's HTML. This step is NOT a
# second one: it runs the differential harness against a nine-file
# synthetic tree that carries one fault of every kind, so
# scripts/check_links.mjs -- still the tool for a tree the build did not
# produce, and the oracle the fused path is defined against -- cannot rot
# unnoticed. ~0.3 s, no site files touched.
#
# The full script-vs-fused comparison over the real trees stays a manual
# gate (`check_links_diff.mjs --a script --b fused`): running it here would
# mean checking every page twice, which is exactly what folding the check
# into the build removed.
- name: Verify the standalone link checker (check_links_diff.mjs)
shell: bash
run: node scripts/check_links_diff.mjs --case fixture --a script --b index
# The publish allowlist (builder/publish-policy.mjs) is enforced inside
# the build, so a green build already says nothing unpublishable is in
# docs/. It does NOT say the allowlist still refuses anything: one widened
# until it refuses nothing reports the same clean pass. This asserts the
# refusals against named probes -- a stray .bak, a .pem, a scratch .md
# with no frontmatter. No browser, no built tree, ~40 ms.
- name: Verify the publish allowlist (check_publish_policy.mjs)
shell: bash
run: node scripts/check_publish_policy.mjs
# The two gate lists on Tools.md against the wrappers that run them, plus
# every gate count stated in prose in README.md or under
# docs/Documentation/. Documented gate counts have rotted three times; the
# third was round 3's own fix pass, on the two pages the first version of
# this gate did not read. Pure text, ~50 ms.
- name: Verify the documented gate lists (check_gate_lists.mjs)
shell: bash
run: node scripts/check_gate_lists.mjs
# Both workflows, and this action, against the wrappers: every gate
# test.bat and check.bat run, with the same arguments and in the same
# order, and a build with build.bat's flags. See the script's header for
# the differences it allows. No browser, no built tree.
- name: Verify the workflows run the wrappers' gates (check_ci_workflows.mjs)
shell: bash
run: node scripts/check_ci_workflows.mjs
# Biome, pinned, over the tooling, with the rules that find defects and
# none about style (biome.jsonc). Moving and deleting code leaves unused
# imports and undeclared names behind, and nothing else reads the tooling
# for them. Warnings fail as well as errors, since Biome reports an unused
# import as a warning and exits 0 on one; and a scope that matches no
# script fails rather than passing. npm ci installs the Linux binary. No
# browser, no built tree, ~0.25 s.
- name: Lint the tooling (check_lint.mjs)
shell: bash
run: node scripts/check_lint.mjs
# A regex that backtracks exponentially does not fail a build, it stops
# one: the corpus passes until a page happens to contain the trigger, and
# then a render worker sits inside String.replace forever. VOID_TAGS_RE
# shipped that way for as long as no alt text contained a slash, and its
# first fix was still exponential on a subtler witness. Nothing else here
# can see it, because there is nothing to see until the content changes.
#
# Reads regex literals AND every `new RegExp(...)` the source decides the
# arguments of. That second half is not a refinement: assembling a pattern
# from shared string constants is ordinary JavaScript, and for as long as
# this read literals only it was also a way out of the gate. Six such
# regexes went into one gate unseen, one of them polynomial.
#
# Gates on exponential only -- about a fifth of the patterns here are
# polynomial, nearly all the ordinary `<tag[^>]*>` shape on bounded input,
# and a gate that fails on day one gets switched off. The self-test probes
# run inside the same pass, classification and folding both, so a green
# line here cannot be a gate that has stopped detecting. No browser, no
# built tree, a few seconds sharded across the runner's CPUs.
#
# recheck's native backend is an optional dependency resolved per
# platform; if it is missing the script says so and falls back to the
# pure-JS implementation, which is slower but reaches the same verdict on
# every probe.
- name: Verify regex safety (check_regex_safety.mjs)
shell: bash
run: node scripts/check_regex_safety.mjs
# render.mjs applies several kramdown-parity rewrites to RAW markdown,
# before anything has been parsed, so none of them can tell prose from
# code -- on a site whose subject matter is code. Four defects of that
# shape shipped: `{% raw %}` stripped inside fences, admonition bodies
# losing the indentation of the code they contain, `Items[1](a, b)`
# percent-encoded inside a fence, and a YAML sample's closing `---`
# deleted with the line above it promoted to a heading.
#
# No other gate can see any of it: the corruption is inside <code>, and
# the link, integrity, publish and axe checks all pass over it. Tokenise
# the source, apply the real rewrite chain, re-tokenise, and compare the
# literal regions. Probes ride along in the same run so a clean corpus
# cannot be mistaken for a working gate. No browser, no built tree.
- name: Verify code regions survive the pre-render rewrites (check_code_regions.mjs)
shell: bash
run: node scripts/check_code_regions.mjs
# The page-count drift guard reports nothing on a healthy tree, so a green
# build says exactly what a guard that had stopped working says. These
# probes make the other assertion, against a scratch baseline rather than
# the committed one. The first replays the defect that motivated it: 37
# pages of AppGlobalClassObject lost to a blanket exclude rule, under a
# guard that knew only a floor of 836 against a real 908. No browser, no
# built tree.
- name: Verify the page-count drift guard (check_page_baseline.mjs)
shell: bash
run: node scripts/check_page_baseline.mjs
# The book-coverage warnings say nothing when every page has an entry in
# docs/_book.yml, which is also all a check that had stopped working would
# say. Before they existed, whole sections dropped out of the PDF without a
# word. These probes give each of the five findings a fault to report, on
# a manifest and pages built in memory. No browser, no built tree.
- name: Verify the book-coverage warnings (check_book_coverage.mjs)
shell: bash
run: node scripts/check_book_coverage.mjs
# The symbol index (tB/symbols.json) is read by the IDE help add-in. A
# build that indexes the reference cleanly says nothing about the rules
# that did not fire on it, so these probes assert each against the case
# that made it necessary -- the .twin scanner's traps, the rules placing a
# symbol on a page or heading, and the drift guard refusing a URL the index
# stopped publishing. Fixtures only: no tree, no install.
- name: Verify the symbol index and its drift guard (check_symbol_index.mjs)
shell: bash
run: node scripts/check_symbol_index.mjs
# Graphviz sizes each node box from a width table; the browser paints the
# label with a real font. Nothing in the build compares the two, so a
# mismatch ships as text hanging outside its box on a green build -- which
# is how 27 labels across three diagrams went out, through a full
# accessibility sweep, unreported. axe does not evaluate SVG <text>
# geometry either.
#
# After the build on purpose: builder/dot.mjs rewrites a stale .svg from
# its .dot in place, so this measures the bytes about to be deployed, not
# the ones that were committed. It loads Inter from the committed .woff2 by
# @font-face rather than relying on an installed face, so unlike the
# target-size rules it measures the same here as on a dev box. ~1 s.
- name: Verify DOT diagram fit (check_dot_fit.mjs)
shell: bash
run: node scripts/check_dot_fit.mjs
# check_a11y.mjs injects a PATCHED axe bundle (plain-color-fields, -26 % on
# a realistic page set -- see builder/PLAN-axe-perf.md), so the patch has
# to be verified before its results are trusted. The patch asserts its
# substitution targets and so fails loudly if an axe-core bump moves the
# code; this catches the other case, where the text still matches but the
# colour maths has changed. The fingerprint gate cannot see that -- it
# compares `incomplete` as a rule-id set.
#
# Cheap (one page, two bundles), and Chromium is already installed. The
# change that bumps axe-core is exactly when it earns its place.
- name: Verify axe source patch (check_axe_patch_equiv.mjs)
shell: bash
run: node scripts/check_axe_patch_equiv.mjs
# The scan is thirteen pages of ~1,160, so its page list decides what it
# can report at all. This fails when the site grows a markup construct no
# sample page carries -- the drift that let the previous six-page sample
# report a clean pass while 54 pages had violations in constructs it never
# saw. No browser, ~1 s.
- name: Verify a11y sample coverage (pick_a11y_sample.mjs)
shell: bash
run: node scripts/pick_a11y_sample.mjs --check
# Matches check.bat: the build's own link check gates this, and a link
# failure short-circuits before the (slower) browser scan runs. Scans
# _site-offline/, whose relative asset paths actually resolve -- _site/
# uses root-absolute URLs that render unstyled here, making every
# colour-contrast result meaningless.
- name: Accessibility check (check_a11y.mjs)
shell: bash
run: node scripts/check_a11y.mjs
Loading
Loading