<feed xmlns='http://www.w3.org/2005/Atom'>
<title>npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/src/sync, branch v1.0.1</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=v1.0.1</id>
<link rel='self' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=v1.0.1'/>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/'/>
<updated>2026-02-26T15:42:09+00:00</updated>
<entry>
<title>chore: apply cargo fmt and fix clippy warnings</title>
<updated>2026-02-26T15:42:09+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-26T15:42:09+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=9d86cf15f0275ffeee4519bd054e3b61dc8992ac'/>
<id>urn:sha1:9d86cf15f0275ffeee4519bd054e3b61dc8992ac</id>
<content type='text'>
Fix pre-existing clippy lints:
- &amp;PathBuf -&gt; &amp;Path in audit_cleanup.rs
- too_many_arguments on process_newly_available_git_data,
  process_purgatory_announcements, and HttpService::new
- clone_on_copy for PublicKey (Copy type) in purgatory cleanup loop
</content>
</entry>
<entry>
<title>Merge master into 3ca0-announcements-purgatory</title>
<updated>2026-02-23T15:20:59+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-23T15:20:59+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=113928aa84894ea8f65c247d9987527e792b32a9'/>
<id>urn:sha1:113928aa84894ea8f65c247d9987527e792b32a9</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor: replace inline purgatory sync registration with timer-only approach</title>
<updated>2026-02-23T12:48:26+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-23T12:48:26+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=f62ef12fb84e2210f9a0a67a5e1e574a8ee66c16'/>
<id>urn:sha1:f62ef12fb84e2210f9a0a67a5e1e574a8ee66c16</id>
<content type='text'>
Remove the redundant inline kind-30617 registration block from the sync
event loop and the three is_generic/recompute_new_sync_filters_for_relay
calls from confirm_batch error paths. The purgatory announcement sync
timer (run_purgatory_announcement_sync) is now the sole registration path.

Consolidate NGIT_SYNC_BATCH_WINDOW_MS and NGIT_PURGATORY_SYNC_INTERVAL_MS
into a single NGIT_TEST=1 flag that sets both timers to 200ms, replacing
two ad-hoc env vars with one reusable test-mode flag.
</content>
</entry>
<entry>
<title>fix: replace repo_sync_index wiring with purgatory announcement sync timer</title>
<updated>2026-02-18T20:32:13+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T20:32:13+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=ee113a654e2971a6ebdb07398cc5638dbe59b48c'/>
<id>urn:sha1:ee113a654e2971a6ebdb07398cc5638dbe59b48c</id>
<content type='text'>
Instead of threading repo_sync_index through PolicyContext/builder.rs/main.rs
to handle user-submitted purgatory announcements, add a simple background
timer (run_purgatory_announcement_sync, every 5s) that scans the purgatory
for announcement entries and registers them in repo_sync_index as StateOnly.

This is simpler and covers both flows:
- Sync-path announcements: inline registration still happens during event
  processing (sync/mod.rs:1839+), timer provides a safety net
- User-submitted announcements: SelfSubscriber never sees them (rejected
  from DB), timer is the primary registration path

The timer calls sync_purgatory_announcements_to_index() which:
1. Snapshots purgatory via new announcements_for_sync() public method
2. Or_inserts StateOnly entries (never downgrades Full entries)
3. Detects newly added relay URLs and calls handle_new_sync_filters to
   connect and subscribe - fixing the failing test that expected relay
   discovery from a user-submitted purgatory announcement

Removes: repo_sync_index field from PolicyContext, set/get_repo_sync_index
methods, set_repo_sync_index on Nip34WritePolicy, wiring in main.rs, and
the inline AcceptPurgatory registration block in builder.rs.
</content>
</entry>
<entry>
<title>fix: simplify purgatory sync - fix SelfSubscriber sync_level upgrade and negentropy fallback</title>
<updated>2026-02-18T19:41:29+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T19:41:29+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=e22021f0b248ebcf3bd09210d59b2cdb4701032f'/>
<id>urn:sha1:e22021f0b248ebcf3bd09210d59b2cdb4701032f</id>
<content type='text'>
Three targeted fixes for purgatory announcement sync:

1. SelfSubscriber sync_level upgrade: After or_insert_with in process_batch,
   always set entry.sync_level = SyncLevel::Full so that when a promoted
   announcement is broadcast via notify_event and SelfSubscriber receives it,
   an existing StateOnly entry gets upgraded to Full and PR event subscriptions
   are triggered immediately (not delayed up to 24h).

2. Negentropy fallback filter split: In handle_eose, when falling back from
   negentropy to REQ+EOSE, split batch_repos by SyncLevel and call
   build_sync_level_aware_filters instead of build_layer2_and_layer3_filters.
   Prevents StateOnly (purgatory) repos from getting Layer 2 #a/#A/#q filters
   prematurely, which caused nostr-sdk client deduplication to permanently
   drop PR events after orphan rejection.

3. Recompute sync filters after announcement batch EOSE: Add
   recompute_new_sync_filters_for_relay calls at all three batch-completion
   paths in handle_eose for generic filter (announcement) batches. This
   triggers state-only subscriptions for any purgatory repos registered during
   that batch, fixing the 24h delay before state event sync starts.

