Skip to content

Catch up characters from Chronicle's change feed - #128

Merged
keyxmakerx merged 2 commits into
mainfrom
claude/project-thread-bs6baq
Oct 3, 2026
Merged

keyxmakerx merged 2 commits into
mainfrom
claude/project-thread-bs6baq

Conversation

@keyxmakerx

@keyxmakerx keyxmakerx commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Fixes: none
Security implication: none. It uses the same feed route and API key as the journal catch-up (GET /sync/changes, which needs an owner key). Nothing is deleted: a removed character only unlinks its actor.
Consumer-verified: Chronicle internal/plugins/syncapi change feed (/sync/changes, merged in #957 and earlier) and GET /entities/:id; the bench exercises both against Chronicle main at 82578dd.
Foundry compatibility: n/a. No new Foundry API is used; it runs through the same actor update/flag calls as before. Not live-checked in a Foundry world (#94).
Mockup: n/a, nothing on screen changes.

What this changes

Before: every time Foundry connected, it listed every character in Chronicle and rewrote each linked actor, even when nothing had changed.

After: on connect, linked actors catch up only on the characters the change feed says changed. An actor already at Chronicle's version is left alone, including on the full walk. Reopening a world with nothing new writes nothing. A character deleted in Chronicle unlinks its actor and keeps it. An older copy never rolls an actor back.

Why

This is step 3 of the agreed Foundry sync rebuild, characters after journals (module #125). The hard requirements were no duplicate copies, changes that are safe to repeat, and a passing two-sided bench before anything is called ready.

  • scripts/actor-sync.mjs:
    • adds feedArea = 'actors' and feedActive();
    • in delta mode, onInitialSync({feed}) calls _catchUpFromFeed;
    • _atVersion and _olderThanRecorded guard every apply;
    • a failure throws, so the shared cursor is not saved and the next connect replays.
  • _notifySyncIssues({quick}) counts unlinked actors locally on a delta connect instead of listing all of Chronicle. That listing was the remaining full walk on reopen.
  • bench/scenario.mjs holds the shared bench helpers. assertHealthy now also fails on duplicate actors, and on a character that exists as both an actor and a journal.

Deviation: an untouched character listed in the feed is still fetched once, by design: the feed carries ids, not versions. The bench asserts data writes only, because Chronicle publishes a stale updated_at after a fields update, which can cause a harmless flag-only rewrite. That is filed on keyxmakerx/Chronicle#985.

Test plan

  • node --test tools/test-*.mjs: 1023 tests, 1023 pass, 0 fail, with module main (Player notebook and Jot notes tab in Foundry #126) merged in (5 new in tools/test-actor-feed.mjs)
  • node tools/check-package-descriptor.mjs: n/a, the descriptor is unchanged
  • Manual verification in Foundry: not done (no Foundry runtime here; live checks tracked in Live test session on Foundry v14 (after TESTING.md is brought up to date) #94)
  • If UI-touching: n/a
  • CHRONICLE_DIR=../Chronicle bench/run.sh against Chronicle main (82578dd), rerun after merging module main: 16 of 16 scenarios pass, 4 of them new for characters:
    • live create makes one actor and no journal;
    • offline changes arrive from the feed, and a second open writes nothing;
    • a deleted character unlinks its actor and keeps it;
    • a Foundry HP edit is pushed once and not re-applied on reopen.
  • CI passes

Tenet self-check

  • T-B1 security: no new route or token handling; nothing is deleted without asking
  • T-B2 plugin isolation: changes stay inside the module
  • T-B3 production UI: n/a
  • T-B4 dual-audience docs: .ai.md, CLAUDE.md and bench/README.md now say journals and characters use the feed

Generated by Claude Code

Linked actors now refresh on connect from the change feed instead of
listing every character, and skip any actor already at the entity's
version (the full walk too), so a reconnect with nothing new writes
nothing. A removed character unlinks its actor; a stale copy never rolls
an actor back; failures throw so the cursor stays. The bench gains
character scenarios and shares its checks through bench/scenario.mjs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018uKa2E5HNdeubwBSD9Jn4n
@keyxmakerx
keyxmakerx marked this pull request as ready for review October 3, 2026 15:27
@keyxmakerx
keyxmakerx merged commit 8c060d0 into main Oct 3, 2026
2 checks passed
@keyxmakerx
keyxmakerx deleted the claude/project-thread-bs6baq branch October 3, 2026 15:52
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.

2 participants