# Architect Responses - v1.5.0 Developer Questions

**Date**: 2025-12-16
**Architect**: StarPunk Architect Agent
**In Response To**: `docs/design/v1.5.0/2025-12-16-developer-questions.md`

---

## Response Summary

All 8 questions have been addressed. The implementation can proceed immediately after reading this document. Key decisions:

1. **Q1**: Keep existing pattern (pass `existing_slugs: Set[str]`). ADR-062 pseudocode is conceptual.
2. **Q2**: First note gets base slug, first collision gets `-1`. The table in ADR-062 is correct.
3. **Q3**: Create new function in `slug_utils.py`. Migration path provided.
4. **Q4**: Keep reserved slug validation for custom slugs only. Safe to skip for timestamp slugs.
5. **Q5**: Tests should use pattern matching for timestamps. Test strategy provided.
6. **Q6**: Phase 0 is a hard dependency. Cannot proceed with Phase 1 until all tests pass.
7. **Q7**: Slug format is opaque. No format-aware code needed.
8. **Q8**: Phases 2-4 can be parallelized. Commit each phase separately.

---

## Detailed Responses

### Q1: Collision handling function location and signature

**Decision**: Keep the existing pattern of accepting `existing_slugs: Set[str]` as a parameter.

**Rationale**:
The ADR-062 pseudocode (`slug_exists(base_slug)`) is conceptual illustration only. The actual implementation should:

1. Follow the existing pattern in the codebase (passing pre-fetched slug sets)
2. Avoid introducing database coupling into utility functions
3. Prevent N+1 queries when checking multiple candidates

**Implementation Specification**:

Create a new function in `/home/phil/Projects/starpunk/starpunk/slug_utils.py`:

```python
def generate_timestamp_slug(
    created_at: datetime = None,
    existing_slugs: Set[str] = None
) -> str:
    """Generate a timestamp-based slug with collision handling.

    Per ADR-062: Default format is YYYYMMDDHHMMSS with sequential
    suffix (-1, -2, etc.) for collisions.

    Args:
        created_at: Note creation timestamp (defaults to now)
        existing_slugs: Set of existing slugs to check for collisions

    Returns:
        Unique timestamp-based slug
    """
    if created_at is None:
        created_at = datetime.utcnow()

    if existing_slugs is None:
        existing_slugs = set()

    base_slug = created_at.strftime("%Y%m%d%H%M%S")

    # If no collision, return base slug
    if base_slug not in existing_slugs:
        return base_slug

    # Sequential suffix for collisions
    suffix = 1
    while f"{base_slug}-{suffix}" in existing_slugs:
        suffix += 1

    return f"{base_slug}-{suffix}"
```

**Location**: `/home/phil/Projects/starpunk/starpunk/slug_utils.py`

**Do NOT modify**: The `ensure_unique_slug()` function signature in ADR-062 is pseudocode. Do not create a function with database coupling.

---

### Q2: Sequential suffix starting number

**Decision**: First note gets base slug (no suffix). First collision gets `-1`.

**Clarification**: The examples table in ADR-062 is correct. The text "first collision: `20251216143052-1`" means the first **duplicate** (collision) gets `-1`, not the first note overall.

**Example Scenario**:
```
Note A created at 14:30:52  ->  slug = "20251216143052"      (base, no suffix)
Note B created at 14:30:52  ->  slug = "20251216143052-1"    (first collision)
Note C created at 14:30:52  ->  slug = "20251216143052-2"    (second collision)
```

**Implementation**: Sequential suffix loop should start at `1`, not `2`:

```python
suffix = 1
while f"{base_slug}-{suffix}" in existing_slugs:
    suffix += 1
return f"{base_slug}-{suffix}"
```

**Note**: This differs from the existing `make_slug_unique_with_suffix()` function in `slug_utils.py` which starts at `-2`. The new timestamp slug function should start at `-1` per ADR-062.

---

### Q3: Two `generate_slug()` functions with different signatures

**Decision**: Create a new function in `slug_utils.py`. Do not modify or remove the existing function in `utils.py`.

**Migration Path**:

1. **Create new function** in `/home/phil/Projects/starpunk/starpunk/slug_utils.py`:
   - Name: `generate_timestamp_slug()` (as specified in Q1 response)
   - Do not name it `generate_slug()` to avoid confusion during migration

2. **Update `/home/phil/Projects/starpunk/starpunk/notes.py`** (lines 228-234):

   **Current code** (line 228-234):
   ```python
   else:
       # Generate base slug from content
       base_slug = generate_slug(content, created_at)

       # Make unique if collision
       slug = make_slug_unique(base_slug, existing_slugs)
   ```

   **Replace with**:
   ```python
   else:
       # Generate timestamp-based slug (ADR-062)
       from starpunk.slug_utils import generate_timestamp_slug
       slug = generate_timestamp_slug(created_at, existing_slugs)
   ```

3. **Keep the existing function** in `utils.py` unchanged. It may be used elsewhere or for future content-based slug options.

