docs: record the structured-dtype and querying-chart decisions
Also the one the session settled by hand: database nodes stay transport and credentials, and the Python nodes either side do the query building and the answer shaping. That is what a series read mode inside the node would have prevented, so the read-mode item goes with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+22
-33
@@ -50,7 +50,6 @@ is what M4 still waits on, together with porting the flows.
|
||||
|
||||
- CHORE/API: revoking an OAuth client does not invalidate access tokens already issued; they are stateless JWTs valid up to `MCP_TOKEN_EXPIRE_MINUTES`. Immediate revocation means `app/mcp/http.py` checking the client row still exists.
|
||||
- CHORE/FLOW: `Pipeline.trigger`'s docstring says a paused flow still publishes so the value shows on the canvas. True only without a queue; with one the item parks before `apply_outputs` and nothing shows. Docstring and behaviour disagree.
|
||||
- CHORE/FLOW: `_to_messages` keeps its `if not retval: return None` guard ahead of the new type check, so a falsy non-dict return (`0`, `""`, `[]`) is still silently "no output" rather than the named error. Deliberate for now; worth a decision.
|
||||
- CHORE/FLOW: `WorkItem.kind == "node"` ("executes exactly one node") was documented but never implemented. If a run-one-node item is wanted, it still needs writing.
|
||||
- CHORE/API: `GET /observability/runs` caps at 200 rows, so pinning a minute busier than that on the Home chart shows its newest 200 with nothing saying more exist. Fine at ~60 runs/min; a count alongside the rows, or paging, is what a busier instance needs.
|
||||
|
||||
@@ -97,28 +96,27 @@ Decisions taken up front, because most items below depend on them:
|
||||
- A chart asks a flow for its series the way every other input widget speaks:
|
||||
it publishes a request message and reads the answer. No query API, no
|
||||
database knowledge in the widget.
|
||||
- Database nodes are transport and credentials only. The InfluxDB node runs the
|
||||
Flux it is handed and echoes back every other field of the request; building
|
||||
the query and shaping the answer are Python nodes either side of it. That is
|
||||
what keeps a widget ignorant of the database, and it is also what a series
|
||||
read mode inside the node would have prevented. A "grouped nodes" concept
|
||||
could later package the standard chart→build→db→parse→chart quintet so a
|
||||
dashboard is not five nodes of wiring each time.
|
||||
- Nothing e-ink-specific in the widgets. Panel access is a credential problem
|
||||
(see below); the display's demands are a rendering profile, deferred.
|
||||
|
||||
- !FEAT/FLOW: declared structured dtypes — `series` (labelled ts/value pairs),
|
||||
`record` (flat named scalars) and `list` (ordered items of a declared shape) in
|
||||
`DType`, checked like the scalars are, with `WIDGET_DTYPES` extended so a
|
||||
widget binds a shape rather than "some JSON". Everything a single number can
|
||||
say stays a `float`/`bool` message. Prerequisite for the agenda, forecast,
|
||||
notification and queried-chart widgets.
|
||||
- !FEAT/UI+FLOW: charts that query. A chart owns a refresh interval, publishes a
|
||||
request message (range, interval) exactly as a slider publishes a value, and
|
||||
draws the `series` message a data node answers with. The answer carries the
|
||||
range and interval it was computed for and the widget ignores one that does not
|
||||
match its request — otherwise two charts, or two panels, on the same node
|
||||
overwrite each other's window. Costs a duplicate query rather than a wrong
|
||||
chart. Needs a floor under the interval and dedup of identical in-flight
|
||||
requests. The alternative — a message name per widget — would mean dynamic
|
||||
names in a namespace that is deliberately static. Overall idea is that visualization and data stays separate. The widget can make a query to an influx db node (with some python function in front of it to prepare the query) and the node then feeds the answer back to the widget (again with some python function to parse the response). This makes the widget agnostic of any database type
|
||||
- FEAT/NODE: a series read mode for the InfluxDB node: return the whole
|
||||
aggregated window (`aggregateWindow`, function and interval from the request)
|
||||
as one `series` message, instead of the single aggregated scalar it produces
|
||||
now. This is what the environment, power and server pages are made of.
|
||||
- FEAT/UI: assemble the range-aware demo dashboard now that charts can query —
|
||||
an InfluxDB node behind a build/parse pair, with the panel's own range picker
|
||||
governing the window. The pieces are in and verified against a real bucket;
|
||||
what is missing is a dashboard someone would actually hang.
|
||||
- CHORE/UI: identical in-flight chart requests are deduplicated per browser tab,
|
||||
so two wall panels showing the same tile still run the query twice. An
|
||||
`interval` on the request port is the backstop, and it belongs to the flow
|
||||
serving the request rather than to the widget asking.
|
||||
- CHORE/FLOW: one request/answer pair per InfluxDB node — the first input
|
||||
carrying a `flux` key is the request and the answer leaves on the first output
|
||||
port. A second query stream through one node needs a second node.
|
||||
- FEAT/UI: bar/level widget — a horizontal bar with its value written on it, and
|
||||
a nested bar for a quantity contained in another (PV inside inverter input).
|
||||
The arc gauge is the only level display today.
|
||||
@@ -129,20 +127,13 @@ Decisions taken up front, because most items below depend on them:
|
||||
- FEAT/UI: icon-by-value widget — a mapping from value or range to a lucide icon
|
||||
and a colour token. Carries both the weather condition icon and derived hints
|
||||
such as "indoor dewpoint above outdoor, open a window".
|
||||
- FEAT/UI: agenda widget over a `list` message — the next N items with relative
|
||||
day labels ("Today", "Tomorrow", weekday, then date) and truncated titles.
|
||||
- FEAT/UI: forecast strip widget over a `list` message — N columns of label,
|
||||
icon and value, with the later columns drawn progressively dimmer.
|
||||
- FEAT/UI: notification widget — title and body from a `record` message, held
|
||||
until replaced. Worth wiring to the alerting events rather than a message of
|
||||
its own.
|
||||
- FEAT/UI: clock widget — local time and date, bound to nothing.
|
||||
- FEAT/UI: chart presentation — axis titles, a unit, an optional fixed y range,
|
||||
and the per-series label the document already stores but the editor never
|
||||
offers.
|
||||
- FEAT/UI: the slider panel exposes only min and max; the renderer already reads
|
||||
`step` and `unit`. Add those plus tick marks (a 20–22 °C setpoint at 0.1 is
|
||||
unusable without them).
|
||||
- FEAT/UI: chart axis titles. The unit, the fixed y range and the per-series
|
||||
label are in; a named axis is not.
|
||||
- FEAT/UI: the slider offers `step` now, but no tick labels — the `datalist`
|
||||
marks are unlabelled and drop out past fifty steps.
|
||||
- FEAT/API: a kiosk credential for `/view/{name}`, so a panel is not a
|
||||
logged-in browser session. Note it cannot be strictly read-only: a querying
|
||||
chart publishes its request, so the token needs that one write scope.
|
||||
@@ -172,7 +163,6 @@ as an em dash.
|
||||
- FEAT/UI: only `layout.lg` is ever written. Below `lg` the view stacks widgets full width in CSS, so `md`/`sm` stay unused until a per-breakpoint editor exists.
|
||||
- PERF/UI: `ChartWidget` re-joins the whole table on every live value. Fine at IoT rates; at `HISTORY_CAP` × 5 series it should append into a ring buffer.
|
||||
- CHORE/UI: opening edit mode on a dashboard whose widgets predate placement writes the migrated positions immediately, bumping the version once.
|
||||
- CHORE/API: no backend test for the `WidgetDef` dtype validator or `columns`.
|
||||
- FEAT/UI: `POST /dashboards/{name}/discard` has no button. The flow settings panel offers "discard draft"; the dashboard settings panel does not, so an unwanted edit can only be undone by hand or by publishing it.
|
||||
- CHORE/API: creating a dashboard publishes it straight away (an empty document goes to the panels), while a new flow starts as a draft. Keeps `read`/`list` free of a never-published case, at the cost of the asymmetry.
|
||||
- PERF/UI: "Publish all" reads each document's detail for the version its publish must match, so a click is 2N requests. A bulk endpoint, or a `version` on the summaries, would make it one.
|
||||
@@ -217,7 +207,6 @@ Open on purpose. Each names what should bring it back.
|
||||
- CHORE/INFRA: `bun run --filter frontend build` fails on this workspace with `crypto.hash is not a function` — Vite 7 wants Node 20.12+ and the host has 18. The Docker image builds fine, so it only bites local bundling; `bunx tsc` still type-checks.
|
||||
- FEAT/UI: an endpoint's edge routes straight across the graph, so it can pass behind a node that sits between the lane and the node it wires to. Readable, but a routed edge would be tidier.
|
||||
- FEAT/UI: the node-panel and edge trend curves take no range, unlike the health block. They are drawn from a Redis ring of the last 120 values per message, which has no window to ask for — a hover caption names what the curve covers instead of a picker promising a span nothing can serve. Reopen if per-message history ever gains a time window.
|
||||
- FEAT/UI: a dashboard that demonstrates the time range concept, with an InfluxDB node as its data source. The range picker governs the health block, which is backed by minute rollups; a dashboard chart draws a message's 120-sample ring, and the InfluxDB node answers a query as one aggregated scalar over a `query_range` fixed in its params. So a range-aware dashboard chart is the *charts that query* item under wall-panel parity — the `series` dtype, the chart publishing its request, and an InfluxDB series read mode — not a dashboard anyone can assemble today. Reopen with that work.
|
||||
- FEAT/UI: an e-ink rendering profile for a dashboard — motion off, hover-only affordances resolved to something visible, high-contrast palette, thick strokes, and a repaint cadence low enough for a display that takes a second to settle. Reopen when a panel with such a display is actually hung.
|
||||
- CHORE/INFRA: Postgres stays. The 2026-08 review rejected YugabyteDB/CockroachDB (multi-node cluster systems, ~4 GB+ RAM per node, against the small-server target — the scaling story is remote workers, not a distributed DB) and found merging Postgres into Redis or vice versa buys little: the stores hold disjoint data and both sit behind abstractions. SQLite would fit the single-instance design and drop a container; reopen if the home-install footprint becomes a product concern.
|
||||
- CHORE/INFRA: NATS JetStream as the work-queue backend — durable streams whose consumer semantics match the `WorkQueue` interface, in one small binary. Reopen with M5 remote workers, when the queue crosses hosts.
|
||||
|
||||
Reference in New Issue
Block a user