Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a082b6a
Remove unreferenced environment-variables.png
KubaO Oct 9, 2026
fea756b
Help Add-In: page renamed; helpdemo drops tbIDE, Choices and Settings…
KubaO Oct 7, 2026
d633dfe
WIP.Screenshots: plan for shoot_docs.mjs, the docs-wide screenshot tool
KubaO Oct 7, 2026
a7a159e
shoot_docs: screenshot tool for menus and dialogs too; 33 pictures re…
KubaO Oct 8, 2026
9894dfd
shoot_docs: annotation overlay; four New / Open Project pictures reta…
KubaO Oct 8, 2026
0fed37f
shoot_docs: the no-project panels, Debug Console and Diagnostics anno…
KubaO Oct 8, 2026
7357bab
shoot_docs: sample setup on a SampleProject fixture; 31 Project Explo…
KubaO Oct 8, 2026
7070abe
shoot_docs: Project Settings pictures and glyph crops retaken; settin…
KubaO Oct 8, 2026
8c8e000
shoot_docs: capture keeps the picture on disk when any of up to 8 cap…
KubaO Oct 8, 2026
6c104b3
shoot_docs: a full run in ~70 s (was ~765): closeMenus fix, condition…
KubaO Oct 9, 2026
a592149
shoot_docs: increment 3 batch 3, global-search and sample6 setups; Sa…
KubaO Oct 9, 2026
9d3f1e6
shoot_docs: increment 4 batch 1, designer setup; form and report desi…
KubaO Oct 9, 2026
408bc28
shoot_docs: --diffs under-docs check right across drives; its cli cas…
KubaO Oct 9, 2026
08cc31c
shoot_docs: increment 4 batch 2, forms setup and a WebView2 form in s…
KubaO Oct 9, 2026
e6c9be1
shoot_docs: increment 4 batch 3, replica select lists, composites, cu…
KubaO Oct 9, 2026
f60ccd4
shoot_docs: increment 4 batch 4, code and sample9 setups, codeLines; …
KubaO Oct 9, 2026
cee5969
shoot_docs: increment 5, the IDE feature map (featuremap setup and fi…
KubaO Oct 9, 2026
bdc3dce
tbdocs: build the help add-in's project file and publish it as a down…
KubaO Oct 9, 2026
6e3fe94
Help add-in: a 2px line in the theme's text colour between the result…
KubaO Oct 9, 2026
0ae4be0
Help add-in: the detached window's pages keep the IDE's theme and pan…
KubaO Oct 9, 2026
45e126c
Help add-in download carries the offline archive; CI builds the archive
KubaO Oct 9, 2026
63e9dda
check_links: --online-root excuses the offline rewrite's links to web…
KubaO Oct 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .github/actions/run-gates/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ runs:
- name: Unit-test the harness's port claims (test/ports.test.mjs)
shell: bash
run: node --test test/ports.test.mjs
# Unit tests for builder/addin-project.mjs, which packs add-in/ into the
# help add-in's project file the build publishes: the project holds exactly
# the files git tracks there, never Resources/HELP/, and the same bytes from
# a CRLF checkout as from an LF one. Needs git. No browser, no built tree,
# about 1 s.
- name: Unit-test the help add-in's project file (test/addin-project.test.mjs)
shell: bash
run: node --test test/addin-project.test.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. Nothing else
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ jobs:
# step fails on the exit code: 1 when the check found a problem,
# 2 when the build could not run.
#
# --no-help-archive: a local build ends by zipping the offline tree
# for the IDE help add-in. CI has no use for that archive and must
# not spend time on it.
run: node builder/tbdocs.mjs --src docs --no-fetch-assets --no-help-archive --check-audit-index
# The build also zips the offline tree for the IDE help add-in and
# packs the zip into the add-in's project file, the download the site
# offers. Never pass --no-help-archive here: the download would lose
# the archive (check_ci_workflows.mjs refuses the flag).
run: node builder/tbdocs.mjs --src docs --no-fetch-assets --check-audit-index
# The gates both workflows run, in one list: see
# .github/actions/run-gates/action.yml, which check_ci_workflows.mjs
# checks against test.bat and check.bat. Each gate is its own group in
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/tbdocs-gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ jobs:
# online tree gets a base path -- the offline tree's links are all
# relative after the rewrite.
#
# --no-help-archive: a local build ends by zipping the offline tree
# for the IDE help add-in. CI has no use for that archive and must
# not spend time on it.
run: node builder/tbdocs.mjs --src docs --url '${{ steps.pages.outputs.origin }}' --baseurl '${{ steps.pages.outputs.base_path }}' --no-fetch-assets --no-help-archive --check-audit-index
# The build also zips the offline tree for the IDE help add-in and
# packs the zip into the add-in's project file, the download the site
# offers. Never pass --no-help-archive here: the download would lose
# the archive (check_ci_workflows.mjs refuses the flag).
run: node builder/tbdocs.mjs --src docs --url '${{ steps.pages.outputs.origin }}' --baseurl '${{ steps.pages.outputs.base_path }}' --no-fetch-assets --check-audit-index
# The gates both workflows run, in one list: see
# .github/actions/run-gates/action.yml, which check_ci_workflows.mjs
# checks against test.bat and check.bat. checks.yml runs only on pull
Expand Down
116 changes: 107 additions & 9 deletions WIP.Build.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ keys through .NET, because `reg.exe` mangles names outside the console code page
`lib/` — modules that every other tooling folder may import, and that import none of them.
`builder/` may not import `scripts/`, so code that both need lives here;
[lib/README.md](lib/README.md) states the rule, and `biome.jsonc` refuses an import that
breaks either one.
breaks either one. The rule has one exception, named in `biome.jsonc`:
`scripts/impexp.mjs`, a published standalone tool that must stay one dependency-free
file, which the build packs the help add-in's project file with (see [The help add-in's
project file](#the-help-add-ins-project-file)).

`wisdom/` — Discord knowledge-harvesting tool (three-phase: export → process → extract). Plans in `wisdom/PLAN-{1,2,3}.md`; implementation under `wisdom/`. Uses only Node.js built-in APIs. Running it is [WIP.Wisdom.md](WIP.Wisdom.md).

Expand Down Expand Up @@ -215,7 +218,7 @@ Unlike the link check, **a finding here aborts the build**. A broken link still
leaves a tree worth inspecting; a tree with a private key in it is a tree nobody
should be one `upload-pages-artifact` away from publishing.

Three details of the policy are essential:
Four details of the policy are essential:

- **`SOURCE_EXTENSIONS` and `BUILD_EXTENSIONS` are separate sets, and must stay
separate.** The build emits `.xml` and `.json`; a contributor has no business
Expand All @@ -235,6 +238,14 @@ Three details of the policy are essential:
ends spelled out, which is what makes them shippable. The same extension
anywhere else still fails; otherwise declaring one entry would bless a whole
type.
- **`addin_project` is exempt by path too, and on the tree surface only.** The
help add-in's `.twinproj` is written by the build, not found in `docs/`, so
`publishPolicyFor` puts its `dest` in a set of its own, `generated`, which only
`unpublishableTreePaths` reads. A `.twinproj` found in `docs/`, even at that
path, is refused at source: the build writes the file there, and a copy in the
source tree could only be a stale one. `check_publish_policy.mjs` asserts all
three: the path publishes from a tree, a `.twinproj` elsewhere does not, and
one at that path in `docs/` does not.

**A clean build says only that nothing in `docs/` is currently refused, which is
also what an allowlist widened until it refuses nothing says.** No build over a
Expand Down Expand Up @@ -392,7 +403,7 @@ node scripts/check_tree_fresh.mjs --tree docs/_site-pdf --marker book.html
**`--marker` is what makes that work on this tree.** The script identifies a tree
by its `index.html`, which every output tree has *except* `_site-pdf/` --- that one
holds a single `book.html`. Exit codes are the script's: **2** when the tree is
absent, **1** when it is older than `docs/`, `builder/` or `lib/`. The renderer that runs after it
absent, **1** when it is older than one of its sources (`DEFAULT_SOURCES`). The renderer that runs after it
has no 1, so `book.bat`'s 1 means a stale tree (or a failed `npm install`) and nothing about the render.

> **Batch detail:** `%ERRORLEVEL%` inside a parenthesised `if errorlevel 1 (...)`
Expand All @@ -401,11 +412,14 @@ has no 1, so `book.bat`'s 1 means a stale tree (or a failed `npm install`) and n
> `goto :fail` and captures outside the block, which is the same shape
> `test.bat` uses, and for the same reason.

**Known false positive.** `DEFAULT_SOURCES` is `["docs", "builder", "lib"]` and
does not distinguish code from notes, so editing a `builder/PLAN-*.md` or
`REVIEW-*.md` marks every tree stale even though nothing in the build reads those
files. It errs toward refusing, which is the safe direction, and a rebuild is
~4 s --- but a pure note edit blocks a `book.bat` render until you rebuild.
**Known false positive.** `DEFAULT_SOURCES` is `docs`, `builder`, `lib`, `add-in`
and `scripts/impexp.mjs`, and does not distinguish code from notes, so editing a
`builder/PLAN-*.md` or `REVIEW-*.md` marks every tree stale even though nothing in
the build reads those files; so does a file under `add-in/` that git does not track,
which the add-in's project file leaves out. It errs toward refusing, which is the
safe direction, and a rebuild is ~4 s --- but a pure note edit blocks a `book.bat`
render until you rebuild. `add-in/` and `impexp.mjs` are there because they decide
the bytes of the [help add-in's project file](#the-help-add-ins-project-file).

**Which folders under `docs/` are outputs comes from one list.** A build given
`--dest docs/_site-basepath` writes `_site-basepath-offline` and
Expand All @@ -421,7 +435,11 @@ prefix list (`_site`, `_serve`, `_pdf`) the markdown walk uses --- and keeps onl
`page-baseline.json` and `symbol-baseline.json` (`IGNORED_FILES`) are written
after the tree, so counting them would mark every tree that added a page or a
heading stale on the next `check.bat`. `package-api.json` is an input: the build
reads it and it decides the bytes of `tB/symbols.json`.
reads it and it decides the bytes of `tB/symbols.json`. Under `add-in/` two paths are
skipped by their place in the repository (`IGNORED_PATHS`): `Resources/HELP/`, where
the build writes the help archive, and `Resources/SYMBOLS/symbols.json`,
the copy of the index the build rewrites. Neither is an input, since the project file is
packed with the index the build wrote rather than with that copy.

### The code-region gate

Expand Down Expand Up @@ -642,6 +660,86 @@ members are placed before the rest**, so a member's URL is the heading under
Properties and not a prose section of the same name above it (`Screen.Fonts` is
`#fonts-1`, its `### Fonts`, not a prose `#fonts`).

### The help add-in's project file

Every build of `docs`, CI's included, writes `tB/IDE/AddIns/downloads/tbDocsHelp.twinproj`
into the online tree: the `addinProject` task
([builder/addin-project.mjs](builder/addin-project.mjs)), declared by `addin_project` in
`_config.yml`, so the test fixtures' configs get none. The Help Add-In page offers it.
The decisions, each with what it rules out:

- **What goes in is `git ls-files` of `add-in/`, read from the working folder.** A plain
walk of the folder packs whatever lies there: a stale `Resources/HELP/site.zip`
(gitignored, ~26 MB, from some earlier build), a `Build/` folder an IDE wrote, a
scratch module. Reading git's blobs instead would leave a local build's download one
commit behind the add-in being edited. `Resources/HELP/` is also refused by name, in
case it is ever added. A file git does not track is named in the build's output.
- **The archive in the project is the one this build wrote, handed over in memory.**
The `helpArchive` task returns the zip it wrote, and `addinProject` waits for it and
packs those bytes as `Resources/HELP/site.zip`. Reading the file back from
`add-in/Resources/HELP/` could pick up the archive of an earlier build whenever this
one wrote none (`--no-help-archive`, `--serve`, another `--dest`, a fixture): that
case packs no archive, and the summary line says `without the offline archive`.
The archive is made **before** the Gantt injection, so it holds `BuildInfo.html`
without the chart: the chart holds the build's timings, and a download that held it
would differ from one build of a tree to the next. `recheckHelpArchive` checks at
the end of `runBuild` that the offline tree still lists the archive's files and
differs from it in `BuildInfo.html` and `assets/images/gantt.svg` alone.
`gantt.svg` is a tracked 105-byte placeholder in `docs/assets/images/`, copied into
both trees as a static file, so it is in the archive's file list; the injection
overwrites it in the trees and the archive keeps the placeholder.
- **The task waits for every writer of the offline tree.** `flushJoin` (the render
lanes write each page's offline HTML in their flush), `scss` (the offline
stylesheet) and `writeOffline` (statics, theme assets, redirect stubs, `nav.js`,
`search-data.js`). Nothing else writes there before the injection; a writer added
later and missed here fails the build in `recheckHelpArchive`, which is why that
check compares every file's content.
- **The offline tree has no copy, and its link goes to the website.** The project
carries the offline tree's archive, so a copy in that tree would be inside its own
archive. `deriveTreeRels` takes the path as an online-only file. The page links to
it relatively, and the offline rewrite (`computeWebsiteUrl` in `offline-rewrite.mjs`)
writes any URL the offline tree lacks and the online tree holds as `site.url` + base
path + path, without counting a miss. The offline link check would flag that URL
(the `forbid` prefix is the site's origin), so its worker env carries `forbidExempt`
(`isWebsiteOnlyLink`), which excuses a website URL only when the online tree holds
the path and the offline tree does not: a live-site link to a page the offline tree
holds is still a missed rewrite. `scripts/check_links.mjs`, which reads trees from
disk, makes the same exemption when `--online-root` names the online tree, and
`check_links_diff.mjs`'s two offline cases pass it.
- **Line endings are git's, not the checkout's.** `.gitattributes` checks
`add-in/Resources/` out `-text`, but not `Settings`, `Sources/*.twin` or the `.tbform`:
under `core.autocrlf` a Windows checkout holds them with CRLF and CI's Linux one with
LF, and `impexp` stores `Settings` and the `.tbform` byte for byte. So CRLF becomes LF
outside `Resources/` before packing, and `impexp` then gives the code files CRLF. Without
it the published file (built on Linux) and a local build differ, and so do
`compare_trees` sides built on different machines.
- **The index is the build's, not the committed copy.** `syncAddinIndex` never writes in
CI, so packing `add-in/Resources/SYMBOLS/symbols.json` would publish the committed copy,
one build behind whenever a page changed. The task packs `symbolIndex`'s `json`, so
the download holds the index of the pages it is published with; that is also why it
runs after `symbolIndex` and why `checkReport` waits for it.
- **The path is in the online tree from `dispatch` on.** It goes into the list
`deriveTreeRels` takes (`onlineOnlyRels`), so the link check resolves the page's link to
it and the publish sweep sees it. If the task stops writing,
`--check-audit-index` reports the file as indexed but not on disk.
- **The pack is `impexp.mjs`'s `importProject`, in process.** `builder/` may not import
`scripts/` (`biome.jsonc`), because `check_tree_fresh.mjs` would not see a change to
what the build imports. `impexp.mjs` is the one exception, by name in the rule: it
imports nothing, the build already publishes it through `bundle_extra`, and
`check_tree_fresh.mjs` now watches it and `add-in/`. Not the compiler executable,
which CI does not have, and not `impexp.py`, which CI's Node job need not have.
- **`--serve` writes it, `--dry-run` does not.** The preview has the page that links to
it, and packing takes about 100 ms; the help archive is skipped under `--serve` because
it takes seconds and writes into `add-in/`, which this writes nowhere near. The `--serve`
download holds no archive.
- **Deterministic by construction.** `impexp` writes no time, numbers every revision with
a constant and sorts every folder by code point; `git ls-files` is sorted too.
`test/addin-project.test.mjs` packs the real `add-in/` and fixture repositories:
exactly the tracked files, no `Resources/HELP/` file from the disk, the given archive
byte for byte (and none when none is given), a CRLF and an LF checkout giving the
same bytes, and the file in exactly the trees it is given; and `checkHelpArchive`
against small trees.

### Build-time counts as named values

`{{tbdocs:pages}}` in a page renders as the number of pages the build
Expand Down
Loading
Loading