Commit Graph
22 Commits
Author SHA1 Message Date
ekklesiaandClaude Opus 5.5 bf4e98fa30 ci: run session-blip and stream-failure on every change
CI / lint (pull_request) Successful in 12s
CI / typecheck (pull_request) Successful in 14s
CI / test (pull_request) Successful in 22s
CI / build (pull_request) Successful in 18s
CI / integration (pull_request) Successful in 3m40s
Both failed on main before this PR: a display that failed its first
viewer-session request, or its first realtime connection, never
recovered without a reload. With the retries in place they pass, and
CI now holds them there.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 21:32:03 -05:00
ekklesiaandClaude Opus 5.5 fbc8af7510 fix(display): retry every failed request with backoff, and never give up
A display tried each of its network paths once:
- A registration that failed left it continuing from its persisted
  state, behind the offline banner, with no realtime, heartbeat or
  retry, until someone reloaded it. This is what the production kiosk
  showed after a restart.
- A failed state refresh scheduled no further refresh, so a display
  whose realtime was also down never fetched state again.
- A realtime stream the host reported closed was never subscribed
  again.

Each path now retries on its own backoff: about 1 s, doubling to a
one-minute ceiling, with jitter so a building's screens do not return
in lockstep. There is no attempt limit, because a television has
nobody to press Retry. Each resets when its request works again.
- Registration retries until it works, then brings the display live
  exactly as a first-time success does.
- A failed refresh schedules its own retry, with no realtime needed.
- A closed realtime subscription is replaced.
- Stopping clears every retry.

The recovery test's virtual window shrinks from an hour to five
minutes: eight failures back off for at most about 183 s, and an hour
of offline-continuation timers made the test slow without proving more.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 21:31:55 -05:00
ekklesiaandClaude Opus 5.5 518fd101a2 test(display): a display recovers from every failed request without a reload
Pins what a kiosk needs from each network path, on a virtual clock: a
registration that fails once is retried with backoff until it works, a
state refresh that fails is retried without a realtime nudge, and a
realtime stream the host reports closed is subscribed again. Nothing is
scheduled after stop.

