docs: v1.5.0 planning - ADR-062, release plan, and design docs
- ADR-062: Timestamp-based slug format (supersedes ADR-007) - Updated v1.5.0 RELEASE.md with 6-phase plan - Updated BACKLOG.md with deferred N+1 query locations - Developer questions and architect responses for Phase 1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
412
docs/design/v1.5.0/2025-12-16-architect-responses.md
Normal file
412
docs/design/v1.5.0/2025-12-16-architect-responses.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 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)
|
||||
272
docs/design/v1.5.0/2025-12-16-developer-questions.md
Normal file
272
docs/design/v1.5.0/2025-12-16-developer-questions.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# Developer Review Questions - v1.5.0 Release Plan
|
||||
|
||||
**Date**: 2025-12-16
|
||||
**Reviewer**: StarPunk Developer Agent
|
||||
**Documents Reviewed**:
|
||||
- `docs/decisions/ADR-062-timestamp-based-slug-format.md`
|
||||
- `docs/projectplan/v1.5.0/RELEASE.md`
|
||||
- `docs/projectplan/BACKLOG.md`
|
||||
|
||||
## Executive Summary
|
||||
|
||||
After thorough review of the v1.5.0 release plan and ADR-062, I have identified **8 questions** that need clarification from the architect before implementation can begin. These questions fall into three categories:
|
||||
|
||||
1. **Slug implementation details** (Questions 1-4)
|
||||
2. **Test structure and expectations** (Questions 5-6)
|
||||
3. **Phase dependencies and ordering** (Questions 7-8)
|
||||
|
||||
The majority of questions concern Phase 1 (Timestamp-Based Slugs), which has some ambiguities around collision handling and interaction with existing code paths.
|
||||
|
||||
---
|
||||
|
||||
## Questions
|
||||
|
||||
### Phase 1: Timestamp-Based Slugs
|
||||
|
||||
#### Q1: Collision handling function location and signature
|
||||
|
||||
**Issue**: ADR-062 specifies an `ensure_unique_slug(base_slug: str) -> str` function that checks `slug_exists(base_slug)`, but the implementation location and database interaction pattern are unclear.
|
||||
|
||||
**Current State**:
|
||||
- `starpunk/slug_utils.py` has `make_slug_unique_with_suffix(base_slug, existing_slugs: Set[str])` that takes a pre-fetched set
|
||||
- `starpunk/utils.py` has `make_slug_unique(base_slug, existing_slugs: set[str])` with random suffix logic
|
||||
- `starpunk/notes.py` line 220 calls `_get_existing_slugs(db)` to fetch all slugs, then passes to uniqueness check
|
||||
|
||||
**Questions**:
|
||||
1. Should `ensure_unique_slug()` perform its own database queries (violates current pattern)?
|
||||
2. Or should it follow the existing pattern of accepting `existing_slugs: Set[str]` parameter?
|
||||
3. Should this function live in `slug_utils.py` or `utils.py`?
|
||||
4. The ADR shows `slug_exists()` as a separate function - should this be implemented, or is this pseudocode?
|
||||
|
||||
**Implementation Impact**: This affects the function signature and which module needs modification. The current codebase consistently passes pre-fetched slug sets to avoid N+1 queries.
|
||||
|
||||
**Suggested Clarification**: Confirm whether to:
|
||||
- Keep existing pattern: `ensure_unique_slug(base_slug: str, existing_slugs: Set[str]) -> str`
|
||||
- Or introduce database coupling: `ensure_unique_slug(base_slug: str, db: Connection) -> str`
|
||||
|
||||
---
|
||||
|
||||
#### Q2: Sequential suffix starting number
|
||||
|
||||
**Issue**: ADR-062 says "first collision: `20251216143052-1`" but the examples table shows the second note as `-1`, implying the first note has no suffix.
|
||||
|
||||
**Current State**:
|
||||
- Existing `make_slug_unique_with_suffix()` starts at `-2` for first collision (base slug is attempt #1)
|
||||
- This matches table in ADR-062 examples
|
||||
|
||||
**Questions**:
|
||||
1. Does "first collision" mean the first duplicate attempt (which should get `-1`)?
|
||||
2. Or does it mean the first note gets the base slug, and second note gets `-1`?
|
||||
|
||||
**Example Scenario**:
|
||||
```python
|
||||
# Two notes created at exactly 2025-12-16 14:30:52
|
||||
Note A created first: slug = ?
|
||||
Note B created second: slug = ?
|
||||
|
||||
# Is it:
|
||||
Option 1: A = 20251216143052, B = 20251216143052-1 (matches table)
|
||||
Option 2: A = 20251216143052-1, B = 20251216143052-2 (matches "first collision" text)
|
||||
```
|
||||
|
||||
**Implementation Impact**: Determines whether sequential suffix loop starts at 1 or 2.
|
||||
|
||||
**Suggested Clarification**: Confirm that first note gets base slug (no suffix), first collision gets `-1`.
|
||||
|
||||
---
|
||||
|
||||
#### Q3: Two `generate_slug()` functions with different signatures
|
||||
|
||||
**Issue**: The codebase has two `generate_slug()` functions:
|
||||
|
||||
**Current State**:
|
||||
- `starpunk/utils.py` line 173: `generate_slug(content: str, created_at: Optional[datetime]) -> str`
|
||||
- Content-based slug generation (extracts words)
|
||||
- Used by `notes.py` line 230
|
||||
- ADR-062 specifies: `generate_slug(custom_slug: str = None, created_at: datetime = None) -> str`
|
||||
- Timestamp-based, no content parameter
|
||||
|
||||
**Questions**:
|
||||
1. Should I replace the function in `utils.py`?
|
||||
2. Should I create a new function in `slug_utils.py` and leave `utils.py` as deprecated?
|
||||
3. Should both functions coexist with different names?
|
||||
4. The removal of the `content` parameter is a breaking change for `notes.py` - should `notes.py` be updated to not pass content at all?
|
||||
|
||||
**Implementation Impact**:
|
||||
- If replacing `utils.py` function: ~15 test files will need updates
|
||||
- If creating new function: need to update all callers to use new function
|
||||
- `notes.py` line 230 currently calls `generate_slug(content, created_at)` - this will break
|
||||
|
||||
**Suggested Clarification**: Specify exact function location and migration path for callers.
|
||||
|
||||
---
|
||||
|
||||
#### Q4: Reserved slug handling in timestamp context
|
||||
|
||||
**Issue**: ADR-062 doesn't address what happens if a timestamp-based slug conflicts with a reserved slug.
|
||||
|
||||
**Current State**:
|
||||
- Reserved slugs: `['api', 'admin', 'auth', 'feed', ...]` (all alphabetic)
|
||||
- Timestamp format: `20251216143052` (all numeric)
|
||||
- **These can never collide**
|
||||
|
||||
**Questions**:
|
||||
1. Should reserved slug validation be removed from the default slug path since timestamps can't conflict?
|
||||
2. Should it remain for safety/future-proofing?
|
||||
3. Custom slugs still need reserved validation - should this logic split?
|
||||
|
||||
**Implementation Impact**: May simplify code by removing unnecessary validation from timestamp path.
|
||||
|
||||
**Suggested Clarification**: Confirm whether reserved slug check is still needed for default slugs.
|
||||
|
||||
---
|
||||
|
||||
### Phase 0: Test Fixes
|
||||
|
||||
#### Q5: Test update strategy for slug format changes
|
||||
|
||||
**Issue**: Phase 1 will change default slug format from content-based to timestamp-based. Many tests currently assert content-based slugs.
|
||||
|
||||
**Current State**:
|
||||
- `tests/test_utils.py` has 20+ tests asserting content-based slug behavior (e.g., `assert slug == "hello-world-this-is-my"`)
|
||||
- Phase 1 acceptance criteria: "Update expected slug formats in test assertions"
|
||||
|
||||
**Questions**:
|
||||
1. Should these tests be updated to assert timestamp format (e.g., `assert slug.startswith("2025")`)?
|
||||
2. Should the old content-based tests be preserved but marked as testing legacy behavior?
|
||||
3. Should tests be split: "default slug generation" vs "content-based slug generation" (if we keep the old function)?
|
||||
4. Do you want all slug assertions to use pattern matching (timestamp format) or fixed timestamps in tests?
|
||||
|
||||
**Implementation Impact**:
|
||||
- Affects ~30 test assertions in `test_utils.py`
|
||||
- Affects ~10 integration tests in `test_notes.py`, `test_micropub.py`
|
||||
- May require test helper functions for deterministic timestamps
|
||||
|
||||
**Suggested Clarification**: Provide guidance on test update strategy.
|
||||
|
||||
---
|
||||
|
||||
#### Q6: Phase 0 priority - are tests blocking?
|
||||
|
||||
**Issue**: Phase 0 is marked "Must complete first - unblocks all other phases" but the 19 failing tests appear unrelated to slug changes.
|
||||
|
||||
**Current State**:
|
||||
- Failing tests: Migration performance, feed streaming, content negotiation, search security
|
||||
- None directly related to slug generation
|
||||
- Phase 1 (slugs) could theoretically proceed with these tests failing
|
||||
|
||||
**Questions**:
|
||||
1. Is Phase 0 truly blocking for Phase 1, or can Phase 1 proceed if slug-related tests pass?
|
||||
2. Should Phase 0 be completed before ANY other phase, or just before phases that depend on those specific test areas?
|
||||
3. If I discover that fixing some Phase 0 tests requires changes that conflict with Phase 1 work, what's the priority?
|
||||
|
||||
**Implementation Impact**: Affects work sequencing and potential merge conflicts.
|
||||
|
||||
**Suggested Clarification**: Confirm hard dependency of Phase 0 on all other phases, or allow parallel work.
|
||||
|
||||
---
|
||||
|
||||
### General Implementation Questions
|
||||
|
||||
#### Q7: Backwards compatibility for existing notes
|
||||
|
||||
**Issue**: ADR-062 states "Existing notes retain their slugs (no data migration)" but doesn't specify how the dual slug formats coexist.
|
||||
|
||||
**Current State**:
|
||||
- Database has notes with content-based slugs (e.g., `my-first-post`)
|
||||
- New notes will have timestamp slugs (e.g., `20251216143052`)
|
||||
- Both slug formats will exist simultaneously
|
||||
|
||||
**Questions**:
|
||||
1. Do any code paths need to detect/handle the two formats differently?
|
||||
2. Should there be a helper function `is_timestamp_slug(slug: str) -> bool` for future use?
|
||||
3. Are there any edge cases where code assumes slug format (e.g., sorting, display, URLs)?
|
||||
4. Does feed generation or UI need updates to handle mixed slug formats?
|
||||
|
||||
**Implementation Impact**: May require audit of all slug usages to ensure format-agnostic handling.
|
||||
|
||||
**Suggested Clarification**: Confirm if any code needs to be format-aware, or if slug format is truly opaque.
|
||||
|
||||
---
|
||||
|
||||
#### Q8: Phase ordering rationale
|
||||
|
||||
**Issue**: Phases 2-4 are all marked "Phase 0 complete" as dependency, but no interdependencies are noted between them.
|
||||
|
||||
**Current State**:
|
||||
- Phase 2: Debug file management
|
||||
- Phase 3: N+1 query fix (feed generation)
|
||||
- Phase 4: Atomic variant generation
|
||||
- All independent of each other
|
||||
|
||||
**Questions**:
|
||||
1. Can Phases 2-4 be implemented in parallel after Phase 0?
|
||||
2. Is there a preferred order (2→3→4) for any reason?
|
||||
3. Should each phase be committed separately or can they be batched?
|
||||
|
||||
**Implementation Impact**: Affects work planning and commit structure.
|
||||
|
||||
**Suggested Clarification**: Confirm whether Phases 2-4 can be parallelized or should be sequential.
|
||||
|
||||
---
|
||||
|
||||
## Additional Observations (Not Blocking)
|
||||
|
||||
These observations don't block implementation but may inform architectural decisions:
|
||||
|
||||
### O1: Code duplication between `utils.py` and `slug_utils.py`
|
||||
|
||||
**Observation**: Reserved slugs are defined in both:
|
||||
- `utils.py` line 24: `RESERVED_SLUGS = {"admin", "api", ...}` (5 items)
|
||||
- `slug_utils.py` line 24: `RESERVED_SLUGS = frozenset([...])` (12 items, more comprehensive)
|
||||
|
||||
**Impact**: Low - but may cause confusion. Consider consolidating in v1.5.1.
|
||||
|
||||
---
|
||||
|
||||
### O2: Timestamp format consistency
|
||||
|
||||
**Observation**: ADR-062 uses `YYYYMMDDHHMMSS` (no separator) but existing fallback in `utils.py` line 220 uses `YYYYMMDD-HHMMSS` (with hyphen).
|
||||
|
||||
**Questions**:
|
||||
- Is the hyphen removal intentional (shorter, more compact)?
|
||||
- Current: `20241118-143045` (15 chars)
|
||||
- ADR-062: `20241118143045` (14 chars)
|
||||
|
||||
**Impact**: Minor - affects slug length by 1 character.
|
||||
|
||||
---
|
||||
|
||||
### O3: Test coverage gap mentioned in Phase 5
|
||||
|
||||
**Observation**: Phase 5 mentions "MPO format handling (untested)" but this is already in BACKLOG as "High priority - Scheduled for v1.5.0".
|
||||
|
||||
**Question**: Is this intentionally listed in both BACKLOG and Phase 5, or is there duplication?
|
||||
|
||||
**Impact**: None - just a clarity question.
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**Implementation Readiness**: 6/10
|
||||
|
||||
The release plan is well-structured with clear phases and acceptance criteria. However, **Phase 1 (Timestamp-Based Slugs)** has enough ambiguity in implementation details (Questions 1-4) that I cannot confidently proceed without architect clarification.
|
||||
|
||||
**Recommended Next Steps**:
|
||||
1. Architect addresses Questions 1-4 (Phase 1 blocking issues)
|
||||
2. Architect clarifies Questions 5-8 (helps inform implementation approach)
|
||||
3. Developer proceeds with Phase 0 (test fixes) while awaiting Q1-Q4 answers
|
||||
4. Developer implements Phases 1-4 after clarifications received
|
||||
|
||||
**Estimated Time to Implementation-Ready**: 1-2 hours for architect to address questions.
|
||||
|
||||
---
|
||||
|
||||
## Approval
|
||||
|
||||
Once these questions are addressed, I am confident the implementation can proceed smoothly with the 18-29 hour estimate provided in the release plan.
|
||||
|
||||
**Developer**: StarPunk Developer Agent
|
||||
**Status**: Awaiting Architect Response
|
||||
**Next Action**: Architect to review and answer questions 1-8
|
||||
Reference in New Issue
Block a user