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
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:
@@ -1,7 +1,7 @@
|
||||
# The connector contract
|
||||
|
||||
A connector is the device-facing node class. It talks to something outside the
|
||||
engine — a device, a service, a protocol — and publishes what it finds as
|
||||
engine (a device, a service, a protocol) and publishes what it finds as
|
||||
ordinary typed messages, so the rest of a flow cannot tell the difference
|
||||
between a reading from a heat pump and one from a `print` statement.
|
||||
|
||||
@@ -75,7 +75,7 @@ class Params(ConnectorNode.Params):
|
||||
```
|
||||
|
||||
- Booleans render as switches, numbers and strings as inputs. Objects and
|
||||
arrays are not rendered — keep settings flat.
|
||||
arrays are not rendered, so keep settings flat.
|
||||
- A field carrying **`x-secret`** renders as a picker over the stored secrets
|
||||
and writes a reference, `{"$secret": "name"}`, rather than the value. The
|
||||
engine resolves it when the node is built, so a credential never lands in
|
||||
@@ -98,13 +98,13 @@ optional `interval`.
|
||||
at most that often. A connector should poll at the rate the device is
|
||||
comfortable with and leave delivery rates to whoever wires it up.
|
||||
- A key no port declares is an error, and it fails the whole reading rather
|
||||
than the one value — a mistyped metric name is how a training curve goes
|
||||
than the one value. A mistyped metric name is how a training curve goes
|
||||
missing.
|
||||
|
||||
### When the device decides what the ports are
|
||||
|
||||
A connector for a device whose readings vary by model — which components a
|
||||
relay has, which entities were flashed onto a board — cannot know its ports in
|
||||
A connector for a device whose readings vary by model (which components a
|
||||
relay has, which entities were flashed onto a board) cannot know its ports in
|
||||
advance, and returning everything the device reports would fail on the first
|
||||
value nobody bound. Narrow the reading to the ports that were declared:
|
||||
|
||||
@@ -115,7 +115,7 @@ return {port: value for port, value in reading.items() if port in declared}
|
||||
|
||||
`spec.port` is the local, unqualified name and stays that way for the node's
|
||||
whole life, so the set can be taken fresh each time. Say something in the log
|
||||
when a declared port is not one the device has — once, not once per poll: from
|
||||
when a declared port is not one the device has, once rather than once per poll: from
|
||||
the canvas a renamed entity and a typo look the same, and both leave a port
|
||||
silent forever.
|
||||
|
||||
@@ -131,7 +131,7 @@ async def poll(self) -> dict[str, Any] | None:
|
||||
- Return `None` when there is nothing new.
|
||||
- **Only changed values are published.** A device polled every few seconds
|
||||
usually says the same thing, and every publication wakes everything
|
||||
downstream, so the loop compares against what it last published — what it
|
||||
downstream, so the loop compares against what it last published, meaning what it
|
||||
actually published, so a publication that failed is retried next tick rather
|
||||
than counting as said.
|
||||
- Raising is not fatal: it is reported as a health problem and retried on the
|
||||
@@ -182,7 +182,7 @@ async def poll(self) -> dict[str, Any] | None:
|
||||
```
|
||||
|
||||
`save_artifact` stores the bytes and returns what an `image`, `audio` or
|
||||
`video` port carries — the media type has to match the port's type. It only
|
||||
`video` port carries: the media type has to match the port's type. It only
|
||||
works once the node has started, since the store is the engine's and is handed
|
||||
over then.
|
||||
|
||||
@@ -200,7 +200,7 @@ async def stop(self, app=None) -> None: ...
|
||||
|
||||
- `start` is called when the connector's flow starts, and after every rebuild.
|
||||
- `stop` is called before a rebuild and when the flow is stopped. **It must be
|
||||
idempotent** — it is called whether or not `start` succeeded.
|
||||
idempotent**: it is called whether or not `start` succeeded.
|
||||
- Overriding either means calling `super()` if the polling loop is also wanted.
|
||||
- The `app` argument is the FastAPI application, for the rare connector that
|
||||
needs to mount a route. Most ignore it.
|
||||
@@ -216,7 +216,7 @@ self.report_health("down", str(exc))
|
||||
```
|
||||
|
||||
Three values, `ok`, `degraded` and `down`, plus an optional detail string.
|
||||
Reporting the same status twice is free — only changes are published. A node
|
||||
Reporting the same status twice is free, since only changes are published. A node
|
||||
reporting `down` is named among its flow's issues and counted on the health
|
||||
summary on Home; `degraded` means still working, and is not. The polling loop
|
||||
already reports around `poll()`; a connector managing its own connection should
|
||||
|
||||
Reference in New Issue
Block a user