4. User-submitted purgatory announcements: Add repo_sync_index field to
   PolicyContext with setter/getter, wire in main.rs after SyncManager
   creation, and register in AcceptPurgatory handler so user-submitted
   announcements get StateOnly sync started immediately.

5. Update archive tests: test_archive_without_state_events_does_not_sync_git
   updated to reflect that StateOnly subscription now proactively fetches
   state events from source relays. test_archive_read_only_creates_bare_repo
   un-ignored as it now works end-to-end.
</content>
</entry>
<entry>
<title>Revert "fix: use sync-level-aware filters in negentropy fallback to prevent premature PR event delivery"</title>
<updated>2026-02-18T19:28:44+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T19:28:44+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=a804164468d3beafb243ece12555b4d1692a075d'/>
<id>urn:sha1:a804164468d3beafb243ece12555b4d1692a075d</id>
<content type='text'>
This reverts commit 806936e7d1aab5dfd0c2ad6b98a115122dc1785c.
</content>
</entry>
<entry>
<title>fix: use sync-level-aware filters in negentropy fallback to prevent premature PR event delivery</title>
<updated>2026-02-18T17:12:04+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T17:12:04+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=806936e7d1aab5dfd0c2ad6b98a115122dc1785c'/>
<id>urn:sha1:806936e7d1aab5dfd0c2ad6b98a115122dc1785c</id>
<content type='text'>
StateOnly repos in a pending batch had their repo IDs included in the
negentropy REQ+EOSE fallback, which called build_layer2_and_layer3_filters.
This generated #a/#A/#q tag filters for repos whose announcements were
still in purgatory (not yet promoted to the database).

When the remote relay responded with PR events matching those filters,
the write policy correctly rejected them as 'orphan' (no accepted repo
in DB yet). However, nostr-sdk's client-level deduplication then silently
dropped the same event on all subsequent deliveries, making it permanently
unavailable even after the announcement was promoted.

Fix: split batch_repos into full vs state-only by consulting repo_sync_index
at fallback time, then call build_sync_level_aware_filters which only
generates #a/#A/#q filters for Full repos. StateOnly repos only get
the kind 30618 + #d filter they were originally subscribed with.
</content>
</entry>
<entry>
<title>feat: add SyncLevel to sync system for purgatory announcement state-only sync</title>
<updated>2026-02-13T19:59:36+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-13T19:59:36+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=e922e14e3ec4b898c111b2100cd63dddbe2fcdb1'/>
<id>urn:sha1:e922e14e3ec4b898c111b2100cd63dddbe2fcdb1</id>
<content type='text'>
Purgatory announcements need state events (kind 30618) synced from
external relays, but not full L2/L3 events (patches, issues, PRs)
which would be rejected anyway. This implements the SyncLevel concept
from the design doc (decision #6):

- Add SyncLevel enum (Full vs StateOnly) to RepoSyncNeeds
- When announcement enters purgatory during sync, register in
  RepoSyncIndex with SyncLevel::StateOnly
- Add build_sync_level_aware_filters() that partitions repos by level:
  StateOnly repos only get state event filters (kind 30618)
- Update derive_relay_targets to track state_only_repos separately
- Update compute_actions to handle both repo sets
- SelfSubscriber always uses SyncLevel::Full (promoted repos)
</content>
</entry>
<entry>
<title>fix: revert wrong sync approach for purgatory announcements</title>
<updated>2026-02-13T17:42:08+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-13T17:42:08+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=8c903c9449d387c9b0edefa5aa283b176a3ed0cb'/>
<id>urn:sha1:8c903c9449d387c9b0edefa5aa283b176a3ed0cb</id>
<content type='text'>
The partial fix treating ProcessResult::Purgatory as confirmed in
pending_sync_index would trigger full L2/L3 sync for purgatory
announcements. Per design (decision #6), purgatory announcements
should only sync state events via SyncLevel::StateOnly (not yet
implemented).

Ignore test_archive_read_only_creates_bare_repo until SyncLevel
is implemented in Phase 3.
</content>
</entry>
<entry>
<title>feat: implement announcement purgatory core (breaks archive sync test)</title>
<updated>2026-02-13T17:29:23+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-13T13:24:46+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=1d09e4bdea7e328cf2740818df9df660c5532a99'/>
<id>urn:sha1:1d09e4bdea7e328cf2740818df9df660c5532a99</id>
<content type='text'>
Route new announcements to purgatory instead of accepting immediately.
Announcements are promoted to the database when git data arrives,
ensuring we only serve announcements for repos with actual content.

Implemented:
- AnnouncementPurgatoryEntry type and DashMap store
- Route new announcements to purgatory (replacement announcements skip)
- Promote announcements on git data arrival (process_purgatory_announcements)
- Authorization checks purgatory announcements (fetch_repository_data_with_purgatory)
- State policy uses purgatory announcements for maintainer validation
- Cleanup task handles announcement expiry
- Updated count()/cleanup() to 3-tuples

Known broken:
- test_archive_read_only_creates_bare_repo fails: sync module does not
  treat purgatory announcements as confirmed repos, so per-repo sync
  (state events, PRs) is never triggered for purgatory announcements
- Announcement persistence (save/restore) not implemented
- SyncLevel (StateOnly vs Full) not implemented
- Soft expiry two-phase not implemented
- Expiry extension on state event / git auth not wired up
</content>
</entry>
</feed>
