upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-01-05sync all repos when authorised state data push receivedDanConwayDev
2026-01-05purgatory: git data sync applies state and saves eventDanConwayDev
2026-01-05purgatory: state git data sync use single command to fetch oidsDanConwayDev
2026-01-05purgatory: add state git data syncDanConwayDev
2026-01-02sync: use purgatoryDanConwayDev
don't save new events destined for purgatory events directly to db or serve on websockets don't download events already in purgatory via negentropy sync
2026-01-02test: fix issue kind numberDanConwayDev
2026-01-02docs: remove purgatory implementation planDanConwayDev
2025-12-31test: remove local sync on state git data received testDanConwayDev
because the current fixtures don't actually having mutliple owner_repos. they would need 2 announcements that both listed the service and a maintainer relationship. We could do this in grasp-audit but it would require an extra announcement from a different maintainer sent eariler on in the dependancy chain.
2025-12-31purgatory: when state data recieved sync across repositoiesDanConwayDev
2025-12-31test: fix ↵DanConwayDev
test_push_to_nostr_ref_with_correct_commit_after_event_received_accepted_and_event_served
2025-12-31test: fix test_head_set_after_git_push_with_required_oidsDanConwayDev
2025-12-31test: fix purgatory not-served check outcomeDanConwayDev
2025-12-31purgatory: fix pr event recieve codeDanConwayDev
2025-12-31purgatory: fix state event receive codeDanConwayDev
2025-12-30purgatory: improve git authorization integetrationDanConwayDev
2025-12-24feat(purgatory): add broken purgatory implementationDanConwayDev
2025-12-23test: add purgatory to PR push testDanConwayDev
commented out so it currently passes
2025-12-23test: add stub for purgatory maintainer repo sync testDanConwayDev
2025-12-23test: prepare other state tests for purgatory featureDanConwayDev
2025-12-23test: prepare OwnerStateDataPushed fixture for purgatoryDanConwayDev
This is the model for how to prepare all push tests for purgatory
2025-12-23test: remove test covered elsewhereDanConwayDev
as new feature purgatory is going to complicate having this test here. it will be better to have this covered in push authorisation
2025-12-23audit: updated grasp01 line refs to reflect purgatory insertionDanConwayDev
2025-12-23docs: purgatory designDanConwayDev
2025-12-22chore: cargo fmt and clippyDanConwayDev
2025-12-22chore: bump rust-nostr to latest masterDanConwayDev
so we can more easily support grasp purgatory feature
2025-12-22accept all UserGraspList for better discoveryDanConwayDev
2025-12-22docs: proactive sync hand written overview rewrite and AI update of restDanConwayDev
2025-12-22fix: sync consoldate subscription countDanConwayDev
2025-12-22sync: add req rate-limit detection and cooldownDanConwayDev
2025-12-19docs: sync updates to reflect changesDanConwayDev
2025-12-19docs: sync add pagination updatesDanConwayDev
2025-12-19test: sync add test for pagination of historic that requires manually ↵DanConwayDev
setting lower thresholds
2025-12-19feat(sync): implement pagination for historic_sync REQ+EOSE flowDanConwayDev
Add automatic pagination support for non-Negentropy historic sync to handle large result sets efficiently. When a subscription receives >= 75 events, the system automatically fetches the next page using the 'until' parameter. Changes: - Add PaginationState struct to track event counts and min timestamps - Add pagination_state HashMap to PendingBatch for per-subscription tracking - Add PAGINATION_THRESHOLD constant (75 events) - Pass pending_sync_index to event processor for state updates - Track events and timestamps as they arrive - Check threshold on EOSE and launch follow-up subscriptions - Initialize pagination state when creating historic sync subscriptions - Update test fixtures in algorithms.rs The pagination continues recursively until a page returns fewer than 75 events, ensuring complete historic data retrieval without overwhelming relay limits.
2025-12-19docs: cleanupDanConwayDev
2025-12-19Simplify sync metrics to track only newly saved eventsDanConwayDev
Replace broken event counting that occurred before duplicate/policy checks with accurate tracking of events that are new, accepted, and saved. Changes: - Added ProcessResult enum to track event processing outcomes - Modified process_event_static() to return ProcessResult - Replaced events_total (with source labels) with events_synced_total - Removed gap_events_total and event_source module - Removed eose_received flag (EOSE is per-subscription, not suitable) - Updated all tests to use new simplified API The new ngit_sync_events_synced_total metric only counts events that: 1. Are new (not duplicates) 2. Pass write policy validation 3. Are successfully saved to database All 165 tests pass (124 lib + 41 integration)
2025-12-19sync: fix autoclose on EOSE for historic filtersDanConwayDev
2025-12-19refactor: rename connect_and_subscribe to connectDanConwayDev
Separated connection from subscription logic. The RelayConnection.connect() method now only handles WebSocket connection establishment. Subscriptions are managed separately via handle_connect_or_reconnect. Changes: - Renamed RelayConnection::connect_and_subscribe() to connect() - Removed subscription logic from connect method - Updated call site in try_connect_relay() - Removed unused build_announcement_filter import
2025-12-19Fix: Capture old_last_connected before updating stateDanConwayDev
Bug: handle_connect_or_reconnect() was incorrectly calling quick_reconnect() on first connections instead of fresh_start(). Root cause: The code updated last_connected = Some(now) at line 808, then immediately read it back at line 932 to make the reconnection decision. This meant first connections saw elapsed = now - now = 0 seconds, which triggered quick_reconnect() instead of fresh_start(). Fix: Capture old_last_connected BEFORE updating the state, then use that value for the reconnection decision. Now first connections correctly see None and call fresh_start(). Impact: - First connections now properly use fresh_start() with full historic sync - Short disconnections (< 15 min) use quick_reconnect() with since filter - Long disconnections (> 15 min) use fresh_start() with full resync All 41 sync tests passing.
2025-12-19fix: prevent CLOSED messages from terminating relay connectionsDanConwayDev
The system was incorrectly treating subscription-specific CLOSED messages as connection-wide disconnects, causing live subscriptions to be terminated immediately after historic_sync completed. Two bugs fixed: 1. relay_connection.rs: Removed break on RelayMessage::Closed - it's subscription-specific, not connection-wide 2. mod.rs: Removed disconnect handling for RelayEvent::Closed - only log at DEBUG level and continue All 41 sync tests now pass including previously failing live sync tests.
2025-12-19sync: negentropy fixesDanConwayDev
2025-12-19test: fix test_multi_source_aggregate_countsDanConwayDev
2025-12-19test: fix test_live_sync_event_countDanConwayDev
2025-12-19test: clear names for sync testsDanConwayDev
2025-12-18docs: archive sync test refactoring options documentDanConwayDev
2025-12-18docs: document sync test refactoring findings and patternsDanConwayDev
- Add comprehensive test pattern guidance to tests/sync/mod.rs - Explain when to use run_sync_test() vs manual setup - Document helper scope and architectural limitations Key findings: - historic_sync.rs: 4 tests refactored, 143 lines removed (50% reduction) - live_sync/discovery/tag_variations: Manual setup required due to architectural incompatibilities (timing, multi-relay, assertions) - Helper works for batch historic verification, not real-time scenarios Detailed summary available in work/sync-test-refactor-summary.md
2025-12-18refactor: migrate historic_sync.rs tests to use run_sync_test() helperDanConwayDev
- Refactored all 4 tests in historic_sync.rs to use run_sync_test() - Tests maintain same logic and assertions, only setup simplified - Moved run_sync_test() and SyncTestResult outside #[cfg(test)] module - Updated validation to allow empty event slices (for announcement-only tests) - All 4 historic_sync tests passing (test_bootstrap_syncs_existing_layer2_events, test_relay_replays_events_after_restart, test_announcement_not_listing_relay_is_not_synced, test_history_sync_without_negentropy) - Result: 39/40 tests passing (1 more than Phase 1 baseline of 38/40)
2025-12-18refactor: rename bootstrap.rs to historic_sync.rs for clarityDanConwayDev
2025-12-18test: add unified run_sync_test() helper infrastructureDanConwayDev
Add SyncTestResult struct and run_sync_test() helper function to sync_helpers.rs for unified test setup. The helper automatically determines sync mode (historic vs live) based on which event slice has content. Features: - SyncTestResult: holds test fixtures (relays, keys, repo_coord) - run_sync_test(): unified setup for both historic and live sync tests - Panic guards for invalid usage (both slices or neither) - Unit tests for panic conditions Test results: 40 tests total, 38 passing (same as baseline) - 2 pre-existing metric test failures (unchanged from baseline) - All new panic condition tests passing - No regressions introduced
2025-12-18docs: establish sync test baseline before refactoringDanConwayDev
2025-12-18sync: turn off negentropy and fix some testsDanConwayDev
2025-12-18sync: fix sync connectionDanConwayDev
2025-12-18sync: new connection logicDanConwayDev
2025-12-18sync removing dead codeDanConwayDev
2025-12-16proactive sync prep - some helper functions written but not enabledDanConwayDev
2025-12-12docs: fix sync SyncMethod in architecture docDanConwayDev
2025-12-12fix: remove misleading fallback claim from negentropy sync error logDanConwayDev
The log message claimed 'will fall back to REQ+EOSE' but no such fallback was implemented - the function simply returns 0 and exits.
2025-12-12fix: unify sync state tracking for negentropy and REQ+EOSE pathsDanConwayDev
When negentropy (NIP-77) sync was enabled, the RelaySyncIndex was never updated to reflect historical sync completion. This caused the three-way diff algorithm in compute_actions() to malfunction, leading to: - Repeated sync attempts for the same items - Incorrect filter counting for consolidation - Potential premature relay disconnection This fix unifies both sync paths (REQ+EOSE and Negentropy) through a consistent PendingBatch flow: 1. Added SyncMethod enum to distinguish between sync types 2. Updated PendingBatch struct to include sync_method field 3. Extracted confirm_batch() method for unified batch confirmation 4. Modified negentropy_sync_and_process() to: - Create a PendingBatch before sync - Add batch to pending_sync_index - On success: Remove batch and call confirm_batch() - On failure: Remove batch without confirming The confirm_batch() method moves repos and root_events from the batch to the RelayState.repos and RelayState.root_events, ensuring the three-way diff works correctly regardless of sync method. Closes: negentropy-sync-state-tracking.md
2025-12-11sync: remove reply kind from sync filters for root eventsDanConwayDev
they are legacy and not root events
2025-12-11docs: relay-limitsDanConwayDev
2025-12-11fix: resolve all fmt and clippy warningsDanConwayDev
Main lib (src/): - Add #[allow(dead_code)] for build_info field (stored to prevent Prometheus unregistration) - Add #[allow(dead_code)] for first_seen field (reserved for future rate limiting) - Replace .or_insert_with(RelaySyncNeeds::default) with .or_default() - Replace manual div_ceil implementations with .div_ceil(100) Test code (tests/): - Replace .expect(&format!(...)) with .unwrap_or_else(|_| panic!(...)) - Remove needless borrows in fetch_metrics() calls - Add #[allow(dead_code)] and #[allow(unused_imports)] to test helpers module grasp-audit: - Apply cargo fmt to fix formatting
2025-12-11sync: test sync works without negentropy and add disable option in syncDanConwayDev
2025-12-11feat: implement NIP-77 negentropy sync for historical dataDanConwayDev
Replace EOSE-based sync completion with negentropy reconciliation for: - Initial connect (fresh sync) - Daily sync (Layer 1 announcements) - Stale reconnect (>15 min) Key changes: - Add NegentropySyncResult struct with remote_only, local_only, received fields - Add supports_negentropy() using try-and-fallback approach - Add negentropy_sync_filter() using nostr-sdk client.sync() API - Modify handle_connect_or_reconnect() to use negentropy for fresh/stale sync - Modify daily_sync() to use negentropy for Layer 1 - Single-warning logging per relay when negentropy fails Quick reconnects (<15 min) unchanged - still use REQ with since filter. If negentropy unsupported, gracefully falls back to REQ+EOSE flow.
2025-12-11test: nip77 smoke testDanConwayDev
2025-12-11docs(tests): replace catchup.rs test with documentationDanConwayDev
The catchup sync mechanism (reconnection with since filter) is implemented in src/sync/mod.rs handle_connect_or_reconnect(), but cannot be reliably integration tested with current infrastructure: - TestRelay uses in-memory database (events lost on stop) - No way to force WebSocket disconnection without stopping relay - Stopping syncing relay creates new instance (fresh sync, not catchup) Convert the skeleton test file to comprehensive documentation explaining: - How catchup sync works (since filter on reconnect) - The 15-minute quick reconnect window logic - Why integration testing is not feasible - Alternative approaches that could enable testing - Related tests that cover adjacent functionality
2025-12-11docs: simplify grasp-02 docDanConwayDev
2025-12-11docs: remove old grasp-02 design doc versionsDanConwayDev
2025-12-11fix docsDanConwayDev
2025-12-11fix(sync): add Layer 1 re-subscription to daily_sync()DanConwayDev
- Add Layer 1 (announcements) re-subscription in daily_sync() after unsubscribe_all() to ensure kinds 30617+30618 are re-established - Clarify comments in handle_connect_or_reconnect() explaining that Layer 1 subscription is established during connect_and_subscribe() Addresses implementation gaps from design vs implementation report: - Gap 1: Comments clarified (Layer 1 handled by connect_and_subscribe) - Gap 2: daily_sync() now re-subscribes to Layer 1 without since filter - Gap 3: consolidate() already had Layer 1 re-subscription (no change) All 125 unit tests and integration tests pass.
2025-12-11chore: remove unused sync config fieldsDanConwayDev
Remove 4 config fields that were defined but never used: - sync_startup_delay_secs - sync_reconnect_delay_secs - sync_reconnect_lookback_days - sync_startup_jitter_ms These fields were added during GRASP-02 planning but the implementation took a different approach (using hardcoded constants for quick reconnect windows and batch window via env var).
2025-12-11fix: sync metrics aggregate relay countsDanConwayDev
2025-12-11fix: classify sync events as startup/live based on EOSE, not relay typeDanConwayDev
Previously, events were classified as 'startup' or 'live' based on whether they came from a bootstrap relay (is_bootstrap flag). This meant ALL events from bootstrap relays were counted as 'startup', even events received after the initial sync completed. Now events are classified based on whether EOSE (End Of Stored Events) has been received for that connection: - Events BEFORE EOSE → 'startup' (historical events during initial sync) - Events AFTER EOSE → 'live' (new events via real-time subscription) This enables the test_live_sync_event_count test which validates that events received after sync connection is established are counted as live events. Also removed the #[ignore] attribute from test_live_sync_event_count since the metrics are now properly wired up.
2025-12-11docs(sync): document why RelayConnection uses Client instead of Relay directlyDanConwayDev
nostr-sdk 0.44's Relay::new() is pub(crate), making it impossible to construct a Relay directly from outside the crate. Relays can only be created through Client::add_relay() or RelayPool::add_relay(). This commit: - Adds 'Why Client instead of Relay directly?' section to struct docs - Updates run_event_loop() docs to explain the API constraint - Removes outdated 'Future Refactoring' suggestion (not feasible)
2025-12-11refactor: use Relay::notifications() for event-driven disconnect detectionDanConwayDev
Replace the 1-second polling loop with nostr-sdk's relay-level notification system that provides immediate disconnect detection via RelayNotification::RelayStatus. Key changes: - Use relay.notifications() instead of client.notifications() - Handle RelayNotification::RelayStatus { Disconnected | Terminated } to detect connection loss immediately without polling - Remove tokio::select! with interval timer - now uses simple match loop - Handle additional notification types (Authenticated, AuthenticationFailed) Why this is better: - Event-driven vs polling: no wasted CPU cycles checking every second - Immediate detection: disconnect triggers notification instantly - Uses nostr-sdk's built-in mechanism that was previously inaccessible at pool level (RelayStatus notifications are filtered out in RelayPoolNotification) Technical note: RelayNotification::RelayStatus is only available via Relay::notifications(), not Client::notifications(), because the pool-level broadcast filters out status change events. Future refactoring opportunity: Consider restructuring RelayConnection to hold a Relay directly instead of wrapping a Client, since we only manage one relay per connection anyway.
2025-12-11fix: wire up relay disconnection detection for metricsDanConwayDev
- Add periodic health check in RelayConnection::run_event_loop that polls nostr-sdk's relay.is_connected() every second to detect dead connections - When event channel closes without explicit Closed/Shutdown, send DisconnectNotification to SyncManager (fixes case where TCP drops silently) - Enable test_relay_connected_status test which validates the ngit_sync_relay_connected metric correctly reflects connection state The issue was that when a remote relay stops abruptly, nostr-sdk's notification receiver blocks indefinitely waiting for data. TCP disconnect detection without keepalive can take minutes. The health check polls nostr-sdk's internal relay status which detects disconnection promptly.
2025-12-11fix: resolve duplicate SyncMetrics registration preventing metrics recordingDanConwayDev
Root cause: Both Metrics::new() and SyncManager::new() were trying to register SyncMetrics with the same Prometheus registry. The second registration failed silently, leaving SyncManager.metrics = None, so record_connection_attempt() calls were no-ops. Changes: - SyncManager::new() now accepts Option<SyncMetrics> instead of Option<&Registry> - main.rs passes already-registered sync metrics from Metrics to SyncManager - Simplified test_connection_failure_increments_counter assertion - Marked 3 tests as #[ignore] pending relay tracking metrics wiring Tests fixed: - test_connection_failure_increments_counter (now counts failures) - test_health_state_degrades_on_failure (now tracks health state) - test_live_sync_layer3_events (already working, confirmed) Tests ignored (future work): - test_live_sync_event_count - test_multi_source_aggregate_counts - test_relay_connected_status
2025-12-11sync: add sync_base_backoff_secs config for better testingDanConwayDev
2025-12-11sync: improve connection timeout handlingDanConwayDev
2025-12-11fix(sync): improve metrics recording and connection failure detectionDanConwayDev
Changes: - Fix connection attempt metrics: record success/failure based on actual connection result instead of pre-emptively recording failure - Add health tracker integration on connection failure: call record_failure() and record_health_state() in error path - Add connection verification in relay_connection.rs: wait 500ms after connect() then verify is_connected() to detect silent failures - Add configurable disconnect check interval via NGIT_SYNC_DISCONNECT_CHECK_INTERVAL_SECS env var - Update TestRelay with fast test settings: startup_delay=0, jitter=0, disconnect_check_interval=1s - Add debug output to metrics tests for investigation Note: Tests may still fail due to 5-second base backoff in health tracker. A follow-up task will add NGIT_SYNC_BASE_BACKOFF_SECS config parameter to allow faster test cycles. Related: metrics-wiring-plan.md Tasks 1 & 2
2025-12-11Phase 4: Add health state and multi-relay aggregate testsDanConwayDev
2025-12-11Phase 3: Delete useless tests, add 3 real metrics testsDanConwayDev
Deleted 12 existence-only tests that provided zero confidence: - test_sync_metrics_exposed - test_sync_metric_names_present - test_connection_metrics_on_success - test_event_sync_metrics - test_health_state_metrics - test_gap_event_tracking - test_connection_failure_metrics - test_failure_counter_increments - test_relay_count_metrics - test_event_source_labels_in_metrics - test_multi_relay_load - test_gap_events_tracked_separately Kept 5 valuable tests: - test_prometheus_format_valid - test_concurrent_metrics_requests - test_metric_values_are_numeric - test_startup_sync_event_count - test_metrics_availability_during_sync Added 3 real value-checking tests (currently ignored): - test_connection_failure_increments_counter - test_live_sync_event_count - test_relay_connected_status Test results: 6 passed, 0 failed, 3 ignored
2025-12-11Phase 2: Add first real metrics test (startup event count)DanConwayDev
2025-12-11Phase 1: Add ParsedMetrics and MetricsTestHarness infrastructureDanConwayDev
2025-12-11test: add additional sync metrics tests for better coverage (Phase 8)DanConwayDev
2025-12-11refactor: move metrics tests to tests/sync/ structure (Phase 7)DanConwayDev
2025-12-11feat: add event metrics tracking throughout sync (Phase 5)DanConwayDev
2025-12-10feat: connect REGISTRY to SyncManager (Phase 3)DanConwayDev
2025-12-10feat: add metrics field to SyncManager (Phase 2)DanConwayDev
2025-12-10feat: create sync metrics module (Phase 1)DanConwayDev
2025-12-10fix: enable Layer 3 sync by adding root events to pending queueDanConwayDev
When root events (issues/patches) are received via self-subscription, handle_root_event() was only updating the repo_sync_index directly. This caused process_batch() to early-return when pending.is_empty(), so Layer 3 filters for comments/replies were never created. The fix adds root events to both: 1. repo_sync_index (for immediate availability) 2. pending queue (to trigger Layer 3 filter creation in next batch) Critical: The pending entry must include relays from repo_sync_index so derive_relay_targets() knows where to send Layer 3 subscriptions. The Layer 3 test now verifies that events sent BEFORE the subscription is established are still synced - proving subscriptions without 'since' correctly fetch historical events. Enabled 4 previously ignored Layer 3 tests: - test_live_sync_layer3_events - test_layer3_sync_with_lowercase_e_tag - test_layer3_sync_with_uppercase_e_tag - test_layer3_sync_with_q_tag
2025-12-10feat(sync): broadcast synced events to WebSocket subscribersDanConwayDev
Enable recursive relay discovery by broadcasting synced events to WebSocket subscribers via LocalRelay.notify_event(). This allows the SelfSubscriber to receive 30617 announcements synced from external relays and discover additional relay URLs to connect to. Changes: - Pass LocalRelay to SyncManager::new() from main.rs - Add local_relay field to SyncManager struct - Call notify_event() after saving synced events to database - Enable test_recursive_relay_discovery_syncs_announcement test The test verifies that when relay_a syncs announcement_x from bootstrap relay_b (which lists relay_c), relay_a discovers and connects to relay_c to sync announcement_y. Fixes recursive relay discovery from bootstrap sync.
2025-12-10test(sync): add wait_for_sync_connection helper for improved reliabilityDanConwayDev
2025-12-10test(sync): add 3-relay recursive discovery testDanConwayDev
2025-12-10test(sync): add rejection test for announcements without clone tagsDanConwayDev
2025-12-10refactor(tests): extract shared create_repo_announcement helperDanConwayDev
2025-12-10Phase 10: Remove obsolete proactive_sync_basic.rs test fileDanConwayDev
All tests from this file have been migrated to the new modular structure: - tests/sync/bootstrap.rs (Tests 1, 4) - tests/sync/discovery.rs (Tests 2, 3) - tests/sync/live_sync.rs (Tests 5, 6, 7) - tests/sync/tag_variations.rs (Tests 8a-c, 9a-c) - tests/sync/catchup.rs (Test 0) Verified: cargo test --test sync shows 19 passed, 5 ignored
2025-12-10Phase 8: Create catchup sync stub testDanConwayDev
2025-12-10Phase 7: Implement tag variation testsDanConwayDev
Add comprehensive tests for different Layer 2 and Layer 3 tag variations: Layer 2 tests (Tests 8a-c) - all pass: - test_layer2_sync_with_lowercase_a_tag (standard NIP-01) - test_layer2_sync_with_uppercase_a_tag (NIP-33) - test_layer2_sync_with_q_tag (NIP-18 quotes) Layer 3 tests (Tests 9a-c) - marked #[ignore]: - test_layer3_sync_with_lowercase_e_tag (NIP-01) - test_layer3_sync_with_uppercase_e_tag (NIP-22) - test_layer3_sync_with_q_tag (NIP-18) Layer 3 tests have full implementation but are ignored until Layer 3 sync is enabled in the relay.
2025-12-10Phase 6: Implement live sync testsDanConwayDev
2025-12-10Phase 5: Migrate bootstrap and discovery testsDanConwayDev
Create organized test structure for proactive sync: tests/common/sync_helpers.rs (from Phase 4): - TestClient with retry logic for connect/send - Event builders: build_layer2_issue_event, build_layer3_comment_event - Tag variants (a/A/q for Layer 2, e/E/q for Layer 3) - wait_for_event_on_relay() assertion helper - repo_coord() utility function - Unit tests for all builders tests/sync/mod.rs: - Module organization for sync tests - Documentation of test categories tests/sync.rs: - Main test harness including common and sync modules tests/sync/bootstrap.rs: - test_bootstrap_syncs_existing_layer2_events (Test 1) - test_relay_replays_events_after_restart (Test 4) tests/sync/discovery.rs: - test_discovers_layer3_via_layer2 (Test 2) - test_layer2_discovery_with_chain (Test 3 - simplified) All 14 tests pass: cargo test --test sync
2025-12-10sync: fix connection registration issueDanConwayDev