Developers · The folder

Fixtures, check and preview

Copies of your sources and what they must give, so check runs your plug-in as the Server will, offline. preview draws the days; probe tries real sources.

Fixtures prove to you, the tool and a reviewer that your plug-in works without the network. They are outside the digest; check runs them every time.

text
fixtures/ sources/<name> a real copy of each declared source (tides, or tides.csv) records.jsonl what fetch.mjs prints for them context.json optional: the moment the check runs at runs/<case>/ optional: a later run, or a source that must fail sources/<name> the files that differ from fixtures/sources/ context.json its own moment records.jsonl what that run must print, or expect.json { "exit": 2, "reason": "…" }: how it must fail

Cut a real source down to the days you want rather than invent one; a source with no fixture fails with PLG-FIXTURE-SOURCE-MISSING. What fetch.mjs prints is held to records.jsonl byte for byte. Without context.json, check runs now, and may print differently next week; with it, today must be now's date in your zone, which catches the commonest time-zone mistake:

json
{ "now": "2026-09-30T10:00:00.000Z", "today": "2026-10-01" }
sh
node kanboombo-plugin.mjs check harbour-almanac
text
Kanboombo plug-in checks: harbour-almanac ✖ PLG-FIXTURE-CONTEXT-INVALID fixtures/runs/wrong-day: today 2026-10-01 is not 2026-09-30T10:00:00.000Z's date in Pacific/Auckland (2026-09-30) Fix: Write { "now": "2026-10-01T13:30:00Z", "today": "2026-10-01" }, where today is now's date in your time zone. https://kanboombo.com/developers/plugins/publish/submission-errors/#plg-fixture-context-invalid
sh
rm -r harbour-almanac/fixtures/runs/wrong-day

A case with records.jsonl is a later day, run with backfill false. A case with expect.json is a source that must fail, the most useful kind, and the portal asks for at least one: when your source changes shape, your fetcher must stop with a reason, not print nothing or the wrong column. exit is the code it must use (any non-zero if left out); reason, words its last stderr line must contain. Add one for each way your source has broken, or will:

json
{ "asOf": "2026-10-01", "meetings": [{ "id": "meeting-2026-10-1", "date": "2026-10-01", "status": "postponed" }] }
json
{ "exit": 2, "reason": "a status this plug-in does not know" }

check

sh
node kanboombo-plugin.mjs check harbour-almanac
text
✔ harbour-almanac: 350 records, 1 later run, 2 failure cases, contract 1 digest …

The new case passes: its fetcher stops. Had it printed records, or stopped for another reason, it would fail with PLG-RUN-EXPECTED-FAILURE. check reads plugin.json against contract 1, the folder (named after the id, with a fetch.mjs) and its imports; finds a fixture per source; runs fetch.mjs on them; checks every record; compares with records.jsonl; runs each runs/<case>; checks your listing if you have one; and prints the digest. It stops at the first failing step with every problem so far (code, fix, link) and exits 0 or 1: put it in your CI as it is.

On your machine the fetcher runs as you, behind a guard: any way Node reaches the network throws (PLG-RUN-NETWORK), Node's permission model limits reads to the folder and its sources (PLG-RUN-READ-OUTSIDE), and your limits kill it (PLG-RUN-KILLED). That is a seat belt for your own code, not a sandbox for anyone else's: other people's code runs only in the Server's locked room.

preview

preview <id> draws each day with pluginDayRows, the function the app's day uses, so a row reads as it will for a reader (quickstart, How records look). --days A..B shows up to 62 days (three either side of today by default), --language es your Spanish names (dates and figures stay English, as in the app), --run <case> a runs/<case>, and --html <file> writes a page. One run cannot show Moved to … or a revision: those come from what the Server stored before.

probe

sh
node kanboombo-plugin.mjs probe harbour-almanac

probe downloads each source once (https, your hosts only, within maxBytes), runs the fetcher and checks every record. Use it before you refresh a fixture; it is never part of a check. This site serves the almanac's sources, so you can probe it.

When check fails

Copy all of check's output: its code, fix and link are what an assistant needs (every code). The ones everyone meets once:

Code
Nearly always
Do
Code
PLG-RECORD-AFTER-TODAY
Nearly always
A date from toISOString(): in the evening west of UTC, it is already tomorrow
Do
Compare every date with the context's today and skip what is later
Code
PLG-RUN-NETWORK
Nearly always
A fetch() in the fetcher
Do
Declare the file as a source and read the path the context gives
Code
PLG-IMPORT-PACKAGE, PLG-IMPORT-OUTSIDE
Nearly always
An npm package, or ../shared/
Do
Copy the code into the folder as readable .mjs, as Harbour Almanac does with its CSV reader
Code
PLG-RUN-FAILED
Nearly always
An exit you did not mean
Do
Read the last line it wrote to stderr
Code
PLG-MANIFEST-UNKNOWN-KEY
Nearly always
A misspelt key
Do
Fix the key the message names