Make the docs state things rather than argue them
Docs / docs (push) Successful in 37s
Playwright Tests / test-playwright (1, 2) (push) Failing after 1m35s
Playwright Tests / test-playwright (2, 2) (push) Failing after 17s
pre-commit / pre-commit (push) Failing after 2m8s
Test Backend / test-backend (push) Failing after 2m48s
Compose Smoke Test / test-compose (push) Failing after 13s
Playwright Tests / merge-reports (push) Failing after 2m25s

The site read as a design journal: rationale paragraphs, hedges
("deliberately", "on purpose", "genuinely"), meta-commentary about the docs
themselves, and one em-dash every ten lines carrying an aside.

Roughly twenty rationale blocks are gone or reduced to what a reader needs
in order to use the thing. Em-dashes go from 507 to 135, and what is left is
structural rather than prose: list and definition separators, table cells,
and four inside code blocks that quote what the CLI actually prints.

Also: api.example.com becomes api.fluksio.com (the emails stay, since
bootstrap.py really defaults to admin@example.com and RFC 2606 reserves it);
the mqtt table gains the two settings it had drifted behind on and inject's
wording matches the engine; llms.txt lists the two connector pages that were
in the nav but not in it; and the two device/device_policy notes now agree.

Builds clean under `zensical build --strict`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
2026-08-31 10:49:58 +02:00
co-authored by Claude Opus 5
parent 2422a9b22b
commit bdad6d7fc2
25 changed files with 450 additions and 479 deletions
+13 -14
View File
@@ -20,11 +20,10 @@ the state backend, the work queue and the worker protocol unchanged.
| `str` | a string |
| `bool` | exactly `true` or `false` |
`bool` is an `int` subclass in Python and deliberately not a number here: a flag
is not a measurement, and a switch bound to a temperature is a mistake worth
catching.
`bool` is an `int` subclass in Python but is not a number here, so a switch
cannot bind to a temperature.
`NaN` and infinity are refused, wherever they sit including inside a `json`,
`NaN` and infinity are refused, wherever they sit, including inside a `json`,
`record`, `series` or `list`. JSON cannot spell either, so one that travelled
would come back as a response nobody can parse and a row the database rejects,
a long way from the node that made it. An empty subset or a division with no
@@ -43,8 +42,8 @@ Flat named scalars.
{"title": "Boiler", "body": "Pressure low", "severity": "warning"}
```
Nesting is deliberately out: a record that can contain a record is a schema
language, and the shape stops being readable from the declaration alone.
A record cannot contain a record, so its shape is readable from the declaration
alone.
Read by the **Notification** widget. It is also what an alert channel of kind
*dashboard* writes.
@@ -64,7 +63,7 @@ point.
### `series`
Labelled lines of `(timestamp, value)` pairs what a chart draws.
Labelled lines of `(timestamp, value)` pairs, which is what a chart draws.
```json
{
@@ -91,7 +90,7 @@ A reference to stored bytes.
{"digest": "sha256:…", "size": 4194304, "media_type": "application/octet-stream", "name": "weights.pt"}
```
Binary payloads tensors, checkpoints, images never travel as a message. The
Binary payloads (tensors, checkpoints, images) never travel as a message. The
bytes go to a content-addressed store and the message carries this. A
thirty-megabyte checkpoint never sits in the state backend, and the reference
stays valid wherever the store is reachable from, including on another machine.
@@ -110,14 +109,14 @@ The same reference, narrowed to a kind of media by its `media_type`.
An `audio` port takes `audio/*` and refuses anything else, so a speech
recogniser declares what it eats rather than taking any bytes at all and
finding out. An `artifact` port still accepts all three media narrows
finding out. An `artifact` port still accepts all three: media narrows
artifact, not the other way round.
`meta` is optional and nothing here reads it: sample rates, dimensions and
sequence numbers are for whoever consumes the media.
Bytes still never travel as a message. A camera publishes one reference per
frame and a microphone one per chunk which makes a media stream an ordinary
frame and a microphone one per chunk, which makes a media stream an ordinary
[streaming port](../concepts/flows.md#streaming-ports), and each frame an
artifact. What that costs is worth knowing before pointing a camera at it:
@@ -143,8 +142,8 @@ next author nothing.
## Naming a run's output
Any *run parameter* is also accepted as text, since nobody wants to paste an
object into a shell. `@run:<id>.<output>` names what an earlier run produced
whatever its type, an `artifact` reference or a `json` config alike — and a bare
object into a shell. `@run:<id>.<output>` names what an earlier run produced,
whatever its type, an `artifact` reference or a `json` config alike. A bare
`sha256:…` digest names content in the artifact store. Both resolve before the
run starts, so the CLI, the run dialog and a python caller all mean the same
thing by the same string.
@@ -171,8 +170,8 @@ Enforced on the server as well as in the editor.
A value that does not match its port's declaration raises on the node that
published it, naming the port and what arrived. It does not get published, and
it does not reach anything downstream — a wrong value stopping at its source is
much easier to diagnose than one propagating.
it does not reach anything downstream. A wrong value stopping at its source is
easier to diagnose than one propagating.
## See also