ADRs: - Update 0008-honor, 0009-courage, 0013-overflow, 0015-plausibility - Add 0017-hosted-coding-assistant-architecture RFCs: - 0032: per-repo AWS profile configuration (draft) - 0033: round-scoped dialogue files (impl + plan) - 0034: comprehensive config architecture (accepted) - 0036: expert output discipline (impl) - 0037: single source protocol authority (draft) - 0038: SDLC workflow discipline (draft) - 0039: ADR architecture greenfield clarifications (impl) - 0040: divorce financial analysis (draft) - 0042: alignment dialogue defensive publication (draft) Spikes: - Read tool token limit on assembled dialogues - RFC ID collision root cause - Expert agent output too long - Judge writes expert outputs - Blue MCP server on superviber infrastructure - Playwright MCP multiple window isolation Dialogues: 16 alignment dialogue records Code: - blue-core: forge module enhancements - blue-mcp: env handlers and server updates - alignment-expert agent improvements - alignment-play skill refinements - install.sh script Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
119 lines
3.7 KiB
Markdown
119 lines
3.7 KiB
Markdown
# Spike: Rfc Id Collision Root Cause
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Status** | In Progress |
|
|
| **Date** | 2026-01-26 |
|
|
| **Time Box** | 1 hour |
|
|
|
|
---
|
|
|
|
## Question
|
|
|
|
Why is there an RFC ID collision in blue.db when working on multiple RFCs simultaneously? What is the root cause and how do we prevent it?
|
|
|
|
---
|
|
|
|
## Findings
|
|
|
|
### Evidence
|
|
|
|
**Two blue.db files exist:**
|
|
- `/Users/ericg/letemcook/blue/blue.db` — empty (0 bytes), stale artifact at repo root
|
|
- `/Users/ericg/letemcook/blue/.blue/blue.db` — actual database (299KB)
|
|
|
|
**11 RFC numbers have duplicate database entries:**
|
|
```
|
|
number | count
|
|
-------|------
|
|
1 | 3
|
|
2 | 3
|
|
14 | 2
|
|
15 | 2
|
|
17 | 2
|
|
20 | 2
|
|
27 | 2
|
|
28 | 2
|
|
30 | 2
|
|
31 | 2
|
|
33 | 2
|
|
```
|
|
|
|
**RFC 0033 collision details:**
|
|
```
|
|
id | number | title | status | file_path | created_at
|
|
----|--------|--------------------------------|-------------|----------------------------------------------------|-----------
|
|
24 | 33 | round-scoped-dialogue-files | implemented | rfcs/0033-round-scoped-dialogue-files.impl.md | 18:58:43
|
|
137 | 33 | Comprehensive Config Arch | draft | rfcs/0033-comprehensive-config-architecture.draft.md | 19:35:04
|
|
```
|
|
|
|
**File timestamps:**
|
|
```
|
|
14:33 — 0033-comprehensive-config-architecture.draft.md (created via Write tool)
|
|
14:39 — 0033-round-scoped-dialogue-files.plan.md
|
|
14:40 — 0033-round-scoped-dialogue-files.impl.md
|
|
```
|
|
|
|
### Root Cause Analysis
|
|
|
|
**Primary cause: `reconcile()` doesn't check for number collisions**
|
|
|
|
In `store.rs:2031-2034`, the reconcile function finds existing documents by matching on `file_path`:
|
|
|
|
```rust
|
|
let existing = self.list_documents(dt)
|
|
.into_iter()
|
|
.find(|d| d.file_path.as_ref() == Some(&relative_path));
|
|
```
|
|
|
|
This means:
|
|
1. Two files with the same number but different filenames are both considered "unindexed"
|
|
2. Both get registered via `register_from_file()` without collision detection
|
|
3. Database ends up with multiple entries for the same RFC number
|
|
|
|
**Secondary cause: Write tool bypasses Blue's numbering system**
|
|
|
|
When I created `0033-comprehensive-config-architecture.draft.md` using Claude's Write tool instead of `blue_rfc_create`, it bypassed:
|
|
1. Blue's `next_number_with_fs()` function that scans filesystem for max number
|
|
2. Blue's database registration
|
|
|
|
Then when `blue_sync` ran (or when the file was otherwise registered), it created a duplicate entry.
|
|
|
|
**Tertiary cause: Concurrent sessions**
|
|
|
|
Two Claude sessions working simultaneously may have:
|
|
1. Cached state that doesn't reflect filesystem changes from the other session
|
|
2. Race conditions where `next_number_with_fs()` returns the same number to both
|
|
|
|
### Remediation Options
|
|
|
|
1. **Fix reconcile()** — Add collision detection before `register_from_file()`:
|
|
```rust
|
|
// Check if number already exists for this doc_type
|
|
let number_exists = self.list_documents(dt)
|
|
.into_iter()
|
|
.any(|d| d.number == parsed.number);
|
|
|
|
if number_exists {
|
|
// Log warning about collision, don't create duplicate
|
|
result.collisions.push(relative_path);
|
|
continue;
|
|
}
|
|
```
|
|
|
|
2. **Fix the immediate collision** — Delete duplicate database entries:
|
|
```sql
|
|
-- Keep the older entry, delete the newer one
|
|
DELETE FROM documents WHERE id = 137; -- comprehensive-config (newer)
|
|
```
|
|
Then rename the file to use the next available number.
|
|
|
|
3. **Process improvement** — Always use `blue_rfc_create` for new RFCs, never Write tool directly.
|
|
|
|
### Recommendation
|
|
|
|
**Outcome: recommends-implementation**
|
|
|
|
1. Create RFC to add collision detection to `reconcile()` function
|
|
2. Manually fix current collisions by renaming files and cleaning database
|
|
3. Add CLAUDE.md guidance: "Always use blue_rfc_create for new RFCs"
|