4. **Update imports** in `notes.py`:
   - Remove `generate_slug` from the `utils` import line (line 34) if no longer needed
   - Verify no other callers use `generate_slug()` for default note creation

**Rationale**:
- Creating a distinctly-named function makes the transition explicit
- Preserves backward compatibility if content-based slugs are ever needed
- Allows gradual migration with clear audit trail

---

### Q4: Reserved slug handling in timestamp context

**Decision**:
- **Default timestamp slugs**: Safe to skip reserved slug validation (timestamps cannot collide with reserved words)
- **Custom slugs**: Must retain reserved slug validation

**Implementation**:

The new `generate_timestamp_slug()` function does NOT need to check reserved slugs because:
- Reserved slugs are alphabetic (`api`, `admin`, `feed`, etc.)
- Timestamp slugs are purely numeric (`20251216143052`)
- These sets are mutually exclusive by construction

**However**, the existing custom slug validation in `validate_and_sanitize_custom_slug()` must retain reserved slug checking because user-provided slugs could be anything.

**Code Impact**:
- `generate_timestamp_slug()`: No reserved slug check needed
- `validate_and_sanitize_custom_slug()`: Unchanged (already handles reserved slugs)
- `validate_slug()` in `utils.py`: Unchanged (still validates reserved slugs for custom slugs)

**Simplification**: You may remove the defensive `validate_slug()` call after timestamp generation in `notes.py` (line 236-237) since timestamp slugs are guaranteed valid by construction:
```python
# This check is no longer needed for timestamp slugs:
# if not validate_slug(slug):
#     raise InvalidNoteDataError(...)
```

---

### Q5: Test update strategy for slug format changes

**Decision**: Use pattern matching for timestamp assertions. Preserve content-based tests in a separate test file or clearly marked section.

**Test Strategy**:

1. **For new timestamp slug tests**, use regex pattern matching:
   ```python
   import re

   TIMESTAMP_SLUG_PATTERN = re.compile(r'^\d{14}(-\d+)?$')

   def test_default_slug_is_timestamp():
       note = create_note("Some content here")
       assert TIMESTAMP_SLUG_PATTERN.match(note.slug)

   def test_slug_collision_adds_suffix():
       # Create two notes at same timestamp
       fixed_time = datetime(2025, 12, 16, 14, 30, 52)
       note1 = create_note("First note", created_at=fixed_time)
       note2 = create_note("Second note", created_at=fixed_time)

       assert note1.slug == "20251216143052"
       assert note2.slug == "20251216143052-1"
   ```

2. **For timestamp-specific assertions**, use fixed timestamps in tests:
   ```python
   def test_timestamp_slug_format():
       """Test that timestamp slug matches exact format."""
       fixed_time = datetime(2025, 12, 16, 14, 30, 52)
       slug = generate_timestamp_slug(fixed_time, set())
       assert slug == "20251216143052"
   ```

3. **Content-based tests**: Move to a separate section or file named `test_legacy_slug_generation.py` with a comment:
   ```python
   """
   Legacy tests for content-based slug generation.

   These test the generate_slug() function in utils.py which is
   preserved for backward compatibility. New notes use timestamp-based
   slugs per ADR-062.
   """
   ```

4. **Update existing tests that assert specific slug formats**:
   - Replace exact string assertions (`assert slug == "hello-world"`) with pattern matching
   - OR use fixed timestamps and assert exact expected values

**Affected Test Files** (estimate from your question):
- `/home/phil/Projects/starpunk/tests/test_utils.py`: ~20 tests
- `/home/phil/Projects/starpunk/tests/test_notes.py`: ~10 tests
- `/home/phil/Projects/starpunk/tests/test_micropub.py`: ~10 tests

**Helper Function** (add to test utilities or conftest.py):
```python
def assert_valid_timestamp_slug(slug: str) -> None:
    """Assert slug matches timestamp format per ADR-062."""
    pattern = re.compile(r'^\d{14}(-\d+)?$')
    assert pattern.match(slug), f"Slug '{slug}' does not match timestamp format"
```

---

### Q6: Phase 0 priority - are tests blocking?

**Decision**: Phase 0 is a **hard dependency**. Phase 1 cannot proceed until all tests pass.

**Rationale**:

1. **Failing tests mask regressions**: If you implement Phase 1 (slug changes) while 19 tests are failing, you cannot distinguish between:
   - Pre-existing failures
   - New failures caused by your changes

2. **CI/CD integrity**: The project should maintain a green build. Committing Phase 1 work with known failing tests violates this principle.

3. **Debugging complexity**: If slug changes interact unexpectedly with the failing test areas (e.g., feed generation, content negotiation), debugging becomes significantly harder.

**Implementation Order**:

```
Phase 0 (Test Fixes)  <-- MUST COMPLETE FIRST
    |
    v
+-- Phase 1 (Timestamp Slugs)
|
+-- Phase 2 (Debug Files)      <-- Can run in parallel
|
+-- Phase 3 (N+1 Query Fix)    <-- after Phase 0
|
+-- Phase 4 (Atomic Variants)
    |
    v
Phase 5 (Test Coverage)  <-- LAST
```

