From 30cb8a81fe8bde2ea7431f23acb262c4ff6af361 Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 18:02:39 -0400 Subject: [PATCH 1/9] docs: document the core performance and Atlas Topology candidate --- docs/performance-release-candidate.md | 169 ++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 docs/performance-release-candidate.md diff --git a/docs/performance-release-candidate.md b/docs/performance-release-candidate.md new file mode 100644 index 0000000..f364e59 --- /dev/null +++ b/docs/performance-release-candidate.md @@ -0,0 +1,169 @@ +# Core performance and Atlas/Topology candidate + +Review this as a paired server/web candidate before promoting it from `dev` or +`dev1` to a stable release. The collected-telemetry intake, mobile collection and +Atlas sensor cards are a separate dependent change. Basic Atlas and Topology do +not require that optional service. + +## What the core changes + +| Area | Result | +| --- | --- | +| Database baseline | Retains current upstream bigint cursors, exact pagination, workload pools, route/index cleanup, regional read models and trust/recovery rules | +| First-fill work | Preserves duty pacing while bounding individual boot writes, serializing their disk work and retrying smaller ranges on statement pressure | +| Channel history | HTTP/MQTT startup no longer waits for a full historical decrypt scan. A scheduled job scans at most 500 primary-key candidates per tick, within a five-second work context, saving its cursor after successful work | +| Imported channel keys | A changed key-set fingerprint restarts the resumable history pass. Metadata changes alone do not start another scan. Backfilled messages remain historical and are not broadcast as new chat | +| Cache outage | Concurrent misses and Redis read failures share bounded database work. A canceled caller can leave without canceling useful work for other callers. Cache operations have short network deadlines and no internal retry multiplication | +| Signal quality | Missing, malformed, non-finite or out-of-range RSSI/SNR remain absent. Measured zero is retained. Stored observations, neighbor evidence and live events use the same validity distinction | +| Input work | Oversized MQTT envelopes/topics and oversized neighbor snapshots are rejected before expensive processing | +| Live stream | Control-message rates, filter lengths and active subscriptions are bounded. Every socket write has a deadline. Global queue gaps notify clients and have counters, alongside existing slow-client gaps | +| Topology | Keeps indexed minute-window route snapshots, exact node cursors, quality labels and live Public chatter. Query-plan fixtures cover global/regional windows. Animated segment geometry is reused between frames and invalidated when the camera moves | +| API failures | JSON is encoded before success is committed; known temporary query failures use the common 503/Retry-After contract | +| Provenance | `/info` keeps its API-version meaning and adds optional `buildVersion` and `buildRevision` for the actual artifact | +| Runtime image | Moves off Alpine 3.19, keeps the PostgreSQL 16 client and runs the app as UID/GID 65532 | + +The history scan advances through all packet candidates, including pages without +undecrypted group text. That bounds database work rather than merely limiting +the number of matches returned. A failed page leaves its cursor unchanged; +idempotent message inserts make a retry safe. A completed pass is restored after +restart. Existing live ingest decrypts newly received messages. This job is +disabled in read-only server mode. + +The core has no new database migration beyond the current 001-053 baseline. +It adds a `channel_history` entry to the existing `background_state` table. +It does not delete raw observations, rewrite old signal readings, change +retention or initiate RF traffic. + +## Configure the deployment deliberately + +### Cache + +Set `REDIS_ADDR` in the app environment; a running Redis container and YAML TTLs +alone do not activate the reader cache. Give Redis a memory bound and an eviction +policy suitable for a disposable cache. Start with short TTLs for live-facing +data and longer reference-data TTLs, then measure freshness and hit rate: + +```yaml +cache: + ttl: 30s + ttls: + stats: 30s + reference: 5m + nodes: 30s + observers: 30s +``` + +Keep ingestion invalidation and outage tests in the acceptance run. Do not +silently apply a one-hour status TTL from an older configuration. + +### Pools and first fills + +The default `custom_all` layout has eight API connections, two slow connections, +four maintenance connections and at least six ingest connections (one per CPU +when there are more than six CPUs). The split layout adds four API connections. +A `pool_max_conns` DSN parameter does not cap their combined total. + +Reserve PostgreSQL capacity for every app instance, optional intake, backups, +migrations and operator sessions. On shared storage use the supported fill +pacing controls, for example: + +```yaml +readmodels: + fill: + duty: 0.25 + packet_sites_slice: 100000 +``` + +Connection separation does not isolate disk/WAL bandwidth. Observe ordinary +API latency and ingestion lag during a fill. Keep read-model trust checks; +temporary 503s are preferable to presenting incomplete regional history as +complete. + +### Private measurements + +Enable `server.admin_listen` only on a listener reachable through a private +network or a loopback-bound container port. Do not add `/metrics` to the public +reverse proxy. Scrape the existing metrics and the additional bounded series: + +| Metric | Meaning | +| --- | --- | +| `beacon_cache_requests_total{outcome}` | Hit, miss, invalid cached value or read error | +| `beacon_ingest_rejected_total{reason}` | Input rejected for a bounded shape/size reason | +| `beacon_stream_dropped_total{queue}` | Global, per-client or best-effort repeat event drops | +| `beacon_channel_history_scanned_total` | Packet candidates examined by resumable historical decryption | +| `beacon_job_rows_total{job="channel_history"}` | Newly decrypted historical messages, distinct from scanned candidates | + +Also monitor the existing pool waits, statement families, queue depth/drops, +read-model trust/age and job durations. PostgreSQL `pg_stat_statements` requires +the preload library and a planned database restart as well as the extension. +Measure `track_io_timing` overhead before enabling it broadly. Preserve reset +timestamps when comparing counters. Never expose raw query values or message +contents in metric labels. + +### File ownership and privileges + +The candidate image runs as `65532:65532`. Before updating, check mounted +configuration, borders and any enabled backup/export directories. Configuration +must be readable by that user; directories the application must write need +explicit ownership/permissions. Keep secrets private and preserve a rollback +copy. Do not make all mounts world-writable to work around an ownership error. + +Database privilege separation is a distinct operator task. The existing normal +boot/maintenance path performs schema/index work, so replacing its superuser +with a DML-only role without a migration/maintenance ownership design is not a +qualified deployment. Test the intended role model on a restored copy. The +candidate does not automatically revoke roles or edit production credentials. + +## Preserve honest data contracts + +- Raw observations, unique stored packets, broker reports and radio counters + have different grains. Keep their labels and reset/window semantics distinct. +- A missing signal is not zero. Clients must tolerate absent `rssi`/`snr` in live + observation events, just as retained observations can have missing readings. +- Prefix matches and plausible geography are not proof of a physical route. + Keep TRACE warnings, original wire values and the optional questionable-evidence + view. Unvisited requested hops must not become observed edges. +- Topology gaps are notices to refresh/reconcile authoritative state. A healthy + WebSocket and QoS1 subscription do not establish lossless persisted ingestion. +- Atlas's recent-report chart is a labeled sample, not a complete lifetime or + 24-hour total. Optional telemetry must not be required for basic cards. + +## Qualify the exact paired candidate + +1. Record server/web revisions, trees, config hash, schema journal and artifact + hashes. A source branch or container tag alone is insufficient provenance. +2. Run build, vet, unit/race tests, PostgreSQL integration, plan policy/corpus, + backup checks, and web lint/tests/build against the combined heads. Test + signal null/zero, interrupted history pages, cache failure/cancellation, + stream control limits/global gaps and Topology exact boundaries. +3. Use separate disposable databases for functional tests and the large plan + fixture. Concurrent index creation can wait for older snapshots even when + another fixture is loading different tables in the same database. +4. Rehearse 2.0.x-to-2.1 migration/recovery on a representative restored copy. + See [Upgrading](upgrading.md). Schema 053 is not compatible with an image-only + rollback to an older application expecting the removed route stamp. +5. Exercise global/regional packet/message pages, observer comparisons, saved + Atlas cards, Topology 15m/1h/24h, TRACE evidence and live reconnection. Test + cold and warm caches separately and preserve camera state during refresh. +6. Record a maintenance-cycle soak with API latency, input acceptance/lag, + database WAL/temp work and model trust together. Synthetic plan checks are + not a production throughput benchmark. + +A read-only audit of the prior preview measured a 24h snapshot at about four +seconds cold and tens of milliseconds for the same cached window. This is a +baseline, not a promised universal latency or an FPS measurement. The updated +renderer keeps moving cores, glow and chatter while avoiding repeat geometry +work; test on the intended devices before claiming an interaction/FPS gain. + +## Keep optional collection separate + +The telemetry draft stack adds companion enrollment/collection, optional intake +proxy/history/availability and sensor cards. Its mobile and headless clients +must use a shared receipt and RF-budget contract. A signed companion challenge +is key-possession evidence, not hardware attestation or proof that a report is +truthful. Completing that optional stack is not a reason to delay a verified +standalone bigint or backend reliability fix. + +Production rollout, final acceptance, workload-specific SLOs, an off-host +restore/RPO/RTO drill, and physical mobile overnight collection remain explicit +release gates. A draft PR or successful CI run does not close those gates. From 1eeb69dfda9e03f7f2b87a9914c6b824368a53a5 Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 18:04:10 -0400 Subject: [PATCH 2/9] docs: link the paired performance candidate handoff --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d6231b4..35bb921 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ This repo is where you deploy and operate it. The code lives in [beacon-server](https://github.com/MeshCore-Beacon/beacon-server) (the API and ingest) and [beacon-web](https://github.com/MeshCore-Beacon/beacon-web) (the frontend). +The proposed paired backend, basic Atlas and Topology release is described in +[Core performance candidate](docs/performance-release-candidate.md), including +validation, operational budgets and remaining release gates. + > **Coming from 1.x?** 2.0.0 needs a fresh database and a few config changes. Read > [Upgrading](docs/upgrading.md) before you pull new images. From 4ae4b723072860815ef9c1cb83c7e9ea4ef10c8d Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 19:01:43 -0400 Subject: [PATCH 3/9] docs: separate optional mobile collection and intake from core --- README.md | 2 + docs/telemetry-collection.md | 138 +++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 docs/telemetry-collection.md diff --git a/README.md b/README.md index 35bb921..6fd7969 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ This repo is where you deploy and operate it. The code lives in The proposed paired backend, basic Atlas and Topology release is described in [Core performance candidate](docs/performance-release-candidate.md), including validation, operational budgets and remaining release gates. +The separate [optional collection guide](docs/telemetry-collection.md) covers +mobile/headless clients, intake, sensor cards and their qualification gates. > **Coming from 1.x?** 2.0.0 needs a fresh database and a few config changes. Read > [Upgrading](docs/upgrading.md) before you pull new images. diff --git a/docs/telemetry-collection.md b/docs/telemetry-collection.md new file mode 100644 index 0000000..3c00b88 --- /dev/null +++ b/docs/telemetry-collection.md @@ -0,0 +1,138 @@ +# Optional companion telemetry collection + +Enable this alongside the core performance, basic Atlas and Topology candidate +only when the intake service and client qualification are ready. Basic Atlas, +Topology and ordinary observer telemetry continue to work without it. + +## Components + +| Component | Responsibility | +| --- | --- | +| Beacon Flutter app | User-selected BLE or Wi-Fi/TCP companion, saved repeater selection, optional local password/admin requirement, polling budgets and signed delivery | +| Beacon server | Optional bounded proxy and `/info` capability for the selected instance | +| Telemetry intake | Automatic enrollment validation, sample validation/deduplication, quotas, separate storage, retention, history and availability | +| Beacon web | Repeaters-with-telemetry filter, attributed battery/environmental series and explicit gaps/partial history | +| Headless Collector | Alternate polling client for unattended USB/BLE use; it uses the same intake contract | + +The app replaces the user-operated polling client, not the intake/storage service. +The current intake is packaged in the separate Collector project. The org +`beacon-agent` scaffold is not a deployable replacement for that implementation. +Software distribution/access for the alpha is separate from client enrollment: +there is no per-user operator approval list. + +## Enable an instance + +Run intake with its own PostgreSQL database. Its canonical `COLLECTOR_INSTANCE` +must equal the HTTPS Beacon URL the app selects, including any installation +subpath and excluding a trailing slash, query string or credentials. A session +issued for the Canadaverse preview is not a session for another Beacon instance. + +Point the optional server setting at the intake over the private service network: + +```yaml +node_telemetry: + gateway_url: http://collector:8081 +``` + +Replace `collector` with that deployment's actual private service hostname. The +public client uses the Beacon instance's existing HTTPS API. The core proxy +accepts only the enrollment/report/read routes, bounds bodies/responses/deadlines, +does not follow redirects and does not forward caller cookies or authorization +headers. Set the intake's trusted proxy CIDR to the core app's actual private +peer address; never trust a caller-provided forwarding header unconditionally. + +When configured, `/api/v1/info` includes `collectedNodeTelemetry: true`. This is +a capability statement, not an assertion that every companion or sensor is +currently healthy. If intake is disabled, optional history is unavailable and +basic cards still work. A configured service failure must remain a visible, +retryable error rather than an empty successful collection. + +## Client workflow + +In the app, select the Beacon instance, open Telemetry sharing, connect the +companion, choose saved repeaters and an interval from 1 to 72 hours. Optional +repeater/admin passwords stay on the client. The companion private key is never +exported. First use starts with flood discovery; subsequently learned routes are +used within the client's hop/congestion policy. Environmental decoding preserves +channel numbers, including channel 2, and explicit zero values. + +The mobile client reserves attempts before transmitting, applies a shared +two-attempt/six-command hourly companion budget and checks airtime/queue state. +An interval is a minimum; selecting more nodes can make the effective interval +longer. Upload retries resend the same saved report and do not poll again. +There is no automatic burst to catch up missed RF intervals. + +For Android, background collection is an explicit remembered choice. The +connected-device service has an ongoing notification with Stop/Disconnect +actions and optional counts. Expired saved reports are counted separately from +accepted reports. Loss of the connection/process stops collection; a foreground +service is not an exact-time or uninterrupted-work guarantee. iOS collection is +foreground-only in this draft. + +No global cross-instance RF lease or hardware attestation is claimed. Cooperating +clients still need coordination before a broad rollout. The server validates +key possession and report structure; public data remains attributed community +measurements rather than independently verified sensor truth. + +## HTTP and MQTT acceptance + +The version-1 routes are under `/api/v1/node-telemetry`: + +| Method/path | Contract | +| --- | --- | +| POST `/challenge` | Short-lived instance/radio/client-bound challenge | +| POST `/enroll` | Both companion and client sign the prefixed challenge; returns an intake session | +| POST `/reports` | Validates the signed sample and returns acceptance only after storage/deduplication | +| GET `/availability` | Full node keys with retained data, 30-day retention and explicit directory truncation | +| GET `/{full-public-key}` | At most 500 retained samples, chronological output, cap/coverage metadata | + +Sample IDs are idempotent only for identical validated samples. A reused ID with +different data is rejected. Session secrets currently rotate when intake restarts; +clients re-enroll and retry the same queued sample, preserving RF cooldowns. + +The app uses HTTPS. The headless client's optional MQTT publish is followed by +idempotent HTTPS confirmation of the same signed sample. Broker PUBACK alone +does not remove the outbox. This protects against an unavailable consumer or an +intake rejection without adding an RF request. MQTT still needs the existing +enrollment API and appropriate topic/TLS credentials. + +## History, capacity and retention + +History responses include `limit`, `truncated`, `retentionDays`, `windowStart` +and `windowEnd`. A cap is not a complete 30-day history. The web labels partial +history and keeps missing measurements distinct from zero; dashed bridges are +visual estimates, not new samples. Full node keys separate identities and +collector/radio attribution keeps different sources from silently joining. + +Availability is coalesced and cached for at most a minute, invalidated by new +accepted reports and retention maintenance. Concurrent first reads share one +bounded aggregation. Default intake pool capacity is four connections unless an +operator explicitly overrides it; budget these alongside core pools. + +Retention runs in short minute-spaced passes, with a five-second context and at +most four indexed batches of 5,000 expired rows. Monitor the oldest retained +timestamp/backlog on larger deployments. The separate +`collector_schema_migrations` ledger records intake initialization; it is not a +core Beacon migration. Keep core and intake backup/recovery identities distinct. + +## Qualification and deployment gates + +Use the exact paired optional server/web commits above the accepted core stack, +the matching app branch and the identified intake build. Do not merge an older +telemetry PR wholesale over newer config, read-model or virtualization changes. + +Validate signatures, instance binding, null/range handling, replay/different-data +IDs, concurrent quotas, expiry, history/directory caps, cache invalidation and +outage recovery on an isolated database. Synthetic signed samples belong in that +isolated test instance, not in the shared preview's public repeater history. + +Then verify the preview's actual retained data, API proxy, web filter/cards and +normal collector acceptance without resetting RF cooldowns. Preserve the +exclusive radio lease and unrelated services during updates. Check before/after +source/binary/asset hashes, database/configuration identity and recovery copies. + +Physical qualification remains separate: a real selected companion/repeater, +status plus channel-2 readings, intake acceptance, matching Atlas display, locked +screen intervals, notification actions and transport/network failure. The current +consolidation found no Android device attached, so these new physical runs are +not claimed. Build/unit/API success does not replace them. From 65bb9ec5cb1a8bc2560976c60a23a0d092ec79f8 Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 19:10:42 -0400 Subject: [PATCH 4/9] docs: include intake route prefix in gateway configuration --- docs/telemetry-collection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/telemetry-collection.md b/docs/telemetry-collection.md index 3c00b88..dc3e9ce 100644 --- a/docs/telemetry-collection.md +++ b/docs/telemetry-collection.md @@ -31,7 +31,7 @@ Point the optional server setting at the intake over the private service network ```yaml node_telemetry: - gateway_url: http://collector:8081 + gateway_url: http://collector:8081/api/v1/node-telemetry ``` Replace `collector` with that deployment's actual private service hostname. The From 965e69714c310f213086a9955c4932925234bb7e Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 19:40:32 -0400 Subject: [PATCH 5/9] docs: record candidate qualification and remaining release gates --- docs/release-qualification-20261021.md | 113 +++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 docs/release-qualification-20261021.md diff --git a/docs/release-qualification-20261021.md b/docs/release-qualification-20261021.md new file mode 100644 index 0000000..13c7040 --- /dev/null +++ b/docs/release-qualification-20261021.md @@ -0,0 +1,113 @@ +# Candidate qualification, 21 October 2026 + +The core backend, basic Atlas and animated Topology candidate has a separate +optional telemetry layer. All org PRs remain drafts. Only the Canadaverse preview +was deployed; this record is not production acceptance or a dev/dev1 deployment. + +| Layer | Server dev / dev1 | Web dev / dev1 | Documentation | +| --- | --- | --- | --- | +| Core | [266](https://github.com/MeshCore-Beacon/beacon-server/pull/266) / [267](https://github.com/MeshCore-Beacon/beacon-server/pull/267) | [182](https://github.com/MeshCore-Beacon/beacon-web/pull/182) / [183](https://github.com/MeshCore-Beacon/beacon-web/pull/183) | [43](https://github.com/MeshCore-Beacon/beacon-docs/pull/43) | +| Optional collection | [268](https://github.com/MeshCore-Beacon/beacon-server/pull/268) / [269](https://github.com/MeshCore-Beacon/beacon-server/pull/269) | [184](https://github.com/MeshCore-Beacon/beacon-web/pull/184) / [185](https://github.com/MeshCore-Beacon/beacon-web/pull/185) | [44](https://github.com/MeshCore-Beacon/beacon-docs/pull/44) | + +The optional branches include core ancestry until the core is accepted. Review +their optional-only difference against `codex/release-core-20261021`, then +refresh them after core acceptance. Do not independently merge both the old +focused implementations and these consolidations. Flutter [draft 11](https://github.com/MeshCore-Beacon/beacon-flutter-app/pull/11) +targets its canonical dev branch; the app has no upstream dev1 branch. + +## Source and deployment identity + +Current upstream dev is included: server `080141145e964945d3f105be01903b082ebbfd8b`, +web `811f8430ea7eea0a556068904e71a43e07ac93f7` and app +`a8107047f52da43f8b30afb98655bc4452b7a74e`. + +The preview combines core/optional source with its existing preview UI and +route-evidence extensions. Server is `fdae02d4b7c501264280995d145bfe529b9e0d2f` +and web is `79edb9ce26a8eda0764b32de6545d1d486afa98b`, labelled +`2.5.0-n30nex.1`. The server API version remains 2.1.0; the separate `/info` +build fields identify the binary. App is `1f704187a94ea5c84c458a5d63ab8c0a4fdef525`, +version 2.1.0+3. Intake and headless client retain a separate private lifecycle. + +[Public preview](https://canadaverse.org/beacon-dev/), +[build manifest](https://canadaverse.org/beacon-dev/build.json) and +[Changelog/source archives](https://canadaverse.org/beacon-dev/source.html) +identify the running preview. The server/web minimum versions and optional +capability remain distinct from health and release acceptance. + +Artifacts were built locally from exact clean commits qualified by native CI; +Actions artifact uploads are unavailable for this account. These are preview +artifacts, not Actions-produced stable releases. The ARM64 runtime uses the +qualified Alpine 3.22.6/PG16 stage and UID/GID 65532. Original private addresses, +proxy trust and container limits remain intact. No source credential was added. + +## Checks completed + +- Core server build/vet/unit and native PostgreSQL, race, vulnerability and + runtime-image checks passed. The query-plan fixture corpus has 692 cases: + 680 ordinary passes, 11 deliberately planted regressions detected, one + existing skip. All eight added Topology/history cases pass. +- Basic web passed 1,512 tests in 164 files. Combined preview web passed 1,555 + tests in 171 files on native Linux CI, plus build/lint. Two existing React + Compiler warnings remain. Initial merged chart-test assumptions were fixed; + Windows shell-entrypoint cases are covered by Linux CI. +- Both private preview databases were backed up and restored off-host. Core + retained schema 53. New intake initialization preserved all 951 restored + reports and added its separate ledger. No database reset or historical + signal rewrite was performed. +- All 34 public assets and both source archives matched. Both MQTT brokers + connected. A 12-second WebSocket sample received 70 packet observations with + valid hello/subscription and no parse error in that sample. +- Public contract checks verified an instance-bound challenge, rejection of + invalid enrollment signatures and unenrolled reports, six retained histories, + coverage/cap metadata and channel-2 values. No accepted synthetic report or + RF test request was generated by these checks. +- Browser checks confirmed four saved Atlas cards, bright gap-aware histories, + the six-node telemetry filter and live 24-hour Topology with 5,362 loaded + nodes and 15,248 connections at the sampled moment. Node/edge counts change + with the live dataset. +- App analyzer and 347 Flutter tests passed. Org/fork Android builds and five + native telemetry-service tests passed. The local debug APK signature and + package were verified: `meshcorebeacon.app.telemetry`, version 2.1.0+3, + Android API 24 minimum and 36 target. +- The headless worker was updated with its schedule, configuration, private + credentials and radio path preserved. RemoteTerm remains suspended. Its + post-update journal reported `not_due`; no forced poll or fresh worker + acceptance is claimed. + +Native CI evidence: [server](https://github.com/n30nex/beacon-server-contributions/actions/runs/39692021754), +[web](https://github.com/n30nex/beacon-web-contributions/actions/runs/39692465604), +[Android fork](https://github.com/n30nex/beacon-flutter-app/actions/runs/39689785160). + +## Measured limits and remaining gates + +Cold global Topology still needs optimization qualification. One public cold +24-hour request took 13.877 seconds, then 0.336 seconds cached. A later local +Pi check crossed a minute boundary and measured 5.8027 and 5.2405 seconds for +two different cold snapshots, followed by a same-window cache hit in 0.0316 +seconds. The new historical-decryption job was progressing; CMI and packet-sites +were complete. These are individual shared-host samples, not p95 or FPS claims. + +Path deduplication before edge expansion returned identical edge sets on the +restored dataset, but showed no consistent warm speedup. That query change was +not shipped. Measure query-family cost and cache occupancy before choosing a +bounded shared snapshot/precomputation model. Preserve explicit as-of/window +metadata and exact expiry semantics; avoid per-browser pagination fanout. + +Private metrics/statement/IO instrumentation and scrapes, whole-host pool/memory +budgets, least-privilege migration/runtime roles, broker-to-database replay and +durability, production RPO/RTO and a full maintenance-cycle soak remain explicit +operator/design work. Sender-time versus receipt-time policy and bounded Atlas +summary/downsampling contracts also remain follow-ups. The current patch does +not make these guarantees by adding counters or passing fixture tests. + +No Android debugging device was available for this revision. Fresh physical +BLE/Wi-Fi, screen-off/unlock/reconnect, notification controls, mobile RF-to-intake +upload and overnight qualification remain pending. Keep the app draft. A +cross-client RF coordination policy is also needed before broad mobile/headless +coexistence; signed enrollment is not hardware attestation or sensor truth. + +Promote core before optional collection. Rehearse against the actual target +schema/config/roles, deploy a paired immutable candidate to authorized dev/dev1, +and qualify the remaining workload/recovery gates before operators approve a +stable live release. Retained preview recovery copies do not authorize a +database restore over new traffic or a production deployment. From b221d58a31e4dd1fce4818d421eccd34da9bc8a2 Mon Sep 17 00:00:00 2001 From: n30nex Date: Wed, 21 Oct 2026 19:41:31 -0400 Subject: [PATCH 6/9] docs: link the paired qualification record --- docs/performance-release-candidate.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/performance-release-candidate.md b/docs/performance-release-candidate.md index f364e59..db1d177 100644 --- a/docs/performance-release-candidate.md +++ b/docs/performance-release-candidate.md @@ -5,6 +5,9 @@ Review this as a paired server/web candidate before promoting it from `dev` or Atlas sensor cards are a separate dependent change. Basic Atlas and Topology do not require that optional service. +See the [21 October qualification record](release-qualification-20261021.md) +for the paired drafts, exact preview build, measurements and remaining gates. + ## What the core changes | Area | Result | From 88478ea8764be5402ab0812729fb2cfc1fa57759 Mon Sep 17 00:00:00 2001 From: n30nex Date: Fri, 23 Oct 2026 19:22:22 -0400 Subject: [PATCH 7/9] docs: consolidate project roadmap and bound deployment logs --- CONTRIBUTING.md | 12 +- README.md | 3 + docker-deployment-type1/docker-compose.yml | 11 + .../server/docker-compose.yml | 10 + .../web/docker-compose.yml | 8 + docs/project-roadmap.md | 224 ++++++++++++++++++ 6 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 docs/project-roadmap.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e857619..7ced491 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to Beacon -Thank you for your interest in contributing. This page is the shared workflow for all three -Beacon repositories: +Thank you for your interest in contributing. This page is the shared workflow for the +Beacon application and documentation repositories: - [beacon-docs](https://github.com/MeshCore-Beacon/beacon-docs), this repo: deployment, configuration and operator documentation. @@ -11,6 +11,8 @@ Beacon repositories: - [beacon-web](https://github.com/MeshCore-Beacon/beacon-web): the frontend. Its own [CONTRIBUTING.md](https://github.com/MeshCore-Beacon/beacon-web/blob/main/CONTRIBUTING.md) covers TypeScript style, tests and the feature layout. +- [beacon-flutter-app](https://github.com/MeshCore-Beacon/beacon-flutter-app): the canonical + Android and iOS client. Use its mobile build and device qualification instructions. Please read this before opening a PR anywhere. @@ -18,9 +20,9 @@ Please read this before opening a PR anywhere. **Talk first for anything bigger than a small fix.** On beacon-server and beacon-web, open or comment on an issue before starting work, so maintainers can say if something is already in -progress or out of scope. Issues are disabled on beacon-docs; for a docs restructure, a new -deployment type or a correction you are unsure about, reach out on the -[MeshCore Canada Discord](https://discord.gg/Gz3KvJx2hf). For typos, broken links and small +progress or out of scope. For a docs restructure, a new deployment type or a correction +you are unsure about, open an issue in beacon-docs and link any affected application issues. +For typos, broken links and small clarifications, just open a PR. **One thing per PR.** Each pull request covers one logical change: a bug fix, a new endpoint, a diff --git a/README.md b/README.md index 35bb921..6139272 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ This repo is where you deploy and operate it. The code lives in [beacon-web](https://github.com/MeshCore-Beacon/beacon-web) (the frontend). The proposed paired backend, basic Atlas and Topology release is described in +[Project roadmap and maintainer handoff](docs/project-roadmap.md) maps current +repositories, issues, PRs and the staged route to live. + [Core performance candidate](docs/performance-release-candidate.md), including validation, operational budgets and remaining release gates. diff --git a/docker-deployment-type1/docker-compose.yml b/docker-deployment-type1/docker-compose.yml index 9f445d2..c3cf1ea 100644 --- a/docker-deployment-type1/docker-compose.yml +++ b/docker-deployment-type1/docker-compose.yml @@ -1,5 +1,12 @@ +x-logging: &default-logging + driver: json-file + options: + max-size: "10m" + max-file: "3" + services: app: + logging: *default-logging image: ghcr.io/meshcore-beacon/beacon-server:latest env_file: .env ports: @@ -14,6 +21,7 @@ services: restart: unless-stopped db: + logging: *default-logging image: postgres:16-alpine environment: POSTGRES_USER: beacon @@ -31,6 +39,7 @@ services: restart: unless-stopped redis: + logging: *default-logging image: redis:7-alpine volumes: - ./data/redis/:/data @@ -44,6 +53,7 @@ services: restart: unless-stopped caddy: + logging: *default-logging image: caddy:2-alpine ports: - "80:80" @@ -63,6 +73,7 @@ services: restart: unless-stopped web: + logging: *default-logging image: ghcr.io/meshcore-beacon/beacon-web:latest env_file: .env environment: diff --git a/docker-deployment-type2/server/docker-compose.yml b/docker-deployment-type2/server/docker-compose.yml index 2a69d51..ffb868c 100644 --- a/docker-deployment-type2/server/docker-compose.yml +++ b/docker-deployment-type2/server/docker-compose.yml @@ -1,5 +1,12 @@ +x-logging: &default-logging + driver: json-file + options: + max-size: "10m" + max-file: "3" + services: app: + logging: *default-logging image: ghcr.io/meshcore-beacon/beacon-server:latest env_file: .env ports: @@ -14,6 +21,7 @@ services: restart: unless-stopped db: + logging: *default-logging image: postgres:16-alpine environment: POSTGRES_USER: beacon @@ -31,6 +39,7 @@ services: restart: unless-stopped redis: + logging: *default-logging image: redis:7-alpine volumes: - ./data/redis/:/data @@ -44,6 +53,7 @@ services: restart: unless-stopped caddy: + logging: *default-logging image: caddy:2-alpine ports: - "80:80" diff --git a/docker-deployment-type2/web/docker-compose.yml b/docker-deployment-type2/web/docker-compose.yml index bf9a013..d36efa3 100644 --- a/docker-deployment-type2/web/docker-compose.yml +++ b/docker-deployment-type2/web/docker-compose.yml @@ -1,5 +1,12 @@ +x-logging: &default-logging + driver: json-file + options: + max-size: "10m" + max-file: "3" + services: caddy: + logging: *default-logging image: caddy:2-alpine ports: - "80:80" @@ -13,6 +20,7 @@ services: restart: unless-stopped beacon-web: + logging: *default-logging image: ${BEACON_WEB_IMAGE:?Set BEACON_WEB_IMAGE to a reviewed release tag or digest} environment: - VITE_API_BASE=${VITE_API_BASE:?VITE_API_BASE environment variable is required} diff --git a/docs/project-roadmap.md b/docs/project-roadmap.md new file mode 100644 index 0000000..9e8d657 --- /dev/null +++ b/docs/project-roadmap.md @@ -0,0 +1,224 @@ +# Beacon project roadmap and maintainer handoff + +**Snapshot: 23 October 2026.** Scope: seven org repositories, seven related forks, all 25 pre-existing open issues and 34 open PRs, current main/dev/dev1 source, and fresh read-only production/dev/dev1/Canadaverse runtime checks. This review also finishes the bounded Topology follow-up already in progress. Tracking issue: [beacon-docs #45](https://github.com/MeshCore-Beacon/beacon-docs/issues/45). + +## Decision summary + +Use one reviewed core server/web candidate and one optional collection candidate. Do not merge every open feature branch in date order. Most of the Atlas/Topology/backend drafts are overlapping generations of the same work, and a green old build is not proof of compatibility with the current database baseline. + +The recommended sequence is: establish reliable acceptance capacity and repair build-tool qualification; review the core database/reliability changes; qualify basic Atlas and Topology on the paired backend; rehearse production migration/recovery and soak; then promote an immutable core release. Mobile collection follows a separate intake/RF/device gate. A cursor-only hotfix remains an independent option if the full feature release takes longer. + +The main blockers are concrete: dev1 is stopped, live still fails four large-cursor reads, preview is under severe shared-host I/O pressure, a Vite dependency PR has failed CI, development dependencies have current advisories, and the telemetry client has not completed fresh physical/background qualification. None is resolved by consolidating PR titles or declaring the preview a release. + +This is a portfolio review with targeted source, regression, query-plan and runtime validation. Every open issue/PR has a disposition below. It is not a claim of an independent line-by-line approval of every historical diff or a production-scale load/security audit of every component. + +## Environments: source, branch and runtime are separate facts + +| Environment | Verified state before this review's preview update | Consequence | +| --- | --- | --- | +| live.meshcore.ca | Server `202acc6`, web `19f604e`; PostgreSQL 16.14; three migration records; containers running | Ordinary sampled reads work, but the four large-cursor probes return 500. Topology/catalogue endpoints are absent. Do not mistake current dev's fixes for a live deployment. | +| dev.meshcore.ca | Server `0801411`, web `008b2af`; PostgreSQL 16.15; schema 053; running | Backend matches current upstream dev. Web is one source commit behind `811f843`. Read models are complete. Topology is not merged here; its 404 is expected. | +| dev1.meshcore.ca | Four service containers stopped; sampled public requests all return 502 | Stored labels refer to server `b53e3c6` and web `5345519`. The database's current migration journal could not be read while stopped. Do not infer it from a branch name or count the error object as one migration. | +| Canadaverse preview | Started this review at server `fdae02d`, web `79edb9c`, label 2.5.0-n30nex.1; schema 053 | Has core/optional features plus preview extras. Fresh audit exposed load problems despite the prior successful qualification. Updated candidate identities and post-deploy results are recorded in the completion section. | + +Org branch heads at inventory: server main/dev1 `202acc6`, dev `0801411`; web main `19f604e`, dev `811f843`, dev1 `add7acb`; docs main `2731999`, dev `3c2ffe2`; canonical Flutter main `5a3de51`, dev `a810704`. A stopped dev1 container is also different from the org dev1 branch: neither currently represents the complete new core candidate. + +No production/dev/dev1 configuration, data or service was changed. Production checks were read-only and bounded. The separate preview worker retains the radio; RemoteTerm remains suspended. Private credentials, raw production logs and database dumps are not included in the public handoff. + +## Repository responsibilities + +| Repository / lane | Role and disposition | +| --- | --- | +| MeshCore-Beacon/beacon-server | Authoritative ingest, database/sqlc/read models, API, cache and stream contracts. Core #266/#267 are the review lane; optional #268/#269 add only the validating intake proxy/capability above it. | +| MeshCore-Beacon/beacon-web | Basic Atlas, packet/observer views and Topology. Core #182/#183; optional telemetry #184/#185. Keep frontend types and retry/cursor behavior paired with the backend. | +| MeshCore-Beacon/beacon-flutter-app | Canonical mobile app, now public. #11 is the optional collection branch. #5 is a separate CI-action maintenance update. There is no upstream app dev1 branch. | +| MeshCore-Beacon/beacon-docs | Authoritative technical/operator documentation and this roadmap. #43 is the core/roadmap qualification lane; #44 is optional collection. | +| MeshCore-Beacon/beacon-agent | Private scaffold, not a deployable replacement for intake or the current headless client. Define its ownership and contract before moving working service code here. | +| MeshCore-Beacon/beacon-scratch | Optional rough planning space. Its permissive dev workflow is not the promotion policy for the application repositories. | +| MeshCore-Beacon/beacon-flutter-app-archive | Legacy private mobile repository; despite its name, the repository is not formally archived. Decide whether to archive it after preserving needed history. Do not maintain a second release lane by habit. | +| n30nex/beacon-server-contributions and beacon-web-contributions | Active preview integration on the explicitly named n30nex-test branches. Default branches are not reliable deployment identifiers. Keep preview-only changes distinguishable from the org core. | +| n30nex/beacon-docs-contributions | Historical/shared experimental documentation; n30nex-test has advanced independently. Preserve Torchlight history and port relevant current docs through the org dev workflow. | +| n30nex/beacon-flutter-app | Test-build fork for canonical app #11. The tested collection head is `1f70418`, version 2.1.0+3. | +| n30nex/Beacon-Telemetry-Collector | Private, separate intake plus alternate headless client; head `386db29`. The app replaces a polling client, not this intake/storage responsibility. Preserve the private-source boundary and existing license. | +| n30nex/beacon-server and n30nex/beacon-web | Legacy forks, not current deployment sources. Retain recoverable unpublished work; exclude them from automatic release composition. | + +Some local clones use narrow fetch refspecs. A generic fetch left a server origin/n30nex-test tracking ref at `527efa4` even though the actual remote was `fdae02d`. The current work resolved the named remote ref explicitly before integration. Operators should compare the actual remote SHA, not trust a stale local remote-tracking name. + +## Architecture and promotion boundary + +```mermaid +flowchart LR + O[Observers over MQTT] --> S[Beacon ingest] + S --> D[PostgreSQL raw history and read models] + D --> A[Reader cache, API and WebSocket] + A --> W[Beacon web and basic Atlas/Topology] + A --> M[Beacon mobile viewer] + C[User-selected companion over BLE or Wi-Fi] --> P[Optional mobile polling client] + H[Alternate headless client] --> I[Separate validating intake] + P --> I + I --> T[Separate telemetry database] + T --> X[Optional Beacon API proxy] + X --> W +``` + +Observer MQTT ingestion and companion telemetry are different contracts. Keep their clocks, identities, acknowledgment semantics, retention and evidence labels separate. No admin password or companion private key should leave the client. Signed enrollment establishes key possession, not hardware attestation or sensor truth. + +The working promotion path is preview experimentation -> reviewed org dev composition -> a usable dev1 acceptance environment -> paired immutable release/main -> operator deployment to live. The current application PRs also have explicit dev1 targets because the operator requested that review route. Review the dev-targeted source first, then reconcile the paired dev1 target; do not accept divergent copies of a feature on both branches. + +## Roadmap: ordered packages and exit gates + +| Package | Work / owner by role | Exit gate | +| --- | --- | --- | +| R0. Restore acceptance capacity | Release/preview operators: decide dev1 maintenance/recovery, inspect its actual database before starting the candidate; measure shared Pi pressure and isolate suspected legacy load only with operator authorization. | A named reference environment is healthy, capacity is known, the exact source/schema/config manifest is recorded, and a rollback can be executed without resetting traffic history. | +| R1. Core reliability and build hygiene | Backend/web reviewers: core #266/#267 + #182/#183; current baseline/cursors/read models, bounded first fills, post-start history work, cache/error/stream bounds, supported runtime; fix build-tool advisories and qualify #186. Docs/operator: bounded logs and measured pool/cache settings. | Combined native CI, PostgreSQL/race/vulnerability/plan checks, exact cursor walks and restored-copy migration pass; no unhandled test errors; all unresolved advisories have a documented disposition. | +| R2. Basic Atlas and Topology acceptance | Web/backend reviewers: saved node/observer cards, lazy details, sample/gap labels, trace provenance, bounded feed and rendering; follow-up summary/read-model work only where measured. | Desktop and narrow-screen journeys pass; real target-device frame/interaction measurements and cold/warm API checks meet agreed budgets without hiding nodes, dropping distinct paths or disabling useful live effects. | +| R3. Time, data quality and delayed replay | Backend/protocol owners: #231/#270 sender/observation/receipt policy; #229 configurable evidence policy above structural safety; define replay age/order/rate, dedup lifetime and acceptance receipts. | Original timestamps/raw evidence preserved; future/late data do not pollute sorting, rollups, routes or retention; supported producer contract is versioned and tested before producers replay outages. | +| R4. Core production promotion | Release owner: representative production-shaped restore and migration from the actual live baseline, maintenance-cycle soak, operational metrics/alerts, exact release artifacts and recovery rehearsal. | Paired release manifest approved; operator signs off migration, source/artifact identity, client floors, SLOs, rollback/RPO/RTO and a monitored release window. Production is not the first integration test. | +| R5. Optional mobile telemetry alpha | Mobile/intake/web owners: #11 + server #268/#269 + web #184/#185 + docs #44; select/enroll nodes, BLE/Wi-Fi, background controls, durable delivery, coverage, budgets and service ownership. | Physical reconnect/unlock/screen-off/notification/overnight tests and actual mobile-to-Atlas delivery pass; shared RF coordination and intake operating model accepted; optional service failure leaves basic Beacon usable. | +| R6. Operator and long-term scale features | Owners after the core: remaining #60/#72 account/login/import/remote backup scope, map defaults, Atlas summary/downsampling contract, observer controls and a deliberate beacon-agent transition. | Small independent requirements and acceptance tests; no speculative control channel or destructive import added to the release merely because an old issue mentions it. | + +R3 contains policy work that can proceed alongside R1/R2; do not block an isolated bigint cursor repair on completing a new replay protocol. Basic Atlas can be accepted without collected telemetry. If Topology's hardware/load gate takes longer, use the existing tab configuration to stage its visibility deliberately; do not silently enable an unqualified page in a production release. + +Suggested performance acceptance targets, **proposals for the maintainer to agree, not measured guarantees**: warm route snapshot p95 <=250 ms on the reference host and <=1 s through the public proxy; cold global 24h snapshot p95 <=5 s on a production-sized retained dataset; ordinary packet/message reads remain responsive during fills/cleanup; target-device interaction remains usable with a 30-frame/s render budget at the representative graph size. Test the maximum caps separately. Record hardware, dataset, cold/warm state and measurement method. A frame cap is not an achieved FPS, and a few timings are not p95. + +## Current performance findings and implemented follow-up + +The 22/23 October Topology work changed the route query to stream paired adjacent array values with ROWS FROM/unnest. It avoids repeated array subscripting, preserves exact time bounds and NULL gaps, and handles non-one-based arrays correctly. The old expression could manufacture a bridge or lose adjacency with unusual bounds; a PostgreSQL regression now covers it. The cache keeps the whole minute snapshot, canonicalizes duplicate region keys and uses exact bounds. Six Topology plan cases retain indexed time-window drivers; three expected signatures changed from sort-before-group to hashed aggregation before final sorting. + +The web now applies its frame budget to camera input as well as animation, skips unchanged idle paints, releases inactive canvas buffers while restoring the camera, indexes observer lookup for chatter, and animates repeated hearings of one exact packet/path once. Every raw report and trail and every distinct path is retained; unique packet effects, glows and Public chatter remain. Extra Path2D caching was tried and removed because its timing benefit was inconsistent. + +The native frontend run exposed the same asynchronous fixture failure as Vite #186: all assertions passed, but a delayed TanStack Virtual scroll callback ran after jsdom destroyed window. Test-only commit `c2c3ecb` controls/drains that timer while the environment exists and asserts no timers remain after cleanup. It does not suppress unhandled errors, change production scrolling or remediate dependency advisories. The updated complete preview suite subsequently passed 1,560 tests. + +The Pi is not presently a clean performance reference. The fresh audit saw load around 4.6 on four CPUs and, in a later sample, I/O PSI `some avg60=62.61` and `full avg60=35.22`; these are stall-pressure measures, not disk bandwidth/utilization. CoreScope was at about 1.499 GiB of a 1.5 GiB limit and using about 115% CPU. Beacon app and its database were each using only a few percent CPU. This identifies a suspect co-located contributor, not isolated proof of a sole cause. No unrelated workload was stopped. + +Under that pressure, 15m/24h Topology public reads exceeded the eight-second audit timeout, and both bounded SQL variants hit a fifteen-second statement timeout. Observer-directory traffic ranking returned 500 after about five seconds. Restored-copy query parity and lower cost do not establish a live-host speedup under this condition. The roadmap must include capacity/isolation and query-family measurements before claiming the cold-query gate is closed. + +There were 13 queue/drop-class warning lines in the sampled last-hour preview log tail, plus other warnings. This is neither a drop count nor a loss ratio; inspect the bounded queue metrics and workload together. CMI/packet-sites were complete, so an unfinished first fill is not an adequate explanation for all current latency. + +The current core npm audit reports four affected dependency entries (Vite, Vitest, @vitest/mocker and Zod; two high and two moderate entries). Production-only `npm audit --omit=dev` reports zero. Treat these as development/build-tool exposure requiring an updated qualified lockfile, not evidence that the static site is compromised. Public advisories: [launch-editor](https://github.com/advisories/GHSA-587h-7wmj-h5pm), [Vitest](https://github.com/advisories/GHSA-qxg6-89mg-rqv8), [Zod](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5). Counts are tool-entry counts, not unique exploit counts. + +## Operating and data-contract work that remains + +- **Cold snapshots and Atlas fanout:** measure the query family, cache occupancy and client request budget. If a shared/precomputed adjacent-link model is warranted, define as-of metadata, exact expiry/reference counts, regional isolation and full result parity before making it authoritative. Do not remove the current query-plan gates or hide stale data. Atlas's recent 200-report sample remains a sample, not a complete lifetime/24h count. +- **Failure semantics:** finish the retryable-error review across read handlers. Observer-directory currently maps its read error to generic 500; the Topology-specific 503/Retry-After work does not fix every sibling endpoint. Bound shared background fetch work as well as the HTTP caller's wait. +- **Diagnostics and budgets:** privately enable/scrape the supported metrics and PostgreSQL statement/IO diagnostics through a planned change. Preserve reset timestamps and avoid raw values in labels. Budget all API/slow/maintenance/ingest/intake connections together, including backups and operator headroom; connection isolation alone does not isolate storage bandwidth. +- **Retention and recovery:** preserve deployment-specific raw/rollup/observer/route policies and the separate intake retention. Do not use an image-only rollback across schema 053's incompatible removals. The preview's off-host restore is useful evidence, but it is not production-sized role/ownership/RPO/RTO qualification. +- **Privilege and proxy boundaries:** separate migration/maintenance ownership from runtime authority on a restored copy before revoking privileges; keep metrics/admin private and trust only the actual proxy peers. Do not expose credentials or make every mounted directory writable to accommodate the nonroot image. +- **Clock/replay contract:** outer observer-time clamping is not decrypted sender-time validation. Preserve both clocks and an explicit effective ordering time. MQTT PUBACK is not a Beacon storage receipt. Companion report acceptance is a separate signed protocol and must not be advertised as an observer replay contract. +- **RF and mobile:** local hourly budgets cannot globally coordinate independent clients/instances. A closed repository does not itself enforce RF policy. Keep device reservations, no catch-up bursts, congestion/route limits, honest session/key-possession claims and explicit physical qualification. +- **Operations hygiene:** the three deployment templates now have only a bounded Docker logging change (11 services, json-file 10m/3). Existing containers require planned recreation to adopt it. Caddy access logs, database/WAL/backup growth and remote backup schedules are separate concerns. Data volumes are unchanged. + +## Merge and release procedure + +1. Agree the reference environment and core/optional boundaries in docs #45. Review the dev-targeted core PRs first; use the paired dev1 PRs as the corresponding acceptance candidate, not a second divergent implementation. +2. Resolve development dependency advisories and the exact dependency candidate's CI. Apply the small teardown fix where needed; do not mark an old failed run green because assertions passed. +3. Accept the current core source with its compatibility floors, schema/runbook and tests. Reconcile the optional branches against accepted core so their review diff contains the optional contract rather than re-presenting the whole core. +4. Rehearse migration/read-model initialization, interruption, retention and recovery against a representative copy of the actual release baseline. Check all four large-cursor endpoints and multi-page boundaries, not just health/info. +5. Deploy a paired immutable candidate to authorized dev/dev1, prove image/binary/assets/config/schema identity, then soak through at least a real maintenance cycle with API latency, database WAL/temp work, queues and read-model trust together. +6. Approve the release scope and immutable artifacts before the operator changes live. Keep the rollback/recovery boundary explicit. Monitor the same acceptance probes after rollout and record what was actually deployed. +7. Close/supersede old PRs/issues only after the accepted source and runtime evidence satisfy their scope. Preserve unpublished history and old recovery copies; do not delete branches/worktrees as a substitute for triage. + +## Acceptance checklist for the other maintainer + +- [ ] One chosen core server/web SHA pair, all required checks current on those heads; optional delta separately reviewable. +- [ ] Dev1 available and its actual database state recorded; no assumption that a stored image label or branch equals the running system. +- [ ] Production-shaped schema 003-to-053 migration/recovery rehearsal, writable mount/role/extension checks and exact opaque cursor walks. +- [ ] Cold/warm route, normal reads, fills/cleanup and ingestion budgets measured on a reference workload; no false losslessness, FPS or p95 claim. +- [ ] Atlas saved-state, observer coverage, sparse charts, keyboard/phone/French journeys; Topology camera/fullscreen/hidden-tab/chatter/path-evidence behavior. +- [ ] Current dependency advisory disposition and clean full CI, including absence of asynchronous errors. +- [ ] Private metrics/alerts, container/disk/connection budgets, bounded logs and production restore/RPO/RTO owners. +- [ ] Optional intake is deployed/operated separately; radio/device/background and cross-client budget gates passed before wider enrollment. +- [ ] Operator-approved release and rollback window; final source/artifact/config/schema manifest and post-write proof recorded. + +The issue and PR inventories below are explicit disposition lists. “Covered in candidate” does not mean “accepted” or “deployed live.” “Keep open” identifies scope still missing, rather than suggesting the previous work did nothing. + +## Every pre-existing open issue + +| Issue | Title | Disposition / next acceptance | +| --- | --- | --- | +| [MeshCore-Beacon/beacon-docs #13](https://github.com/MeshCore-Beacon/beacon-docs/issues/13) | Bound Docker container logs in all deployment templates | Bounded json-file logging prepared in #43 for all 11 services; semantic YAML checks pass. Runtime adoption requires planned container recreation. | +| [MeshCore-Beacon/beacon-flutter-app #10](https://github.com/MeshCore-Beacon/beacon-flutter-app/issues/10) | Optional companion telemetry sharing with a compatible Beacon instance | R5 via #11 plus optional API/web/intake; Android background scope now exceeds the original foreground-only issue text. Hardware/RF coordination gates remain. | +| [MeshCore-Beacon/beacon-flutter-app #4](https://github.com/MeshCore-Beacon/beacon-flutter-app/issues/4) | Region selector button missing in portrait orientation | R2/R5 open: reproduce portrait region controls on the current canonical app; old store build report is not proof of a current fix or failure. | +| [MeshCore-Beacon/beacon-server #270](https://github.com/MeshCore-Beacon/beacon-server/issues/270) | Supported producer contract for delayed observer MQTT packets | R3: define supported replay, clock, dedup and receipt contracts; implementation behavior is not a producer guarantee. Source-backed comment posted. | +| [MeshCore-Beacon/beacon-server #265](https://github.com/MeshCore-Beacon/beacon-server/issues/265) | Consolidate backend performance and reliability for the Atlas/Topology release candidate | R1 coordinator: review #266/#267 and the paired web; keep operational acceptance separate from merge status. | +| [MeshCore-Beacon/beacon-server #258](https://github.com/MeshCore-Beacon/beacon-server/issues/258) | Recheck Redis after a late miss becomes the singleflight leader | Covered by #259 and core #266/#267; close after the chosen accepted source includes the late-miss regression. | +| [MeshCore-Beacon/beacon-server #254](https://github.com/MeshCore-Beacon/beacon-server/issues/254) | Avoid empty HTTP 200 responses when JSON encoding fails | Covered by #255 and core #266/#267; require JSON-error regression in accepted source. | +| [MeshCore-Beacon/beacon-server #252](https://github.com/MeshCore-Beacon/beacon-server/issues/252) | Bound read-model backfill writes and retry smaller slices under pressure | Covered by #253 and core #266/#267; require bounded-write/interruption tests and target-load qualification. | +| [MeshCore-Beacon/beacon-server #231](https://github.com/MeshCore-Beacon/beacon-server/issues/231) | Can you remove these chats from the future on YEG beacon? | R3 open: future sender-time ordering is not fixed by outer observation-time clamping. No live deletion performed; policy comment posted. | +| [MeshCore-Beacon/beacon-server #229](https://github.com/MeshCore-Beacon/beacon-server/issues/229) | Add Configurable Topology Validation for Packet Paths and Neighbors | R3 open: structural safeguards are staged; configurable policy, literal byte semantics and aggregate revalidation still need design. | +| [MeshCore-Beacon/beacon-server #226](https://github.com/MeshCore-Beacon/beacon-server/issues/226) | Synchronous channel backfill delayed dev1 startup and live ingestion by about 159 seconds | Post-start resumable history job is in core #266/#267; accept startup/readiness and interruption evidence before closing. | +| [MeshCore-Beacon/beacon-server #224](https://github.com/MeshCore-Beacon/beacon-server/issues/224) | Route reconfirm maintenance repeatedly times out before neighbour revalidation | Current dev/core replace the older maintenance shape; verify backlog progress and a real maintenance cycle before declaring the old starvation report closed. | +| [MeshCore-Beacon/beacon-server #223](https://github.com/MeshCore-Beacon/beacon-server/issues/223) | Suspect TRACE records resolve as confident paths and promote unvisited hops | TRACE ambiguity/width/consumed-hop safeguards are in core; preserve raw evidence and require paired analyzer tests/acceptance. | +| [MeshCore-Beacon/beacon-server #72](https://github.com/MeshCore-Beacon/beacon-server/issues/72) | Backup - local & remote | Keep open for remaining UI/login/import/overwrite/remote-storage scope. Export, validation and protected download foundations already exist; do not rebuild them. | +| [MeshCore-Beacon/beacon-server #60](https://github.com/MeshCore-Beacon/beacon-server/issues/60) | Admin API | Rescope against accepted config/account/CORS code. Ingest worker-pool configuration, persistence, login and tokens are not implied by the existing API. | +| [MeshCore-Beacon/beacon-web #181](https://github.com/MeshCore-Beacon/beacon-web/issues/181) | Consolidate basic Atlas and performant Topology for the core release candidate | R1/R2 coordinator: primary #182/#183, performance and paired API acceptance; optional telemetry stays separate. | +| [MeshCore-Beacon/beacon-web #170](https://github.com/MeshCore-Beacon/beacon-web/issues/170) | Channel list over scroll | R2 open: reproduce Channels nested scrolling/overscroll on current desktop/mobile layouts, especially Safari; add viewport containment regression before closure. | +| [MeshCore-Beacon/beacon-web #163](https://github.com/MeshCore-Beacon/beacon-web/issues/163) | Port the qualified Topology page and bounded backend feed to dev1 | Implementation consolidated in #182/#183 and backend #266/#267; current dev1 deployment acceptance remains open because services are stopped. | +| [MeshCore-Beacon/beacon-web #162](https://github.com/MeshCore-Beacon/beacon-web/issues/162) | Atlas drag can be committed by a different pointer and leak listeners | Drag ownership/cancellation work is included in the core lineage; close after accepted tests and touch/keyboard journeys, not from old PR green status alone. | +| [MeshCore-Beacon/beacon-web #161](https://github.com/MeshCore-Beacon/beacon-web/issues/161) | Sparse sparklines hide isolated signal readings | Isolated readings/zero/gaps have regression coverage in core. Preview shares its bright chart implementation; preserve semantics when promoting. | +| [MeshCore-Beacon/beacon-web #150](https://github.com/MeshCore-Beacon/beacon-web/issues/150) | Make a few map defaults configurable (live map dim level, single IATA tilt, clustering) | R6 partial: preview has a user dimming option, not the full requested per-deployment opacity/pitch/clustering defaults or clustered activity indication. | +| [MeshCore-Beacon/beacon-web #96](https://github.com/MeshCore-Beacon/beacon-web/issues/96) | Add My Atlas saved-node monitoring cards | Basic Atlas is consolidated in #182/#183. Keep sample/coverage semantics; close after saved-state, observer and narrow-screen acceptance. | +| [n30nex/beacon-server-contributions #10](https://github.com/n30nex/beacon-server-contributions/issues/10) | Preserve backfill batch size when only the work-cycle budget expires | Fix present in deployed preview and consolidated core; verify accepted upstream coverage, then close as incorporated. | +| [n30nex/beacon-server-contributions #8](https://github.com/n30nex/beacon-server-contributions/issues/8) | Refresh preview database/API and avoid redundant cache reads | Preview refresh has been deployed; use exact current manifests, then close tracking once the owner accepts the evidence. | +| [n30nex/beacon-web-contributions #16](https://github.com/n30nex/beacon-web-contributions/issues/16) | Refresh preview upstream UI while preserving Atlas telemetry and Topology | Preview refresh is deployed with preserved extras. Close tracking after source/assets/runtime verification; do not infer org acceptance. | + +New coordination issue [beacon-docs #45](https://github.com/MeshCore-Beacon/beacon-docs/issues/45) tracks this roadmap. Existing issues were not mass-closed. + +## Every pre-existing open PR + +| PR | Target / current head | Disposition | +| --- | --- | --- | +| [MeshCore-Beacon/beacon-docs #44](https://github.com/MeshCore-Beacon/beacon-docs/pull/44) | dev / `0d70bf73729f` | OPTIONAL collection guide, refresh after core docs acceptance. | +| [MeshCore-Beacon/beacon-docs #43](https://github.com/MeshCore-Beacon/beacon-docs/pull/43) | dev / `b221d58a31e4` | PRIMARY project roadmap/core qualification/operator docs; includes bounded log templates. | +| [MeshCore-Beacon/beacon-docs #7](https://github.com/MeshCore-Beacon/beacon-docs/pull/7) | main / `93e096f12bb7` | Historical experimental docs targeting main; policy check fails. Port needed content through dev, no bypass. | +| [MeshCore-Beacon/beacon-flutter-app-archive #22](https://github.com/MeshCore-Beacon/beacon-flutter-app-archive/pull/22) | dev / `8392a679f026` | Legacy repository duplicate of canonical action maintenance. Decide archive policy; do not create another release lane. | +| [MeshCore-Beacon/beacon-flutter-app #11](https://github.com/MeshCore-Beacon/beacon-flutter-app/pull/11) | dev / `1f704187a94e` | OPTIONAL mobile collection; native CI passed, physical BLE/Wi-Fi/background gate open. | +| [MeshCore-Beacon/beacon-flutter-app #5](https://github.com/MeshCore-Beacon/beacon-flutter-app/pull/5) | dev / `4ac72a61131f` | Small independent setup-java maintenance update with green CI; review separately from telemetry. | +| [MeshCore-Beacon/beacon-server #269](https://github.com/MeshCore-Beacon/beacon-server/pull/269) | dev1 / `96e29a0c04c1` | OPTIONAL -> dev1, after accepted core and intake/device gates. | +| [MeshCore-Beacon/beacon-server #268](https://github.com/MeshCore-Beacon/beacon-server/pull/268) | dev / `96e29a0c04c1` | OPTIONAL -> dev, after accepted core; review the optional-only comparison. | +| [MeshCore-Beacon/beacon-server #267](https://github.com/MeshCore-Beacon/beacon-server/pull/267) | dev1 / `5c4c53887e91` | PAIRED core -> dev1. Same source lane; actual dev1 acceptance still required. | +| [MeshCore-Beacon/beacon-server #266](https://github.com/MeshCore-Beacon/beacon-server/pull/266) | dev / `5c4c53887e91` | PRIMARY core -> dev. Review current head and release gates. | +| [MeshCore-Beacon/beacon-server #263](https://github.com/MeshCore-Beacon/beacon-server/pull/263) | dev1 / `07188bdfb2ea` | Superseded optional prototype; retain until #268/#269 acceptance. | +| [MeshCore-Beacon/beacon-server #259](https://github.com/MeshCore-Beacon/beacon-server/pull/259) | dev / `14feb220f6a6` | Focused cache fix included in core; choose standalone acceptance or core, not duplicate implementations. | +| [MeshCore-Beacon/beacon-server #256](https://github.com/MeshCore-Beacon/beacon-server/pull/256) | dev1 / `c0abd3e6b374` | Superseded broad dev1 integration; core #266/#267 retain current upstream. | +| [MeshCore-Beacon/beacon-server #255](https://github.com/MeshCore-Beacon/beacon-server/pull/255) | dev / `d2553acd79a3` | Focused JSON fix included in core; retain regression when accepting. | +| [MeshCore-Beacon/beacon-server #253](https://github.com/MeshCore-Beacon/beacon-server/pull/253) | dev / `1f683c9df6d2` | Focused bounded-fill fix included in core; qualify on target storage. | +| [MeshCore-Beacon/beacon-server #242](https://github.com/MeshCore-Beacon/beacon-server/pull/242) | codex/sync-dev1-server-20261015 / `b53e3c67514e` | Legacy dev1 cursor backport; upstream dev/core already include the accepted cursor fix. | +| [MeshCore-Beacon/beacon-server #230](https://github.com/MeshCore-Beacon/beacon-server/pull/230) | dev1 / `5374ee55a3b3` | Older dev1 upstream/Topology sync; superseded by current core. | +| [MeshCore-Beacon/beacon-server #225](https://github.com/MeshCore-Beacon/beacon-server/pull/225) | dev1 / `1d3f7ce6211b` | Original Topology/TRACE port; superseded by core, retain evidence reference. | +| [MeshCore-Beacon/beacon-server #210](https://github.com/MeshCore-Beacon/beacon-server/pull/210) | dev / `b097f19a31cc` | Broad early preview experiment; not the current release source. | +| [MeshCore-Beacon/beacon-server #192](https://github.com/MeshCore-Beacon/beacon-server/pull/192) | dev / `054e08de7d7f` | Experimental fork integration now includes optional work and preview extras. Do not merge as the standalone core. | +| [MeshCore-Beacon/beacon-web #186](https://github.com/MeshCore-Beacon/beacon-web/pull/186) | dev / `b7be0bcd5249` | DEPENDENCY track: failed CI with unhandled virtualizer callback. Test-only fix available; rebase, re-audit and rerun exact candidate. | +| [MeshCore-Beacon/beacon-web #185](https://github.com/MeshCore-Beacon/beacon-web/pull/185) | dev1 / `a6ecbbc25555` | OPTIONAL telemetry -> dev1 after core/intake qualification. | +| [MeshCore-Beacon/beacon-web #184](https://github.com/MeshCore-Beacon/beacon-web/pull/184) | dev / `a6ecbbc25555` | OPTIONAL telemetry -> dev after core/intake qualification. | +| [MeshCore-Beacon/beacon-web #183](https://github.com/MeshCore-Beacon/beacon-web/pull/183) | dev1 / `c2c3ecbba0a1` | PAIRED basic Atlas/Topology -> dev1; requires a running acceptance environment. | +| [MeshCore-Beacon/beacon-web #182](https://github.com/MeshCore-Beacon/beacon-web/pull/182) | dev / `c2c3ecbba0a1` | PRIMARY basic Atlas/Topology -> dev, with performance follow-up. | +| [MeshCore-Beacon/beacon-web #180](https://github.com/MeshCore-Beacon/beacon-web/pull/180) | dev1 / `ff18bd5e84a8` | Older optional telemetry PR; superseded by #184/#185. | +| [MeshCore-Beacon/beacon-web #179](https://github.com/MeshCore-Beacon/beacon-web/pull/179) | dev1 / `b2f025660c24` | Older combined upstream/Atlas/Topology candidate; superseded by core. | +| [MeshCore-Beacon/beacon-web #169](https://github.com/MeshCore-Beacon/beacon-web/pull/169) | dev1 / `5345519ee41d` | Older dev1 sync, used by stored dev1 image; not current core acceptance. | +| [MeshCore-Beacon/beacon-web #167](https://github.com/MeshCore-Beacon/beacon-web/pull/167) | dev1 / `5786dd89fe8b` | Observer/card refinements incorporated into current core lineage. | +| [MeshCore-Beacon/beacon-web #165](https://github.com/MeshCore-Beacon/beacon-web/pull/165) | dev1 / `9209d9388815` | Original Topology/Public-chatter port; superseded by #182/#183. | +| [MeshCore-Beacon/beacon-web #164](https://github.com/MeshCore-Beacon/beacon-web/pull/164) | dev1 / `fee858fd7707` | Sparse-chart/drag fixes incorporated into core; preserve tests. | +| [MeshCore-Beacon/beacon-web #151](https://github.com/MeshCore-Beacon/beacon-web/pull/151) | dev / `add7acbaa1cc` | Earlier basic Atlas PR; org dev1 branch currently points here, but core has later work. | +| [MeshCore-Beacon/beacon-web #148](https://github.com/MeshCore-Beacon/beacon-web/pull/148) | dev / `9d08d9895676` | Broad early preview experiment including extras; do not substitute for separated core/optional lanes. | +| [MeshCore-Beacon/beacon-web #97](https://github.com/MeshCore-Beacon/beacon-web/pull/97) | dev / `91a9541cd6fe` | Original Atlas draft; current core is the maintained review lane. | + +## Work completed during this review + +- Updated core server #266/#267 and optional #268/#269 with the bounded Topology query/cache follow-up; updated core web #182/#183 and optional #184/#185 with rendering/lifecycle/duplicate-hearing improvements and the test teardown fix. All application candidates retain draft status; no org merge occurred. +- Incorporated preview fork PRs [server #14](https://github.com/n30nex/beacon-server-contributions/pull/14) and [web #20](https://github.com/n30nex/beacon-web-contributions/pull/20) after native CI. The preview now runs server `054e08de7d7fd581e55544e0326ca92596b9a990` and web `8dcb7f2f233c8ac4086c1ebe02f81d348630321b`, label **2.5.1-n30nex.1**. API compatibility version remains 2.1.0. +- Native server build/vet/unit/PostgreSQL/race/plan/runtime-image checks and the full 1,560-test preview web run passed. Six Topology plan cases passed with reviewed signatures. The 18-test virtualizer file now drains its fixture timers rather than suppressing asynchronous errors. +- Restored-snapshot global query medians were **1.3691 s -> 0.9836 s (28.2% lower)**, with identical 9,975-edge output. Dense YYJ and sparse YKF outputs also matched. This is a serialized local snapshot comparison, not a live throughput guarantee. Six CPU-raster scene hashes were identical for unique traffic; repeated hearings intentionally produce fewer duplicate particles while retaining reports/paths. +- All 34 public assets and both corresponding source archives matched the deployed build. Both MQTT brokers and retained telemetry API checks passed, including six histories and invalid-signature/unenrolled-report rejection. Schema 053, configuration/retention, private keys, intake/worker and unrelated container identities remained unchanged. +- A final public 24h route snapshot returned 200 in 5.619 s and then 0.191 s cached, with the same 9,346 links and window. Host pressure was lower than during the earlier timeout sample. These two samples do not close the cold p95 or contention gates or prove the improvement came solely from the code. +- No browser surface was available for a new visual/device run in this session. Existing scene/regression checks are not relabelled as fresh Mac/Safari/phone acceptance. No new mobile RF/background qualification is claimed. +- Prepared bounded Docker log rotation across all three templates/11 services in docs #43. Parsed semantic comparison proves only logging changed. No live container was recreated for that template change. +- Published substantive review comments on [server #266](https://github.com/MeshCore-Beacon/beacon-server/pull/266#pullrequestreview-5635386697), [web #182](https://github.com/MeshCore-Beacon/beacon-web/pull/182#pullrequestreview-5635386963) and [web #186](https://github.com/MeshCore-Beacon/beacon-web/pull/186#pullrequestreview-5635268998); source-backed issue comments on [replay #270](https://github.com/MeshCore-Beacon/beacon-server/issues/270#issuecomment-6376355877), [policy #229](https://github.com/MeshCore-Beacon/beacon-server/issues/229#issuecomment-6376566376) and [clock #231](https://github.com/MeshCore-Beacon/beacon-server/issues/231#issuecomment-6376566638); workflow clarification on [docs #7](https://github.com/MeshCore-Beacon/beacon-docs/pull/7#issuecomment-6376497818); and the isolated test-fix pointer on [web #186](https://github.com/MeshCore-Beacon/beacon-web/pull/186#issuecomment-6376498120). These are comment reviews, not approvals. + +## Next operator decisions + +Agree the acceptance host and isolation plan; choose the cursor-only hotfix versus the complete core release schedule; assign migration/recovery and performance-soak owners; decide whether to formally archive the legacy mobile repository; and accept a physical/RF qualification plan for optional collection. No task here requires deleting raw history, resetting IDs, weakening branch protection or forcing a global radio test. + +Retain the current preview rollback checkpoint and exact artifact manifest. This update changed only the application binary and frontend files; no schema migration or radio restart was required. Restore the paired application/frontend rather than overwriting the database or reverting the worker to an unrelated old version. If the preview advances, compare its manifest before applying any older rollback. + +The project needs an accepted release composition and repeatable qualification, not another parallel umbrella implementation. This handoff provides the source/issue/PR map so the other maintainer can make that acceptance decision without reconstructing the full chat history. From 2b4e5a0d8e1e729a6398d50aa49f2027caef5a22 Mon Sep 17 00:00:00 2001 From: n30nex Date: Fri, 23 Oct 2026 19:23:34 -0400 Subject: [PATCH 8/9] docs: clarify live document references --- README.md | 6 +++--- docs/project-roadmap.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6139272..f01caeb 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ This repo is where you deploy and operate it. The code lives in [beacon-server](https://github.com/MeshCore-Beacon/beacon-server) (the API and ingest) and [beacon-web](https://github.com/MeshCore-Beacon/beacon-web) (the frontend). -The proposed paired backend, basic Atlas and Topology release is described in -[Project roadmap and maintainer handoff](docs/project-roadmap.md) maps current +The [project roadmap and maintainer handoff](docs/project-roadmap.md) maps current repositories, issues, PRs and the staged route to live. -[Core performance candidate](docs/performance-release-candidate.md), including +The proposed paired backend, basic Atlas and Topology release is described in the +[core performance candidate](docs/performance-release-candidate.md), including validation, operational budgets and remaining release gates. > **Coming from 1.x?** 2.0.0 needs a fresh database and a few config changes. Read diff --git a/docs/project-roadmap.md b/docs/project-roadmap.md index 9e8d657..2d482a9 100644 --- a/docs/project-roadmap.md +++ b/docs/project-roadmap.md @@ -166,10 +166,10 @@ New coordination issue [beacon-docs #45](https://github.com/MeshCore-Beacon/beac ## Every pre-existing open PR -| PR | Target / current head | Disposition | +| PR | Target / code head (docs via PR) | Disposition | | --- | --- | --- | -| [MeshCore-Beacon/beacon-docs #44](https://github.com/MeshCore-Beacon/beacon-docs/pull/44) | dev / `0d70bf73729f` | OPTIONAL collection guide, refresh after core docs acceptance. | -| [MeshCore-Beacon/beacon-docs #43](https://github.com/MeshCore-Beacon/beacon-docs/pull/43) | dev / `b221d58a31e4` | PRIMARY project roadmap/core qualification/operator docs; includes bounded log templates. | +| [MeshCore-Beacon/beacon-docs #44](https://github.com/MeshCore-Beacon/beacon-docs/pull/44) | dev / `see PR` | OPTIONAL collection guide, refresh after core docs acceptance. | +| [MeshCore-Beacon/beacon-docs #43](https://github.com/MeshCore-Beacon/beacon-docs/pull/43) | dev / `see PR` | PRIMARY project roadmap/core qualification/operator docs; includes bounded log templates. | | [MeshCore-Beacon/beacon-docs #7](https://github.com/MeshCore-Beacon/beacon-docs/pull/7) | main / `93e096f12bb7` | Historical experimental docs targeting main; policy check fails. Port needed content through dev, no bypass. | | [MeshCore-Beacon/beacon-flutter-app-archive #22](https://github.com/MeshCore-Beacon/beacon-flutter-app-archive/pull/22) | dev / `8392a679f026` | Legacy repository duplicate of canonical action maintenance. Decide archive policy; do not create another release lane. | | [MeshCore-Beacon/beacon-flutter-app #11](https://github.com/MeshCore-Beacon/beacon-flutter-app/pull/11) | dev / `1f704187a94e` | OPTIONAL mobile collection; native CI passed, physical BLE/Wi-Fi/background gate open. | From f6c225b59aa8f58f0703de68597fc7f5847f4612 Mon Sep 17 00:00:00 2001 From: n30nex Date: Fri, 23 Oct 2026 19:33:46 -0400 Subject: [PATCH 9/9] docs: record remaining maximum-scene rendering cost --- docs/project-roadmap.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/project-roadmap.md b/docs/project-roadmap.md index 2d482a9..20d4d32 100644 --- a/docs/project-roadmap.md +++ b/docs/project-roadmap.md @@ -87,6 +87,16 @@ The 22/23 October Topology work changed the route query to stream paired adjacen The web now applies its frame budget to camera input as well as animation, skips unchanged idle paints, releases inactive canvas buffers while restoring the camera, indexes observer lookup for chatter, and animates repeated hearings of one exact packet/path once. Every raw report and trail and every distinct path is retained; unique packet effects, glows and Public chatter remain. Extra Path2D caching was tried and removed because its timing benefit was inconsistent. +The maximum-scene CPU raster fixture still shows expensive camera motion. With 5,000 nodes, 10,200 links and a 512-flow cap, the 20-frame sample medians were: + +| CPU raster phase | Before | Current candidate | +| --- | --- | --- | +| Steady flow | 11.92 ms | 10.60 ms | +| Trail update | 128.08 ms | 106.38 ms | +| Orbit | 382.58 ms | 380.34 ms | + +These are synthetic CPU/Skia draw timings, not browser frame rates; run-to-run noise prevents attributing these small differences to the patch. They do show that throttling redraw frequency does not make a maximum-scene redraw cheap. R2 should profile curve projection, rasterization and labels during real Mac/phone camera motion, then qualify any further detail/pixel-ratio or rendering changes against the same visible-node/path and animation requirements. The current work does not establish smooth maximum-cap camera motion. + The native frontend run exposed the same asynchronous fixture failure as Vite #186: all assertions passed, but a delayed TanStack Virtual scroll callback ran after jsdom destroyed window. Test-only commit `c2c3ecb` controls/drains that timer while the environment exists and asserts no timers remain after cleanup. It does not suppress unhandled errors, change production scrolling or remediate dependency advisories. The updated complete preview suite subsequently passed 1,560 tests. The Pi is not presently a clean performance reference. The fresh audit saw load around 4.6 on four CPUs and, in a later sample, I/O PSI `some avg60=62.61` and `full avg60=35.22`; these are stall-pressure measures, not disk bandwidth/utilization. CoreScope was at about 1.499 GiB of a 1.5 GiB limit and using about 115% CPU. Beacon app and its database were each using only a few percent CPU. This identifies a suspect co-located contributor, not isolated proof of a sole cause. No unrelated workload was stopped.