<feed xmlns='http://www.w3.org/2005/Atom'>
<title>npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/src/main.rs, branch master</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<id>https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=master</id>
<link rel='self' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/'/>
<updated>2026-04-10T19:26:23+00:00</updated>
<entry>
<title>feat: add cleanup-empty-repos subcommand to remove stale events for empty git repos</title>
<updated>2026-04-10T19:26:23+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-04-10T19:26:23+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=8aef478c6b1e9e3f6ebbad6d57f59f1a84a261ea'/>
<id>urn:sha1:8aef478c6b1e9e3f6ebbad6d57f59f1a84a261ea</id>
<content type='text'>
Adds a maintenance subcommand that scans the LMDB database for kind 30617
(repository announcement) events whose bare git repo on disk is empty or
missing, then removes both the 30617 and any matching 30618 (state) events.

A relay should not serve announcement or state events for a repository with
no git data. This was needed to clean up repos leaked by the bug fixed in
2161e3c, and is useful as an ongoing maintenance tool.

Usage (dry-run by default, stop relay before --execute):
  ngit-grasp cleanup-empty-repos [--relay-data-path &lt;path&gt;] [--git-data-path &lt;path&gt;] [--execute]

The relay itself is now invoked as an implicit 'serve' subcommand, preserving
full backward compatibility with existing deployments and env-var configuration.
</content>
</entry>
<entry>
<title>add background job to clean up grasp-audit test events and git repos</title>
<updated>2026-02-24T12:45:26+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-24T12:45:26+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=3f4dc8e1bc07f88c064d4734f5cc3ee87b1497e4'/>
<id>urn:sha1:3f4dc8e1bc07f88c064d4734f5cc3ee87b1497e4</id>
<content type='text'>
Spawns a tokio task that runs every 30 minutes and removes all events
tagged 'grasp-audit-test-event' older than 2 hours from the LMDB
database, along with their associated bare git repositories on disk.
</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>fix: re-process hot-cache maintainer announcements after git push promotion</title>
<updated>2026-02-23T12:05:29+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-23T11:17:10+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=70749ea9df1f6061c332112c617b615f91d79d48'/>
<id>urn:sha1:70749ea9df1f6061c332112c617b615f91d79d48</id>
<content type='text'>
When an owner announcement is promoted from purgatory via a git push,
any maintainer announcements sitting in the rejected_events_index hot
cache were never re-processed. The invalidate_and_get call only existed
in SyncManager::process_event_static (the nostr sync path); the git push
promotion path (http -&gt; handlers -&gt; git::sync) had no access to the
rejected_events_index at all.

Thread rejected_events_index and write_policy through the git push path:
- process_purgatory_announcements: after saving the promoted announcement,
  parse its maintainers tag and call invalidate_and_get() for each, then
  re-process any returned hot-cache events via admit_event + save
- process_newly_available_git_data: accept optional write_policy and
  rejected_events_index, pass them through to process_purgatory_announcements
- handle_receive_pack: accept Arc&lt;Nip34WritePolicy&gt; and
  Arc&lt;RejectedEventsIndex&gt;, pass them to process_newly_available_git_data
- HttpService / run_server: carry the two new fields, clone into each
  handle_receive_pack call
- main.rs: obtain rejected_events_index from sync_manager before moving
  it into its task; wrap write_policy in Arc for the HTTP server
- RealSyncContext::process_newly_available_git_data: pass None for both
  new params (purgatory sync path already handles this via
  SyncManager::process_event_static)

Also rewrite the maintainer_reprocessing integration tests to correctly
exercise the hot-cache path now that announcements require git data
before being released from purgatory:
- Start relay_b with relay_a as bootstrap so its SyncManager syncs
  maintainer announcements via negentropy before the owner git push
- Use push_unique_git_data_to_relay (new helper) to give each maintainer
  a distinct commit hash, preventing git from skipping pack transfer
- Make wait_for_event_on_relay poll in a retry loop so transient timing
  gaps between DB write and query do not cause false negatives
</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 "feat: upgrade repo to Full sync and trigger PR event subscription after announcement promotion"</title>
<updated>2026-02-18T19:28:28+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T19:28:28+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=3d9359d5ac0045fb93fd8732160e0de8413d6881'/>
<id>urn:sha1:3d9359d5ac0045fb93fd8732160e0de8413d6881</id>
<content type='text'>
This reverts commit d76003b629a4a03dba23a8a1c41da6e4ac4c30cf.
</content>
</entry>
<entry>
<title>feat: upgrade repo to Full sync and trigger PR event subscription after announcement promotion</title>
<updated>2026-02-18T17:12:17+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-18T17:12:17+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=d76003b629a4a03dba23a8a1c41da6e4ac4c30cf'/>
<id>urn:sha1:d76003b629a4a03dba23a8a1c41da6e4ac4c30cf</id>
<content type='text'>
When git data arrives for a purgatory announcement and promotes it to the
database, the relay now:

1. Upgrades the announcement's sync level in RepoSyncIndex from StateOnly
   to Full (git/sync.rs: process_purgatory_announcements)
2. Sends AddFilters actions to SyncManager for all connected relays, using
   Full sync filters (Layer 2 #a/#A/#q) to subscribe to PR events
   (purgatory/sync/context.rs: RealSyncContext.process_newly_available_git_data)
3. For user-submitted purgatory announcements, registers the repo in
   RepoSyncIndex with StateOnly level and sends AddFilters to SyncManager
   so it discovers and connects to relays listed in the announcement tags
   (nostr/builder.rs: handle_announcement AcceptPurgatory path)

The RealSyncContext now accepts optional repo_sync_index and sync_action_tx
parameters. main.rs wires these up from SyncManager. PolicyContext gains
repo_sync_index and sync_action_tx fields for the write policy path.
</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>
<entry>
<title>Handle SIGTERM for graceful shutdown with systemd</title>
<updated>2026-02-03T22:22:53+00:00</updated>
<author>
<name>DanConwayDev</name>
<email>DanConwayDev@protonmail.com</email>
</author>
<published>2026-02-03T22:22:53+00:00</published>
<link rel='alternate' type='text/html' href='https://upleb.uk/npub1tkq8unhsd5jqx6ueex5lcpsgknrpquxuk44ftpjlpm3ulaake7xs76txrw/ngit-grasp-mirror/commit/?id=e0ad39a489b3398f8208713bf728db0cb11475b0'/>
<id>urn:sha1:e0ad39a489b3398f8208713bf728db0cb11475b0</id>
<content type='text'>
Listen for both SIGINT (Ctrl+C) and SIGTERM (systemd) signals to ensure
graceful shutdown cleanup runs when stopping the service via systemd.

Previously, only SIGINT was handled, causing purgatory state and rejected
events cache to be lost on every systemd restart. Now both signals trigger
the cleanup code that saves state files and removes placeholder refs.

Fixes issue 0f73
</content>
</entry>
</feed>