**Exception**: If fixing a Phase 0 test reveals it requires slug-related changes, document the circular dependency and bring to architect attention.

**Recommendation**: Start Phase 0 immediately. Many of those 19 failures may be simple test maintenance issues (timeouts, assertions that need updating, etc.).

---

### Q7: Backwards compatibility for existing notes

**Decision**: Slug format is **opaque**. No code needs to be format-aware.

**Clarification**:

1. **No format detection needed**: Do not create an `is_timestamp_slug()` helper function. The system should treat all slugs identically regardless of format.

2. **Code paths are format-agnostic**:
   - Database queries use slug as opaque string key
   - URL routing uses slug as path parameter
   - Feed generation includes slug verbatim
   - Templates display slug without interpretation

3. **Coexistence is automatic**: Content-based slugs (`my-first-post`) and timestamp slugs (`20251216143052`) are both valid slug patterns. They coexist naturally.

4. **Sorting behavior**:
   - Database ORDER BY on `created_at` is unaffected
   - Alphabetical slug sorting would interleave formats (numbers sort before letters)
   - This is acceptable; no UI sorts by slug alphabetically

5. **Display considerations**:
   - Timestamps are less readable in URLs, but URLs are rarely human-read
   - UI displays note content, not slugs
   - RSS feeds include full URLs; format doesn't affect feed readers

**No audit required**: You do not need to audit slug usages. The design ensures format-agnosticism.

---

### Q8: Phase ordering rationale

**Decision**:
- Phases 2, 3, and 4 **can be parallelized** after Phase 0 completes
- Phase 1 (Timestamp Slugs) should be done **before** Phases 2-4 for cleaner testing
- Each phase should be **committed separately**

**Recommended Order**:

```
Day 1: Phase 0 (Test Fixes) - Get to green build
Day 2: Phase 1 (Timestamp Slugs) - Quick win, user-visible improvement
Day 3: Phase 2 (Debug Files) or Phase 3 (N+1) or Phase 4 (Atomic) - Any order
Day 4: Remaining phases from above
Day 5: Phase 5 (Test Coverage) - Must be last
```

**Commit Strategy**:

Each phase gets its own commit or small series of commits:
```
feat(slugs): Implement timestamp-based slugs per ADR-062
fix(tests): Resolve 19 failing tests in Phase 0
feat(media): Add debug file cleanup and configuration
perf(feed): Batch load media and tags to fix N+1 query
feat(media): Make variant generation atomic with database
test: Expand coverage to 90% for v1.5.0
```

**Why Not Batch**: Batching commits makes bisecting regressions harder and obscures the changelog.

**Parallelization Note**: If you have capacity to work on multiple phases simultaneously (e.g., waiting for test runs), Phases 2-4 have no code overlap and can be developed in parallel branches:
- `feature/v1.5.0-debug-files`
- `feature/v1.5.0-n+1-fix`
- `feature/v1.5.0-atomic-variants`

Then merge all into main before Phase 5.

---

## Observations Responses

### O1: Code duplication between `utils.py` and `slug_utils.py`

**Acknowledged**. The duplicate `RESERVED_SLUGS` definitions should be consolidated in a future cleanup. For v1.5.0:

- Use the more comprehensive list in `slug_utils.py` (12 items) as the canonical source
- Do not consolidate in this release (scope creep)
- Add to BACKLOG.md for v1.5.1 or v1.6.0

### O2: Timestamp format consistency

**Confirmed**: The hyphen removal in ADR-062 (`YYYYMMDDHHMMSS`) vs existing fallback (`YYYYMMDD-HHMMSS`) is intentional.

- ADR-062 format: `20251216143052` (14 characters, no separator)
- Old fallback format: `20251216-143052` (15 characters, with hyphen)

**Rationale**:
- One fewer character
- Consistent with ISO 8601 compact format
- No functional difference; purely aesthetic

**Action**: Use the unhyphenated format per ADR-062.

### O3: Test coverage gap mentioned in Phase 5

**Clarification**: This is intentional duplication for visibility.

- BACKLOG.md lists the gap for tracking
- Phase 5 in RELEASE.md lists it for implementation planning
- Both point to the same work item

No action needed; this is not an error.

---

## ADR-062 Updates Required

No updates to ADR-062 are required based on these questions. The ADR's pseudocode is understood to be conceptual, and all implementation details have been clarified in this response document.

---

## Implementation Checklist

Based on these responses, the developer can now proceed with:

- [ ] Phase 0: Fix 19 failing tests
- [ ] Create `generate_timestamp_slug()` in `slug_utils.py`
- [ ] Update `notes.py` to use new timestamp slug function
- [ ] Update tests with pattern matching strategy
- [ ] Proceed with Phases 2-4 (order flexible)
- [ ] Complete Phase 5 test coverage last

---

**Architect**: StarPunk Architect Agent
**Status**: Questions Answered - Ready for Implementation
**Next Action**: Developer to begin Phase 0 (Test Fixes)
