Skip to content

fix(admin-dapp): adopt the current @enbox line, sync-driven refresh, and sync health - #272

Open
LiranCohen wants to merge 8 commits into
mainfrom
chore/admin-dapp-sync-wave
Open

fix(admin-dapp): adopt the current @enbox line, sync-driven refresh, and sync health#272
LiranCohen wants to merge 8 commits into
mainfrom
chore/admin-dapp-sync-wave

Conversation

@LiranCohen

Copy link
Copy Markdown
Contributor

Fixes #268

What changed

  1. @enbox upgrade to the current published line — agent 0.8.34, api 0.6.73, auth 0.6.80, browser 0.3.65, common 0.1.5, crypto 0.1.8, dids 0.1.8, dwn-sdk-js 0.4.18, protocols 0.2.100 (was agent 0.8.17 / dwn-sdk-js 0.4.10 — predating the MessagesSubscribe head/fingerprint sync handshake, remote-response verification, and subscription-revalidation hardening). package.json + bun.lock committed together, ending the dev-vs-CI SDK divergence (bun install --frozen-lockfile verified). API breakage fixed: the typed-records rework requires runtime codecs per protocol type.
  2. Protocol definition fix required by the upgrade (protocols/wireguard-mesh.json, own commit since the Go daemon embeds it): dwn-sdk-js 0.4.17 removed $recordLimit.strategy from the schema — the old definition is now rejected at ProtocolsConfigure time, which would have left the upgraded dashboard unable to start. Removing it is semantically a no-op (reject-over-limit is the SDK's only behavior now). A new test drives the shipped JSON through the real installed SDK validator so future schema-gate changes fail bun run test instead of production.
  3. Sync-event-driven refresh: the 10s full-topology poll (5+N queries per tick) is gone; topology refreshes are driven by agent delivery:applied sync events filtered to the mesh protocol (500ms debounce), with the manual Refresh button, visibilitychange refresh, and a 60s visibility-gated safety poll retained. The subscription survives UI action churn.
  4. Per-remote sync health panel (modeled on notesd's): healthy / quota-blocked ("Storage full — pushes deferred") / degraded / offline, waiting+failed counts, next probe, last error, per-remote Retry.
  5. Convergence-aware pushes + query hygiene: post-write sync("push") kept (verified to exist at 0.8.34); terminal dead-lettered pushes surfaced instead of silently swallowed; queryRecords now paginates (limit 100, hard page cap) instead of assuming single-page replies.
  6. Housekeeping: .gitignore for local experiment debris, README key-delivery claim fixed.

Approval-flow gate re-validation (for the record): #1479 (authorized role issuers) and #1480 (record-limited role rejection) are both ProtocolsConfigure-time checks — the mesh definition passes both (no $role path carries $recordLimit; role issuance is who: "author", of: "network" and the dapp's $role writes are owner-authored via delegated grant).

Verification

  • bun install --frozen-lockfile — clean, no changes
  • bun run test — 62/62 pass (+17 new: refresh scheduler, sync health, pagination, dead letters, real SDK protocol gate)
  • bun run build — tsc + vite + PWA worker, zero errors
  • go build ./... && go vet ./... && go test ./... -count=1 -race — all pass (the protocol JSON is embedded in the Go daemon)

🤖 Generated with Claude Code

LiranCohen and others added 8 commits July 26, 2026 14:50
Move all nine @enbox packages from the stale early-June pins (agent
0.8.17 / dwn-sdk-js 0.4.10 line) to the current published versions:
agent 0.8.34, api 0.6.73, auth 0.6.80, browser 0.3.65, common 0.1.5,
crypto 0.1.8, dids 0.1.8, dwn-sdk-js 0.4.18, protocols 0.2.100.
package.json and bun.lock move together, resolving the documented
node_modules/lockfile divergence (CI installs with --frozen-lockfile).

The typed-records rework in @enbox/api now requires defineProtocol to
receive one runtime codec per reachable protocol type; supply plain
JSON codecs for all ten mesh types through a loosely-typed alias (the
JSON-imported definition is too wide for literal path inference and
trips TS2589 otherwise). No behavior change: the typed handle is only
used for configure/verify.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dashboard refetched the full topology (5+N RecordsQuery) every ten
seconds regardless of whether anything changed. The upgraded sync engine
emits typed delivery:applied events once per freshly applied remote
message, so refresh on those instead: filter descriptors to the mesh
protocol, coalesce bursts through a 500ms trailing debounce (an approval
applies member + node + approval records back-to-back), and refetch once.

Kept: the manual Refresh button, the visibilitychange refresh, and a
slow visibility-gated safety-net poll (60s) for anything the event
stream misses. The subscription and any pending debounce are torn down
on unmount/disconnect.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Compact sidebar surface over the sync engine's getRemoteSyncStatus,
modeled on notesd's use-remote-sync-status + remote-sync-panel: one row
per (tenant, remote) with the SDK's rolled-up state (precedence
offline > quota-blocked > degraded > healthy), quota-blocked/failed
message counts, last activity, next probe time, the last error, and a
per-remote Retry bound to retryRemoteNow. Quota-blocked is spelled out
as "Storage full — pushes deferred" — a full remote silently deferring
pushes otherwise just looks like a node that never appears.

The hook refreshes on every sync event (400ms trailing throttle) plus a
slow visibility-gated 30s poll, and unsubscribes on unmount. Styling
follows the dapp's light theme with teal/amber accents.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…shes

queryRecords assumed every matching record arrived in one reply; the
server's bounded record materialization (dwn-sdk-js 0.4.18) makes that
fragile. Walk the reply's pagination cursor with limit-100 pages, capped
at 20 pages so a runaway query can never loop forever (a truncation past
2000 records per path is warned about).

The one-shot sync("push") after each write survives at agent 0.8.34 and
is kept, but terminal push failures never surface through it — the
engine dead-letters them and resolves. After each push, report
mesh-protocol dead letters via console.warn (best-effort, never fails
the write); the sync health panel shows the same state as per-remote
failed counts.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ignore __TESTDATA__/ (PlatformAgentTestHarness LevelDB debris) and
_peervis.mjs (local peer-visibility repro script) — both exist only as
untracked files in local checkouts and were never meant to be committed.

The README claimed the dapp also requests the key-delivery protocol
(https://identity.foundation/protocols/key-delivery); it requests only
the wireguard-mesh protocol, and role-audience keys travel through the
mesh protocol's own sealed $encryption records.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dwn-sdk-js 0.4.17 (#1446) tightened the $recordLimit protocol schema to
additionalProperties:false with "max" as the only property. The shipped
definition still carried strategy:"reject" at network/preAuthKey, which
the 0.4.18 ProtocolsConfigure validator rejects — ensureProtocolsReady
failed at dapp startup against the upgraded @enbox pins. Rejecting over
limit is now the SDK's only behavior, so dropping the property changes
nothing semantically. The Go-side protocol test now rejects any
$recordLimit property other than max instead of only purgeOldest.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ensureProtocolsReady tests mock configure(), so schema-tightening
dwn-sdk-js releases (like 0.4.17 removing $recordLimit.strategy) could
ship green while the real ProtocolsConfigure validator rejects the
definition at startup. Pin protocols/wireguard-mesh.json to the
installed SDK by driving ProtocolsConfigure.create with the
wallet-installed shape ($keyAgreement injected), plus a negative case
proving the gate actually validates $recordLimit.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The topology effect listed busyAction in its deps, so every action
start/finish tore down and re-created the sync-event subscription and
cancelled any pending debounced refresh; delivery:applied events landing
in that gap were dropped until the safety poll. Read busyAction through
a ref so the subscription survives action churn.

Refs #268

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

admin-dapp: upgrade to the current @enbox line; sync-event-driven refresh and sync health

1 participant