Fails today on all three paths: each is tried once. The first matches
the production screen exactly: mounted, showing "Offline — continuing
from the last update", with no heartbeat and no retry until someone
reloads it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 21:31:49 -05:00
The_River 27ee279f28 Merge pull request 'fix(display): define the display-server messages once, in src/shared' (#4) from fix/display-protocol-contract into main
CI / lint (push) Successful in 14s
CI / typecheck (push) Successful in 14s
CI / test (push) Successful in 20s
CI / build (push) Successful in 18s
CI / integration (push) Successful in 3m28s
Reviewed-on: https://git.riverofglorymn.org/River_of_Glory_Church/Ekklesia_Signage/pulls/4
Reviewed-by: The_River <[email protected]>
2026-10-06 02:30:41 +00:00
ekklesiaandClaude Opus 5.5 f1b7d67aa5 fix(display): define the display-server messages once, in src/shared
CI / lint (pull_request) Successful in 13s
CI / typecheck (pull_request) Successful in 15s
CI / test (pull_request) Successful in 21s
CI / build (pull_request) Successful in 18s
CI / integration (pull_request) Successful in 3m32s
The display controller and the viewer routes each described the
heartbeat their own way and disagreed about one thing: the display sent
null for "nothing to report", and the route accepted only a missing
field. Every heartbeat from a screen showing a native image was refused
with a 400. The roster therefore marked working screens Offline 90 s
after they opened, and never recorded offlineReady or cachedAssetCount.

src/shared/display-protocol.ts now defines every message between a
display and the server:
- viewer session request and response;
- heartbeat request and response;
- channel state;
- the realtime display payload.

Both halves import it. Its rules: a nullable field accepts null
explicitly, an absent field means "not reported", and an unknown field
is ignored, so a newer display is never refused by an older server.

- The routes parse with the shared parsers, and a refusal names the
  field with Signage's sanitized code.
- The server's channel state extends the wire type, so a field the
  display relies on cannot drift without a compile error.
- The display builds its heartbeat as the shared type, and reads its
  registration with the shared parser instead of casting it.
- Test stubs that described server responses more loosely than the
  server sends them (no viewerName, no stale, partial media) now match
  the real responses and are typed as the protocol.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 21:25:21 -05:00
ekklesiaandClaude Opus 5.5 458043280a test(display): run the real display controller against the real viewer routes
Every display test answered the controller with a hand-written stub, and
every viewer test called the service with a hand-written object, so
neither side was ever tested against the other. In production every
heartbeat was refused with a 400.

This suite answers the real controller's requests with the real viewer
route handlers over the in-memory store. The routes gain an optional
store factory for that; production still uses the module database.

Fails today: POST /viewers/:viewerId/heartbeat -> 400
SIGNAGE_INVALID_REQUEST, because the display sends
reportedContributionId: null and the route accepts only a missing field.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 21:25:21 -05:00
The_River 914034dda0 Merge pull request 'ci: build, test, and run Signage inside a pinned Ekklesia on every change' (#7) from ci/gitea-actions into main
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 14s
CI / test (push) Successful in 20s
CI / build (push) Successful in 20s
CI / integration (push) Successful in 3m22s
Reviewed-on: https://git.riverofglorymn.org/River_of_Glory_Church/Ekklesia_Signage/pulls/7
Reviewed-by: The_River <[email protected]>
2026-10-06 00:38:49 +00:00
ekklesiaandClaude Opus 5.5 3073baeb8b ci: build, test, and run Signage inside a pinned Ekklesia on every change
CI / lint (pull_request) Successful in 12s
CI / typecheck (pull_request) Successful in 15s
CI / test (pull_request) Successful in 19s
CI / build (pull_request) Successful in 18s
CI / integration (pull_request) Successful in 3m34s
Signage had no CI. Its tests passed while three defects shipped that
appear only inside Ekklesia, in a real browser. Every job now assembles
Signage into a pinned platform commit, as an instance does, and
installs that workspace with --frozen-lockfile:
- lint, typecheck, test: Signage's own checks;
- build: the platform's gates against exactly this module set (boundary
  rules, module manifest, migrations), then the build;
- integration: the deployment image from the platform's Dockerfile,
  then the platform's split-topology smoke. It pairs a kiosk display,
  restarts it on the same profile, and runs the scenarios in
  ci/display-scenarios.

The supporting files:
- ci/platform.env pins one platform commit. ci/assemble.sh fetches the
  platform's main and refuses a pinned commit that is not on it, so CI
  only runs reviewed platform code.
- ci/pnpm-lock.yaml is the assembled workspace's lockfile, regenerated
  with ci/update-lock.sh.

Same trust rules as the platform: actions pinned by SHA,
persist-credentials false, no secrets, no pull_request_target.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 19:11:53 -05:00
The_River 5e418bf941 Merge pull request 'feat: align Signage with platform display and design' (#3) from fix/signage-playback-and-displays into main
Reviewed-on: http://git.riverofglorymn.org/River_of_Glory_Church/Ekklesia_Signage/pulls/3
v0.1.1
2026-10-01 21:36:31 +00:00
The_River a68d7ebaee Update README.md 2026-10-01 21:32:21 +00:00
ekklesia 1bf89a3942 feat: align Signage with platform display and design 2026-09-30 18:21:42 -05:00
The_River ac2b8ded93 Merge pull request 'Fix/signage playback and displays' (#2) from fix/signage-playback-and-displays into main
Reviewed-on: http://git.riverofglorymn.org/River_of_Glory_Church/Ekklesia_Signage/pulls/2
2026-09-30 02:01:22 +00:00
ekklesia af0f0adadc test: align signage release expectations 2026-09-29 20:50:02 -05:00
ekklesia 36c1a72363 feat: make display setup actionable 2026-09-29 20:49:51 -05:00
ekklesia 7999582460 fix: preserve valid timeline slot positions 2026-09-29 20:49:39 -05:00
ekklesia 218e05e71e chore: release signage 0.1.1 2026-09-29 19:33:56 -05:00
ekklesia afac1bf8e7 chore: release signage 0.1.1 2026-09-29 19:27:03 -05:00
The_River 49d056f744 Merge pull request 'Fix/signage stabilization' (#1) from fix/signage-stabilization into main
Reviewed-on: http://git.riverofglorymn.org/River_of_Glory_Church/Ekklesia_Signage/pulls/1
2026-09-29 23:57:32 +00:00
ekklesia aa8cb1c96f fix: complete display and channel group management 2026-09-29 18:15:26 -05:00
ekklesia 5760059ee3 fix: make timeline activation durable and visible 2026-09-29 18:15:08 -05:00
ekklesia 92bef4c7aa feat: initial Signage 0.1.0 2026-08-28 16:41:54 -05:00
ekklesia 20756f11af first commit 2026-08-27 17:05:45 -05:00