···11----
22-"@atmo-dev/contrail-appview": patch
33-"@atmo-dev/contrail-base": patch
44----
55-66-Stop running the `feed_items` prune sweep on every ingest tick.
77-88-A feed only exceeds its cap right after a feed-mutating record, so the per-tick sweep was a no-op on the vast majority of ticks yet still issued a cutoff `DELETE` per actor (~98% of all D1 queries on one deployment). It now sweeps only when a feed-mutating collection was ingested, plus a recovery pass that becomes due ~6h after the previous one completed and then laps one slice per tick — including on idle persistent streams and the `notifyOfUpdate` path. New `getFeedMutatingNsids(config)` derives the gating set. See `docs/04-feeds.md` for sweep timing (and why the full-pass cadence is interval + lap time, not a hard 6h) and the fan-out promptness trade-off.
-24
.changeset/fts-nsid-keyed-collections.md
···11----
22-"@atmo-dev/contrail-base": patch
33-"@atmo-dev/contrail-appview": patch
44-"@atmo-dev/contrail-record-host": patch
55-"@atmo-dev/contrail-lexicons": patch
66----
77-88-Make NSID-keyed collections work through normal ingestion, not just FTS.
99-1010-When a collection is keyed directly by its NSID (no short alias, `collection`
1111-field omitted), the value defaulted to `undefined` everywhere it was read. The
1212-records insert and FTS sync were patched via `resolveCollectionKey`, but the
1313-real ingestion entry points still skipped these collections: `getCollectionNsids`
1414-/ `getDiscoverableNsids` / `getDependentNsids` produced `undefined` NSIDs (so
1515-Jetstream never subscribed and backfill never ran), `shortNameForNsid` returned
1616-undefined (so `notify` rejected the URI as "collection not tracked"), and
1717-`validateConfig` rejected the config outright (missing `collection`, dotted key
1818-failing short-name validation).
1919-2020-`CollectionConfig.collection` is now optional. `resolveConfig` normalizes an
2121-omitted `collection` to the map key, `validateConfig` accepts NSID-keyed entries,
2222-and every collection-list / lookup helper resolves the NSID as `collection ?? key`
2323-so the behavior is correct on both raw and resolved configs.
2424-</content>
···11----
22-"@atmo-dev/contrail-appview": patch
33----
44-55-Persist the jetstream ingest cursor before the identity-refresh tail in `runIngestCycle`.
66-77-`saveCursor` previously ran after `refreshStaleIdentities`, whose per-DID network calls can run long. If the ingest isolate was aborted (e.g. a scheduled-invocation deadline) before the save, the cursor never advanced and the next cycle re-drained the same jetstream window indefinitely. Records are durably applied before this point, so the cursor is now saved first; identity refresh is idempotent and staleness-driven, so deferring it past the save is safe.
-10
.changeset/single-jetstream-no-cursor-rollback.md
···11----
22-"@atmo-dev/contrail-base": patch
33-"@atmo-dev/contrail-appview": patch
44----
55-66-Stop re-ingesting the last 10s on every cron cycle for single-instance jetstream configs.
77-88-`@atcute/jetstream` rolls the cursor back 10s on the first connect when given an array `url`, to absorb clock skew across a pool of interchangeable instances. Contrail's cron ingestion rebuilds the subscription every cycle, so for a single-instance config that once-per-session rollback fired every cycle and redundantly re-delivered the last 10s of events. A new `jetstreamUrlOption` helper hands a one-element config to `@atcute` as a string (one fixed instance, no skew, no rollback) while leaving real multi-instance pools as an array so their cross-instance rollback is preserved. Applied at both subscription construction sites (cron `ingestEvents` and the persistent daemon).
99-1010-The per-cycle reconnect log is now accurate for single-instance configs: a reconnect to one fixed instance no longer claims to "pick a URL at random and roll the cursor back 10s" (it can't). The warning now fires only for multi-instance pools and reports the actual `rolled_back` value; single-instance reconnects log at info level confirming no rollback.
+43
packages/contrail-appview/CHANGELOG.md
···11# @atmo-dev/contrail-appview
2233+## 0.12.1
44+55+### Patch Changes
66+77+- 833a659: Stop running the `feed_items` prune sweep on every ingest tick.
88+99+ A feed only exceeds its cap right after a feed-mutating record, so the per-tick sweep was a no-op on the vast majority of ticks yet still issued a cutoff `DELETE` per actor (~98% of all D1 queries on one deployment). It now sweeps only when a feed-mutating collection was ingested, plus a recovery pass that becomes due ~6h after the previous one completed and then laps one slice per tick — including on idle persistent streams and the `notifyOfUpdate` path. New `getFeedMutatingNsids(config)` derives the gating set. See `docs/04-feeds.md` for sweep timing (and why the full-pass cadence is interval + lap time, not a hard 6h) and the fan-out promptness trade-off.
1010+1111+- 74a2d3d: Make NSID-keyed collections work through normal ingestion, not just FTS.
1212+1313+ When a collection is keyed directly by its NSID (no short alias, `collection`
1414+ field omitted), the value defaulted to `undefined` everywhere it was read. The
1515+ records insert and FTS sync were patched via `resolveCollectionKey`, but the
1616+ real ingestion entry points still skipped these collections: `getCollectionNsids`
1717+ / `getDiscoverableNsids` / `getDependentNsids` produced `undefined` NSIDs (so
1818+ Jetstream never subscribed and backfill never ran), `shortNameForNsid` returned
1919+ undefined (so `notify` rejected the URI as "collection not tracked"), and
2020+ `validateConfig` rejected the config outright (missing `collection`, dotted key
2121+ failing short-name validation).
2222+2323+ `CollectionConfig.collection` is now optional. `resolveConfig` normalizes an
2424+ omitted `collection` to the map key, `validateConfig` accepts NSID-keyed entries,
2525+ and every collection-list / lookup helper resolves the NSID as `collection ?? key`
2626+ so the behavior is correct on both raw and resolved configs.
2727+ </content>
2828+2929+- 9e01ada: Persist the jetstream ingest cursor before the identity-refresh tail in `runIngestCycle`.
3030+3131+ `saveCursor` previously ran after `refreshStaleIdentities`, whose per-DID network calls can run long. If the ingest isolate was aborted (e.g. a scheduled-invocation deadline) before the save, the cursor never advanced and the next cycle re-drained the same jetstream window indefinitely. Records are durably applied before this point, so the cursor is now saved first; identity refresh is idempotent and staleness-driven, so deferring it past the save is safe.
3232+3333+- 9894787: Stop re-ingesting the last 10s on every cron cycle for single-instance jetstream configs.
3434+3535+ `@atcute/jetstream` rolls the cursor back 10s on the first connect when given an array `url`, to absorb clock skew across a pool of interchangeable instances. Contrail's cron ingestion rebuilds the subscription every cycle, so for a single-instance config that once-per-session rollback fired every cycle and redundantly re-delivered the last 10s of events. A new `jetstreamUrlOption` helper hands a one-element config to `@atcute` as a string (one fixed instance, no skew, no rollback) while leaving real multi-instance pools as an array so their cross-instance rollback is preserved. Applied at both subscription construction sites (cron `ingestEvents` and the persistent daemon).
3636+3737+ The per-cycle reconnect log is now accurate for single-instance configs: a reconnect to one fixed instance no longer claims to "pick a URL at random and roll the cursor back 10s" (it can't). The warning now fires only for multi-instance pools and reports the actual `rolled_back` value; single-instance reconnects log at info level confirming no rollback.
3838+3939+- Updated dependencies [833a659]
4040+- Updated dependencies [74a2d3d]
4141+- Updated dependencies [9894787]
4242+ - @atmo-dev/contrail-base@0.12.1
4343+ - @atmo-dev/contrail-record-host@0.12.1
4444+ - @atmo-dev/contrail-authority@0.12.1
4545+346## 0.12.0
447548### Minor Changes
···11# @atmo-dev/contrail-base
2233+## 0.12.1
44+55+### Patch Changes
66+77+- 833a659: Stop running the `feed_items` prune sweep on every ingest tick.
88+99+ A feed only exceeds its cap right after a feed-mutating record, so the per-tick sweep was a no-op on the vast majority of ticks yet still issued a cutoff `DELETE` per actor (~98% of all D1 queries on one deployment). It now sweeps only when a feed-mutating collection was ingested, plus a recovery pass that becomes due ~6h after the previous one completed and then laps one slice per tick — including on idle persistent streams and the `notifyOfUpdate` path. New `getFeedMutatingNsids(config)` derives the gating set. See `docs/04-feeds.md` for sweep timing (and why the full-pass cadence is interval + lap time, not a hard 6h) and the fan-out promptness trade-off.
1010+1111+- 74a2d3d: Make NSID-keyed collections work through normal ingestion, not just FTS.
1212+1313+ When a collection is keyed directly by its NSID (no short alias, `collection`
1414+ field omitted), the value defaulted to `undefined` everywhere it was read. The
1515+ records insert and FTS sync were patched via `resolveCollectionKey`, but the
1616+ real ingestion entry points still skipped these collections: `getCollectionNsids`
1717+ / `getDiscoverableNsids` / `getDependentNsids` produced `undefined` NSIDs (so
1818+ Jetstream never subscribed and backfill never ran), `shortNameForNsid` returned
1919+ undefined (so `notify` rejected the URI as "collection not tracked"), and
2020+ `validateConfig` rejected the config outright (missing `collection`, dotted key
2121+ failing short-name validation).
2222+2323+ `CollectionConfig.collection` is now optional. `resolveConfig` normalizes an
2424+ omitted `collection` to the map key, `validateConfig` accepts NSID-keyed entries,
2525+ and every collection-list / lookup helper resolves the NSID as `collection ?? key`
2626+ so the behavior is correct on both raw and resolved configs.
2727+ </content>
2828+2929+- 9894787: Stop re-ingesting the last 10s on every cron cycle for single-instance jetstream configs.
3030+3131+ `@atcute/jetstream` rolls the cursor back 10s on the first connect when given an array `url`, to absorb clock skew across a pool of interchangeable instances. Contrail's cron ingestion rebuilds the subscription every cycle, so for a single-instance config that once-per-session rollback fired every cycle and redundantly re-delivered the last 10s of events. A new `jetstreamUrlOption` helper hands a one-element config to `@atcute` as a string (one fixed instance, no skew, no rollback) while leaving real multi-instance pools as an array so their cross-instance rollback is preserved. Applied at both subscription construction sites (cron `ingestEvents` and the persistent daemon).
3232+3333+ The per-cycle reconnect log is now accurate for single-instance configs: a reconnect to one fixed instance no longer claims to "pick a URL at random and roll the cursor back 10s" (it can't). The warning now fires only for multi-instance pools and reports the actual `rolled_back` value; single-instance reconnects log at info level confirming no rollback.
3434+335## 0.12.0
436537### Minor Changes
+1-1
packages/contrail-base/package.json
···11{
22 "name": "@atmo-dev/contrail-base",
33- "version": "0.12.0",
33+ "version": "0.12.1",
44 "description": "Shared infrastructure for the contrail family of packages — interfaces (SpaceAuthority, RecordHost, CommunityIntegration), credential primitives, binding resolvers, realtime infra, schema scaffolding. No routes, no tables of its own.",
55 "type": "module",
66 "sideEffects": false,
···11{
22 "name": "@atmo-dev/contrail-community",
33- "version": "0.12.0",
33+ "version": "0.12.1",
44 "description": "Community module for contrail — community-owned spaces with tiered access levels (member → moderator → admin), invite tokens, DID provisioning, and the access-level reconciler that keeps spaces_members in sync.",
55 "type": "module",
66 "sideEffects": false,
+27
packages/contrail-record-host/CHANGELOG.md
···11# @atmo-dev/contrail-record-host
2233+## 0.12.1
44+55+### Patch Changes
66+77+- 74a2d3d: Make NSID-keyed collections work through normal ingestion, not just FTS.
88+99+ When a collection is keyed directly by its NSID (no short alias, `collection`
1010+ field omitted), the value defaulted to `undefined` everywhere it was read. The
1111+ records insert and FTS sync were patched via `resolveCollectionKey`, but the
1212+ real ingestion entry points still skipped these collections: `getCollectionNsids`
1313+ / `getDiscoverableNsids` / `getDependentNsids` produced `undefined` NSIDs (so
1414+ Jetstream never subscribed and backfill never ran), `shortNameForNsid` returned
1515+ undefined (so `notify` rejected the URI as "collection not tracked"), and
1616+ `validateConfig` rejected the config outright (missing `collection`, dotted key
1717+ failing short-name validation).
1818+1919+ `CollectionConfig.collection` is now optional. `resolveConfig` normalizes an
2020+ omitted `collection` to the map key, `validateConfig` accepts NSID-keyed entries,
2121+ and every collection-list / lookup helper resolves the NSID as `collection ?? key`
2222+ so the behavior is correct on both raw and resolved configs.
2323+ </content>
2424+2525+- Updated dependencies [833a659]
2626+- Updated dependencies [74a2d3d]
2727+- Updated dependencies [9894787]
2828+ - @atmo-dev/contrail-base@0.12.1
2929+330## 0.12.0
431532### Patch Changes
+1-1
packages/contrail-record-host/package.json
···11{
22 "name": "@atmo-dev/contrail-record-host",
33- "version": "0.12.0",
33+ "version": "0.12.1",
44 "description": "Default record-host implementation for contrail — stores records and blobs for permissioned spaces, enforces local enrollment as the host's consent layer.",
55 "type": "module",
66 "sideEffects": false,
···11# @atmo-dev/contrail-lexicons
2233+## 0.4.14
44+55+### Patch Changes
66+77+- 74a2d3d: Make NSID-keyed collections work through normal ingestion, not just FTS.
88+99+ When a collection is keyed directly by its NSID (no short alias, `collection`
1010+ field omitted), the value defaulted to `undefined` everywhere it was read. The
1111+ records insert and FTS sync were patched via `resolveCollectionKey`, but the
1212+ real ingestion entry points still skipped these collections: `getCollectionNsids`
1313+ / `getDiscoverableNsids` / `getDependentNsids` produced `undefined` NSIDs (so
1414+ Jetstream never subscribed and backfill never ran), `shortNameForNsid` returned
1515+ undefined (so `notify` rejected the URI as "collection not tracked"), and
1616+ `validateConfig` rejected the config outright (missing `collection`, dotted key
1717+ failing short-name validation).
1818+1919+ `CollectionConfig.collection` is now optional. `resolveConfig` normalizes an
2020+ omitted `collection` to the map key, `validateConfig` accepts NSID-keyed entries,
2121+ and every collection-list / lookup helper resolves the NSID as `collection ?? key`
2222+ so the behavior is correct on both raw and resolved configs.
2323+ </content>
2424+2525+ - @atmo-dev/contrail@0.12.1
2626+327## 0.4.13
428529### Patch Changes