upleb.uk

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

summaryrefslogtreecommitdiff
path: root/docs/archive/2025-11-05-grasp01-event-reference-test-design.md
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-12-03 11:19:40 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-03 11:19:40 +0000
commit2eaff5b79fed364d5eba5eb38e4b7bf76326884d (patch)
treedeacd6294f8860096ee82ee76930204efd65e33c /docs/archive/2025-11-05-grasp01-event-reference-test-design.md
parent57bc8cd9c021feaf08e139e8fb62800bc476068e (diff)
remove docs archive
Diffstat (limited to 'docs/archive/2025-11-05-grasp01-event-reference-test-design.md')
-rw-r--r--docs/archive/2025-11-05-grasp01-event-reference-test-design.md987
1 files changed, 0 insertions, 987 deletions
diff --git a/docs/archive/2025-11-05-grasp01-event-reference-test-design.md b/docs/archive/2025-11-05-grasp01-event-reference-test-design.md
deleted file mode 100644
index dd805b8..0000000
--- a/docs/archive/2025-11-05-grasp01-event-reference-test-design.md
+++ /dev/null
@@ -1,987 +0,0 @@
1# GRASP-01 Event Reference Validation Test Design
2
3**Version:** 1.0
4**Date:** 2025-11-05
5**Status:** Design Phase - Ready for Review
6
7## Executive Summary
8
9This document provides a comprehensive test design for GRASP-01 lines 7-9 compliance, covering event reference validation. The design reshapes existing test stubs to implement proper event relationship testing across all NIP-34 event types (issues, patches, PRs, comments, status updates, and text notes).
10
11## 1. Analysis Section
12
13### 1.1 NIP-34 Event Structures
14
15From `/persistent/dcdev/clones/nips/34.md`, we have these git-related event types:
16
17#### Repository Announcements (kind 30617)
18```json
19{
20 "kind": 30617,
21 "tags": [
22 ["d", "<repo-id>"],
23 ["a", "30617:<pubkey>:<repo-id>"],
24 ["clone", "<url>", ...],
25 ["relays", "<relay-url>", ...],
26 ["maintainers", "<pubkey>", ...]
27 ]
28}
29```
30
31#### Patches (kind 1617)
32```json
33{
34 "kind": 1617,
35 "tags": [
36 ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
37 ["e", "<parent-patch-id>", "", "reply"], // NIP-10 threading
38 ["p", "<repository-owner>"],
39 ["r", "<earliest-unique-commit-id>"]
40 ]
41}
42```
43
44#### Pull Requests (kind 1618)
45```json
46{
47 "kind": 1618,
48 "tags": [
49 ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
50 ["e", "<root-patch-event-id>"], // Optional revision reference
51 ["p", "<repository-owner>"],
52 ["c", "<current-commit-id>"]
53 ]
54}
55```
56
57#### Issues (kind 1621)
58```json
59{
60 "kind": 1621,
61 "tags": [
62 ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
63 ["p", "<repository-owner>"]
64 ]
65}
66```
67
68#### Comments (kind 1111 - NIP-22)
69```json
70{
71 "kind": 1111,
72 "tags": [
73 ["E", "<root-event-id>"], // Root scope (uppercase)
74 ["K", "<root-kind>"],
75 ["P", "<root-pubkey>"],
76 ["e", "<parent-event-id>"], // Parent (lowercase)
77 ["k", "<parent-kind>"],
78 ["p", "<parent-pubkey>"]
79 ]
80}
81```
82
83### 1.2 GRASP-01 Lines 7-9 Requirements
84
85Based on test stub comments in [`grasp01_nostr_relay.rs:29-36`](grasp-audit/src/specs/grasp01_nostr_relay.rs:29-36):
86
87**Line 7-9 (inferred):** Events that **tag** OR **are tagged by** accepted repository announcements SHOULD be stored.
88
89This breaks down into three scenarios:
90
911. **Events NOT referenced** by or referencing other events → SHOULD NOT be stored (orphans)
922. **Events referenced BY** an existing stored event → SHOULD be stored (forward reference)
933. **Events referencing** an existing stored event → SHOULD be stored (backward reference)
94
95### 1.3 Reference Tag Types and Semantics
96
97#### Standard Nostr Reference Tags
98
99| Tag | Purpose | Format | NIP |
100|-----|---------|--------|-----|
101| `e` | Event ID reference | `["e", "<event-id>", "<relay>", "<marker>", "<pubkey>"]` | NIP-10 |
102| `a` | Addressable event reference | `["a", "<kind>:<pubkey>:<d-tag>", "<relay>"]` | NIP-01 |
103| `p` | Pubkey reference | `["p", "<pubkey>", "<relay>"]` | NIP-01 |
104| `q` | Quote reference | `["q", "<event-id or address>", "<relay>", "<pubkey>"]` | NIP-10 |
105
106#### NIP-22 Comment Tags (Uppercase = Root, Lowercase = Parent)
107
108| Tag | Purpose | Format |
109|-----|---------|--------|
110| `E` | Root event ID | `["E", "<event-id>", "<relay>", "<pubkey>"]` |
111| `A` | Root addressable event | `["A", "<kind>:<pubkey>:<d-tag>", "<relay>"]` |
112| `K` | Root event kind | `["K", "<kind>"]` |
113| `P` | Root author pubkey | `["P", "<pubkey>", "<relay>"]` |
114| `e` | Parent event ID | `["e", "<event-id>", "<relay>", "<pubkey>"]` |
115| `k` | Parent event kind | `["k", "<kind>"]` |
116| `p` | Parent author pubkey | `["p", "<pubkey>", "<relay>"]` |
117
118#### NIP-10 Threading Tags
119
120| Marker | Purpose |
121|--------|---------|
122| `root` | First event in thread |
123| `reply` | Direct reply to parent |
124
125### 1.4 Event Type Coverage Requirements
126
127Tests must cover:
128
129- ✅ **Issues** (kind 1621) - referencing repos via `a` tag
130- ✅ **Patches** (kind 1617) - referencing repos via `a` tag, threading via `e` tags
131- ✅ **Pull Requests** (kind 1618) - referencing repos via `a` tag
132- ✅ **Comments** (kind 1111) - replying via NIP-22 structure
133- ✅ **Status updates** (kinds 1630-1633) - referencing issues/PRs via `e` tag (may also use `E` tag for root references)
134- ✅ **Text notes** (kind 1) - may reference announcements/issues/patches/comments OR be referenced by them
135
136## 2. Test Architecture Design
137
138### 2.1 Overall Test Suite Structure
139
140To manage the growing number of tests, we'll organize them into separate test module files:
141
142```
143grasp-audit/src/specs/
144├── mod.rs (module declarations)
145├── grasp01_nostr_relay.rs (main entry point, existing tests)
146└── grasp01/
147 ├── mod.rs (test suite registration)
148 ├── helpers.rs (shared helper functions)
149 ├── issues.rs (issue reference tests)
150 ├── patches.rs (patch reference tests)
151 ├── pull_requests.rs (PR reference tests)
152 ├── comments.rs (NIP-22 comment tests)
153 ├── status_updates.rs (status change tests)
154 └── text_notes.rs (kind 1 reference tests)
155```
156
157**Benefits:**
158- Better code organization and navigation
159- Isolated test contexts
160- Easier to maintain and extend
161- Clear separation of concerns
162
163### 2.2 Test Organization Strategy
164
165**Group by relationship type:**
166
1671. **Forward References** - Event A exists, send Event B that references A
1682. **Backward References** - Send Event A that references B, then send B
1693. **Bidirectional** - Events that both reference each other
1704. **Orphans** - Events with no references (should be rejected)
1715. **Transitive** - Multi-hop references (A → B → C)
172
173**Group by event type:**
174
1751. Issues referencing repos
1762. Patches referencing repos (with threading)
1773. PRs referencing repos
1784. Comments replying to issues/patches/PRs
1795. Status updates for issues/PRs
1806. Text notes being tagged by repos
181
182## 3. Helper Function Specifications
183
184### 3.1 Core Event Creation Helpers
185
186```rust
187/// Create a NIP-34 issue event
188async fn create_issue(
189 client: &AuditClient,
190 repo_announcement: &Event,
191 subject: &str,
192 content: &str,
193) -> Result<Event>
194```
195
196**Purpose:** Create properly formatted issue (kind 1621) with `a` tag to repo
197**Returns:** Signed event ready to send
198**Usage:**
199```rust
200let issue = create_issue(&client, &repo_event, "Bug: Test", "Description").await?;
201```
202
203---
204
205```rust
206/// Create a NIP-34 patch event
207async fn create_patch(
208 client: &AuditClient,
209 repo_announcement: &Event,
210 parent_patch: Option<&Event>,
211 patch_content: &str,
212) -> Result<Event>
213```
214
215**Purpose:** Create patch (kind 1617) with optional NIP-10 threading
216**Returns:** Signed event with proper `a` tag and optional `e` reply tag
217**Usage:**
218```rust
219// First patch in series
220let patch1 = create_patch(&client, &repo, None, "diff...").await?;
221
222// Reply patch
223let patch2 = create_patch(&client, &repo, Some(&patch1), "diff...").await?;
224```
225
226---
227
228```rust
229/// Create a NIP-34 pull request event
230async fn create_pull_request(
231 client: &AuditClient,
232 repo_announcement: &Event,
233 branch_name: &str,
234 commit_id: &str,
235) -> Result<Event>
236```
237
238**Purpose:** Create PR (kind 1618) with proper repo reference
239**Returns:** Signed event with `a` tag
240**Usage:**
241```rust
242let pr = create_pull_request(&client, &repo, "feature-x", "abc123").await?;
243```
244
245---
246
247```rust
248/// Create a NIP-22 comment event
249async fn create_comment(
250 client: &AuditClient,
251 root_event: &Event, // The root (issue, patch, or PR)
252 parent_event: Option<&Event>, // None for top-level, Some for replies
253 content: &str,
254) -> Result<Event>
255```
256
257**Purpose:** Create comment (kind 1111) with proper NIP-22 tags
258**Returns:** Signed event with E/K/P (root) and e/k/p (parent) tags
259**Usage:**
260```rust
261// Top-level comment
262let comment1 = create_comment(&client, &issue, None, "Great idea!").await?;
263
264// Reply to comment
265let comment2 = create_comment(&client, &issue, Some(&comment1), "Thanks!").await?;
266```
267
268---
269
270```rust
271/// Create a status event
272async fn create_status(
273 client: &AuditClient,
274 target_event: &Event, // Issue, patch, or PR
275 status_kind: Kind, // 1630 (Open), 1631 (Resolved), 1632 (Closed), 1633 (Draft)
276 reason: &str,
277) -> Result<Event>
278```
279
280**Purpose:** Create status change event
281**Returns:** Signed event with `e` tag to target
282**Usage:**
283```rust
284let status = create_status(&client, &issue, Kind::Custom(1631), "Fixed in v1.0").await?;
285```
286
287### 3.2 Test Orchestration Helpers
288
289```rust
290/// Send event and verify acceptance by querying back
291async fn send_and_verify_stored(
292 client: &AuditClient,
293 event: Event,
294) -> Result<()>
295```
296
297**Purpose:** Send event, wait for propagation, query to confirm storage
298**Reduces:** Duplication of send → wait → query → verify pattern
299**Usage:**
300```rust
301send_and_verify_stored(&client, issue_event).await?;
302```
303
304---
305
306```rust
307/// Send event and verify it was NOT stored (rejection test)
308async fn send_and_verify_rejected(
309 client: &AuditClient,
310 event: Event,
311) -> Result<()>
312```
313
314**Purpose:** Send event, verify it's not in relay storage
315**Reduces:** Duplication in negative tests
316**Usage:**
317```rust
318send_and_verify_rejected(&client, orphan_event).await?;
319```
320
321---
322
323```rust
324/// Extract repo identifier from announcement event
325fn extract_repo_id(repo_announcement: &Event) -> Result<String>
326```
327
328**Purpose:** Get `d` tag value from repo announcement
329**Reduces:** Tag parsing duplication
330**Usage:**
331```rust
332let repo_id = extract_repo_id(&repo_event)?;
333```
334
335---
336
337```rust
338/// Build addressable event tag (a tag) for repo
339fn build_repo_atag(repo_announcement: &Event) -> Result<Tag>
340```
341
342**Purpose:** Create properly formatted `a` tag for repo reference
343**Reduces:** Tag construction errors
344**Usage:**
345```rust
346let a_tag = build_repo_atag(&repo_announcement)?;
347```
348
349## 4. Test Case Specifications
350
351### 4.1 Issues Referencing Repositories
352
353#### Test: `test_accept_issue_for_repo`
354**Validates:** GRASP-01 lines 8-9 - Accept issues referencing accepted repos
355**Reference Tags:** `a` tag (repo)
356**Expected:** Issue event SHOULD be stored
357
358**Setup:**
3591. Create and send kind 30617 repo announcement
3602. Verify repo is stored
3613. Create kind 1621 issue with:
362 - `["a", "30617:{pubkey}:{d-tag}"]`
363 - `["subject", "Bug: Something broken"]`
3644. Send issue event
365
366**Verification:**
367- Query for kind 1621 with author filter
368- Verify issue event was stored
369- Verify `a` tag correctly references repo
370
371---
372
373#### Test: `test_reject_issue_for_nonexistent_repo`
374**Validates:** GRASP-01 line 7 - Reject orphaned issues
375**Reference Tags:** `a` tag (nonexistent repo)
376**Expected:** Issue event SHOULD NOT be stored
377
378**Setup:**
3791. Create kind 1621 issue with `a` tag referencing non-existent repo
3802. Send issue event
381
382**Verification:**
383- Query for issue event
384- Verify it was NOT stored (empty result)
385
386### 4.2 Patches Referencing Repositories
387
388#### Test: `test_accept_patch_for_repo`
389**Validates:** GRASP-01 lines 8-9 - Accept patches for accepted repos
390**Reference Tags:** `a` tag (repo), `p` tag, `r` tag
391**Expected:** Patch event SHOULD be stored
392
393**Setup:**
3941. Create and send repo announcement
3952. Create kind 1617 patch with:
396 - `["a", "30617:{pubkey}:{d-tag}"]`
397 - `["p", "{repo-owner}"]`
398 - `["r", "{commit-id}"]`
399 - `["t", "root"]` (first patch marker)
4003. Send patch
401
402**Verification:**
403- Query for kind 1617
404- Verify patch stored
405-Verify proper repo reference
406
407---
408
409#### Test: `test_accept_patch_series_threading`
410**Validates:** NIP-10 threading in patches
411**Reference Tags:** `e` reply tag for threading
412**Expected:** All patches in series SHOULD be stored
413
414**Setup:**
4151. Send repo announcement
4162. Create and send patch 1 with `["t", "root"]`
4173. Create patch 2 with `["e", "{patch1-id}", "", "reply"]`
4184. Create patch 3 with `["e", "{patch2-id}", "", "reply"]`
4195. Send patches 2 and 3
420
421**Verification:**
422- Query all 3 patches
423- Verify threading structure via `e` tags
424- Verify all stored
425
426### 4.3 Pull Requests Referencing Repositories
427
428#### Test: `test_accept_pull_request_for_repo`
429**Validates:** GRASP-01 lines 8-9 - Accept PRs for accepted repos
430**Reference Tags:** `a` tag, `c` tag (commit)
431**Expected:** PR event SHOULD be stored
432
433**Setup:**
4341. Send repo announcement
4352. Create kind 1618 PR with:
436 - `["a", "30617:{pubkey}:{d-tag}"]`
437 - `["c", "{commit-id}"]`
438 - `["subject", "Add feature X"]`
4393. Send PR
440
441**Verification:**
442- Query kind 1618
443- Verify PR stored with correct repo reference
444
445---
446
447#### Test: `test_accept_pr_update`
448**Validates:** PR updates (kind 1619) reference original PR
449**Reference Tags:** `E` tag (NIP-22 root), `P` tag
450**Expected:** PR update SHOULD be stored
451
452**Setup:**
4531. Create and send repo + original PR
4542. Create kind 1619 update with:
455 - `["E", "{pr-event-id}"]`
456 - `["P", "{pr-author}"]`
457 - `["c", "{new-commit-id}"]`
4583. Send update
459
460**Verification:**
461- Query kind 1619
462- Verify update references original PR
463
464### 4.4 Comments (NIP-22)
465
466#### Test: `test_accept_reply_to_issue`
467**Validates:** Comments on issues using NIP-22
468**Reference Tags:** `E`, `K`, `P` (root), `e`, `k`, `p` (parent)
469**Expected:** Comment SHOULD be stored
470
471**Setup:**
4721. Send repo + issue
4732. Create kind 1111 comment with:
474 - `["E", "{issue-id}"]` (root)
475 - `["K", "1621"]` (issue kind)
476 - `["P", "{issue-author}"]`
477 - `["e", "{issue-id}"]` (parent, same as root for top-level)
478 - `["k", "1621"]`
479 - `["p", "{issue-author}"]`
4803. Send comment
481
482**Verification:**
483- Query kind 1111
484- Verify proper NIP-22 tag structure
485
486---
487
488#### Test: `test_accept_nested_comment_thread`
489**Validates:** Multi-level comment threading
490**Reference Tags:** E/K/P (constant root), e/k/p (changing parent)
491**Expected:** All comments SHOULD be stored
492
493**Setup:**
4941. Send repo + issue
4952. Send comment 1 (to issue)
4963. Send comment 2 (reply to comment 1):
497 - Root tags point to issue
498 - Parent tags point to comment 1
4994. Send comment 3 (reply to comment 2):
500 - Root tags still point to issue
501 - Parent tags point to comment 2
502
503**Verification:**
504- Query all 3 comments
505- Verify root tags always reference issue
506- Verify parent tags form chain
507
508---
509
510#### Test: `test_accept_comment_on_patch`
511**Validates:** Comments work on patches
512**Reference Tags:** NIP-22 tags for kind 1617
513**Expected:** Comment on patch SHOULD be stored
514
515**Setup:**
5161. Send repo + patch
5172. Send kind 1111 comment referencing patch
5183. Verify stored
519
520---
521
522#### Test: `test_accept_comment_on_pr`
523**Validates:** Comments work on PRs
524**Reference Tags:** NIP-22 tags for kind 1618
525**Expected:** Comment on PR SHOULD be stored
526
527### 4.5 Status Updates
528
529#### Test: `test_accept_status_for_issue`
530**Validates:** Status changes for issues
531**Reference Tags:** `e` tag, `p` tag
532**Expected:** Status event SHOULD be stored
533
534**Setup:**
5351. Send repo + issue
5362. Create kind 1631 (Resolved) status with:
537 - `["e", "{issue-id}", "", "root"]`
538 - `["p", "{issue-author}"]`
539 - `["a", "30617:{pubkey}:{repo-id}"]` (optional)
5403. Send status
541
542**Verification:**
543- Query kind 1631
544- Verify references issue
545
546### 4.6 Text Notes and Cross-References
547
548#### Test: `test_accept_kind1_quoted_by_issue`
549**Validates:** Kind 1 text notes referenced by issues using `q` tag
550**Reference Tags:** Issue's `q` tag pointing to kind 1 note
551**Expected:** Kind 1 note SHOULD be accepted when issue quotes it
552
553**Setup:**
5541. Create kind 1 text note about project
5552. Send text note (may initially be rejected)
5563. Send repo announcement
5574. Create kind 1621 issue with:
558 - `["a", "30617:{pubkey}:{d-tag}"]` (repo reference)
559 - `["q", "{note-id}"]` (quote reference to kind 1)
560 - `["subject", "Discussion: Feature Request"]`
5615. Send issue
5626. Re-query for text note
563
564**Verification:**
565- Text note should now be stored
566- Verifies kind 1 being referenced by issue scenario
567
568## 5. Implementation Phases
569
570### Phase 1: Module Structure Setup (Priority: HIGH)
571**Goal:** Create new test suite file structure
572**Duration:** 0.5 days
573
574**Tasks:**
5751. Create `grasp-audit/src/specs/grasp01/` directory
5762. Set up module files:
577 - `mod.rs` (test registration)
578 - `helpers.rs` (shared functions)
579 - `issues.rs`
580 - `patches.rs`
581 - `pull_requests.rs`
582 - `comments.rs`
583 - `status_updates.rs`
584 - `text_notes.rs`
5853. Update `grasp-audit/src/specs/mod.rs` to include new module
586
587**Acceptance Criteria:**
588- Module structure compiles
589- Tests can be run from new location
590- No duplicate code
591
592### Phase 2: Helper Functions (Priority: HIGH)
593**Goal:** Core helper functions in `helpers.rs`
594**Duration:** 1 day
595
596**Tasks:**
5971. Implement core event creation helpers:
598 - `create_issue()`
599 - `create_patch()`
600 - `create_pull_request()`
601 - `create_comment()`
602 - `create_status()`
603
6042. Implement test orchestration helpers:
605 - `send_and_verify_stored()`
606 - `send_and_verify_rejected()`
607 - `extract_repo_id()`
608 - `build_repo_atag()`
609
610**Acceptance Criteria:**
611- All helper functions documented
612- Unit tests for helpers
613- Functions follow nostr-sdk 0.43 API
614
615### Phase 3: Core Event Type Tests (Priority: HIGH)
616**Goal:** Implement tests for issues, patches, PRs
617**Duration:** 1.5 days
618
619**Tasks:**
6201. Implement in `issues.rs`:
621 - `test_accept_issue_for_repo`
622 - `test_reject_issue_for_nonexistent_repo`
623
6242. Implement in `patches.rs`:
625 - `test_accept_patch_for_repo`
626 - `test_accept_patch_series_threading`
627
6283. Implement in `pull_requests.rs`:
629 - `test_accept_pull_request_for_repo`
630 - `test_accept_pr_update`
631
632**Acceptance Criteria:**
633- All tests pass against ngit-relay
634- Proper event tagging
635- Clear test documentation
636
637### Phase 4: Comment Threading (Priority: HIGH)
638**Goal:** NIP-22 comment support in `comments.rs`
639**Duration:** 1 day
640
641**Tasks:**
6421. Implement comment tests:
643 - `test_accept_reply_to_issue`
644 - `test_accept_nested_comment_thread`
645 - `test_accept_comment_on_patch`
646 - `test_accept_comment_on_pr`
647
648**Acceptance Criteria:**
649- Multi-level threading works
650- Uppercase/lowercase tag handling correct
651- All comment tests pass
652
653### Phase 5: Status Updates and Text Notes (Priority: MEDIUM)
654**Goal:** Complete remaining event types
655**Duration:** 1 day
656
657**Tasks:**
6581. Implement in `status_updates.rs`:
659 - `test_accept_status_for_issue`
660
6612. Implement in `text_notes.rs`:
662 - `test_accept_kind1_quoted_by_issue`
663
664**Acceptance Criteria:**
665- Status updates work correctly
666- Kind 1 quote references validated
667- All tests documented
668
669### Phase 6: Documentation and Finalization (Priority: HIGH)
670**Goal:** Complete documentation and code review
671**Duration:** 0.5 days
672
673**Tasks:**
6741. Add comprehensive doc comments to all modules
6752. Create migration guide from old structure
6763. Update main README with new structure
6774. Code review and refactoring
6785. Run full test suite verification
679
680**Acceptance Criteria:**
681- All modules documented
682- Clear organization
683- No compiler warnings
684- All tests pass
685
686## 6. Edge Cases and Considerations
687
688### 6.1 Potential Edge Cases
689
6901. **Event Arrival Order:**
691 - Issue arrives before repo announcement
692 - Comment arrives before target event
693 - **Mitigation:** Test both orders, document relay behavior
694
6952. **Reference Ambiguity:**
696 - Multiple `a` tags to different repos
697 - Conflicting `e` tags
698 - **Mitigation:** Document which reference takes precedence
699
7003. **Deleted Events:**
701 - Event references something that gets deleted
702 - **Mitigation:** Test and document behavior
703
7044. **Malformed Tags:**
705 - Invalid `a` tag format
706 - Missing required tag components
707 - **Mitigation:** Test rejection with clear errors
708
7095. **Threading Depth:**
710 - Very deep reply chains (100+ levels)
711 - **Mitigation:** Set reasonable limits, test performance
712
7136. **Circular References:**
714 - A references B, B references A
715 - **Mitigation:** Prevent infinite loops, document handling
716
717### 6.2 Performance Considerations
718
7191. **Query Efficiency:**
720 - Use specific filters (kind + author)
721 - Avoid full relay scans
722 - Timeout after 5 seconds
723
7242. **Event Batching:**
725 - Send multiple events efficiently
726 - Wait between sends (100ms) for propagation
727
7283. **Cleanup:**
729 - All events have audit tags for cleanup
730 - Use `run_id` for isolation
731
732### 6.3 Test Isolation Requirements
733
7341. **Unique Identifiers:**
735 - Use UUIDs for repo IDs
736 - Avoid collisions between test runs
737
7382. **Audit Tags:**
739 - Automatic via `AuditClient::event_builder()`
740 - Enable production cleanup
741
7423. **Relay State:**
743 - Assume shared relay (ngit-relay)
744 - Don't depend on empty state
745
746## 7. Implementation Guidelines
747
748### 7.1 Code Style
749
750Follow existing patterns in [`grasp01_nostr_relay.rs`](grasp-audit/src/specs/grasp01_nostr_relay.rs):
751
752```rust
753/// Test: <description>
754///
755/// Spec: Line X of ../grasp/01.md
756/// Requirement: <exact or paraphrased requirement>
757async fn test_name(client: &AuditClient) -> TestResult {
758 TestResult::new(
759 "test_name",
760 "GRASP-01:nostr-relay:X",
761 "Human-readable requirement description",
762 )
763 .run(|| async {
764 // Test implementation
765 Ok(())
766 })
767 .await
768}
769```
770
771### 7.2 nostr-sdk 0.43 API Usage
772
773**Field Access (NOT method calls):**
774```rust
775event.id // ✅ Correct
776event.tags // ✅ Correct
777event.tags.iter() // ✅ Correct
778
779event.id() // ❌ Wrong (0.35 API)
780```
781
782**Tag Construction:**
783```rust
784Tag::custom(TagKind::custom("a"), vec!["30617:pubkey:repo-id"]) // ✅
785Tag::identifier("repo-id") // ✅
786Tag::from_standardized(TagStandard::PublicKey { ... }) // ✅
787```
788
789**Event Building:**
790```rust
791client.event_builder(kind, content)
792 .tag(tag1)
793 .tag(tag2)
794 .build(client.keys())?
795```
796
797### 7.3 Test Naming Convention
798
799Pattern: `test_{action}_{subject}_{condition}`
800
801Examples:
802- `test_accept_issue_for_repo` (positive)
803- `test_reject_orphan_issue` (negative)
804- `test_accept_nested_comment_thread` (complex)
805
806### 7.4 Error Handling
807
808```rust
809.run(|| async {
810 // Create events
811 let repo = client.create_repo_announcement("test").await
812 .map_err(|e| format!("Failed to create repo: {}", e))?;
813
814 // Send events
815 client.send_event(repo.clone()).await
816 .map_err(|e| format!("Failed to send to relay: {}", e))?;
817
818 // Verify results
819 let events = client.query(filter).await
820 .map_err(|e| format!("Failed to query: {}", e))?;
821
822 if events.is_empty() {
823 return Err("Event not stored".to_string());
824 }
825
826 Ok(())
827})
828```
829
830## 8. Test Data Patterns
831
832### 8.1 Sample Event IDs
833Use realistic hex event IDs:
834```rust
835"abc123def456789012345678901234567890abcd" // 40 hex characters
836```
837
838### 8.2 Sample Pubkeys
839Use proper npub format:
840```rust
841client.public_key().to_bech32()? // Real key from client
842```
843
844### 8.3 Sample Repo IDs
845Use test name + UUID:
846```rust
847format!("test-{}-{}", test_name, Timestamp::now().as_u64())
848```
849
850## 9. Acceptance Criteria
851
852### 9.1 Code Quality
853
854- ✅ All functions have doc comments
855- ✅ No compiler warnings
856- ✅ Follows existing code patterns
857- ✅ Uses nostr-sdk 0.43 API correctly
858- ✅ Proper error messages
859
860### 9.2 Test Coverage
861
862- ✅ All 7 test stubs implemented
863- ✅ All NIP-34 event types covered
864- ✅ All reference tag types tested
865- ✅ Both positive and negative cases
866- ✅ Edge cases documented
867
868### 9.3 Passing Tests
869
870- ✅ All tests pass against ngit-relay
871- ✅ Tests properly isolated
872- ✅ No flaky tests
873- ✅ Clear failure messages
874
875## 10. References
876
877- **NIP-34:** `/persistent/dcdev/clones/nips/34.md` (Git Stuff)
878- **NIP-10:** `/persistent/dcdev/clones/nips/10.md` (Threading)
879- **NIP-22:** `/persistent/dcdev/clones/nips/22.md` (Comments)
880- **Current Implementation:** [`grasp01_nostr_relay.rs:29-36`](grasp-audit/src/specs/grasp01_nostr_relay.rs:29-36)
881- **Client Helpers:** [`client.rs:193-235`](grasp-audit/src/client.rs:193-235)
882- **AGENTS.md:** Code patterns and testing guidelines
883
884## 11. Next Steps
885
8861. **Review this design document with user**
8872. **Get approval or iterate on design**
8883. **Switch to Code mode for implementation**
8894. **Implement Phase 1 (Foundation)**
8905. **Test against ngit-relay**
8916. **Iterate through remaining phases**
892
893## Appendix A: Test Flow Diagram
894
895```
896Event Reference Testing Flow
897============================
898
899┌─────────────────────────────────────────────────┐
900│ Setup: Create Repo Announcement │
901│ - Send kind 30617 with clone/relays tags │
902│ - Verify acceptance and storage │
903└────────────────┬────────────────────────────────┘
904
905
906┌─────────────────────────────────────────────────┐
907│ Test 1: Issues (kind 1621) │
908│ ┌─────────────────────────────────────────────┐│
909│ │ → Create issue with 'a' tag to repo ││
910│ │ → Send to relay ││
911│ │ → Query back ││
912│ │ → Verify stored ││
913│ └─────────────────────────────────────────────┘│
914└────────────────┬────────────────────────────────┘
915
916
917┌─────────────────────────────────────────────────┐
918│ Test 2: Patches (kind 1617) │
919│ ┌─────────────────────────────────────────────┐│
920│ │ → Create patch with 'a' tag to repo ││
921│ │ → Optionally thread with 'e' tag ││
922│ │ → Send and verify ││
923│ └─────────────────────────────────────────────┘│
924└────────────────┬────────────────────────────────┘
925
926
927┌─────────────────────────────────────────────────┐
928│ Test 3: Pull Requests (kind 1618) │
929│ ┌─────────────────────────────────────────────┐│
930│ │ → Create PR with 'a' tag and 'c' commit ││
931│ │ → Send and verify ││
932│ └─────────────────────────────────────────────┘│
933└────────────────┬────────────────────────────────┘
934
935
936┌─────────────────────────────────────────────────┐
937│ Test 4: Comments (kind 1111 - NIP-22) │
938│ ┌─────────────────────────────────────────────┐│
939│ │ Top-level: ││
940│ │ E/K/P → Issue ││
941│ │ e/k/p → Issue (same as root) ││
942│ │ Nested: ││
943│ │ E/K/P → Issue (unchanged) ││
944│ │ e/k/p → Parent Comment ││
945│ └─────────────────────────────────────────────┘│
946└────────────────┬────────────────────────────────┘
947
948
949┌─────────────────────────────────────────────────┐
950│ Test 5: Status Updates (kinds 1630-1633) │
951│ ┌─────────────────────────────────────────────┐│
952│ │ → Create status with 'e' tag to issue/PR ││
953│ │ → Test state transitions ││
954│ └─────────────────────────────────────────────┘│
955└────────────────┬────────────────────────────────┘
956
957
958┌─────────────────────────────────────────────────┐
959│ Test 6: Negative Cases │
960│ ┌─────────────────────────────────────────────┐│
961│ │ → Orphan events (no references) ││
962│ │ → Invalid references ││
963│ │ → Verify rejection ││
964│ └──────────────────────────── ────────────────┘│
965└─────────────────────────────────────────────────┘
966```
967
968## Appendix B: Helper Function Dependency Graph
969
970```
971Helper Functions
972================
973
974create_repo_announcement() (exists in AuditClient)
975
976 ├─→ extract_repo_id()
977 └─→ build_repo_atag()
978
979 ├─→ create_issue()
980 ├─→ create_patch()
981 ├─→ create_pull_request()
982 ├─→ create_comment()
983 └─→ create_status()
984
985 ├─→ send_and_verify_stored()
986 └─→ send_and_verify_rejected()
987```