Python's sqlite3.executescript() has a bug where trailing newlines after the final semicolon create empty statements. When APSW's log_sqlite() is enabled (via apswutils, imported by fastmigrate), these cause visible "API called with NULL prepared statement" errors during interpreter shutdown. - Strip trailing newlines from all 9 existing migration files - Update migration template to end with semicolon, no trailing newline - Document the requirement in CLAUDE.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
101 lines
3.1 KiB
Markdown
101 lines
3.1 KiB
Markdown
# AnimalTrack Project Instructions
|
|
|
|
## Project Status
|
|
Check `PLAN.md` for current progress. Each step has a checkbox to track completion.
|
|
|
|
## Critical Workflow Rules
|
|
|
|
### 1. Commit Frequently
|
|
**ALWAYS commit after completing any step.** Don't let changes accumulate.
|
|
|
|
### 2. Update Plan
|
|
After completing work, update `PLAN.md`:
|
|
- Check off completed items with `[x]`
|
|
- Add commit hash if significant
|
|
|
|
### 3. Run Tests
|
|
```bash
|
|
pytest tests/ -v
|
|
```
|
|
|
|
## Framework Documentation
|
|
|
|
**ALWAYS consult docs before implementing UI.** Use vendored documentation.
|
|
|
|
| Framework | Main Context | Examples |
|
|
|-----------|-------------|----------|
|
|
| FastHTML | `docs/vendor/fasthtml/llms-ctx.txt` | API refs in `docs/vendor/fasthtml/` |
|
|
| MonsterUI | `docs/vendor/monsterui/llms.txt` | `docs/vendor/monsterui/examples/` |
|
|
|
|
### Idiomatic Patterns
|
|
- **Always check docs for the idiomatic way** before implementing anything with FastHTML/MonsterUI
|
|
- MonsterUI components: `Card`, `Alert`, `Grid(cols_sm/md/lg)`, `DivFullySpaced`
|
|
- Use `AlertT` enums for alerts, `TextPresets` for typography
|
|
- Forms: Use MonsterUI form components, not raw HTML
|
|
|
|
## Quick Reference
|
|
|
|
### Database (APSW + FastLite)
|
|
This project uses APSW (not standard sqlite3) via fastlite. Key patterns:
|
|
```python
|
|
from fastlite import database
|
|
|
|
db = database('animaltrack.db')
|
|
# db.execute() returns APSW cursor
|
|
# Use db.t for table access
|
|
```
|
|
|
|
### Timestamps
|
|
All timestamps are ms since Unix epoch, stored as INTEGER:
|
|
```python
|
|
import time
|
|
ts_utc = int(time.time() * 1000) # Current time in ms
|
|
```
|
|
|
|
### IDs
|
|
All entity IDs are ULIDs (26 chars):
|
|
```python
|
|
from ulid import ULID
|
|
id = str(ULID()) # "01ARZ3NDEKTSV4RRFFQ69G5FAV"
|
|
```
|
|
|
|
### Money
|
|
Store all prices as integer cents. Display prices with 2 decimals, cost/egg with 3.
|
|
|
|
## Project-Specific Rules
|
|
|
|
### Event Sourcing
|
|
- Every state change is an event
|
|
- Events are immutable (edits create revisions, deletes create tombstones)
|
|
- Projections are updated synchronously in the same transaction
|
|
|
|
### Selection Context
|
|
When handling animal selections:
|
|
1. Client sends filter + resolved_ids + roster_hash
|
|
2. Server re-resolves at ts_utc
|
|
3. On mismatch: return 409 with diff, require `confirmed=true` to proceed
|
|
|
|
### Feed Costing
|
|
- Block FeedGiven if no FeedPurchased exists <= ts_utc
|
|
- Store feed amounts in grams (INTEGER) for precision
|
|
- Display as kg with 3 decimals
|
|
|
|
### Migrations
|
|
- Migration files must end with `;` and NO trailing newline
|
|
- Python's sqlite3.executescript() has a bug: trailing newlines after the final `;` create empty statements that cause SQLITE_MISUSE errors when APSW logging is enabled
|
|
- Use `animaltrack create-migration "description"` to create new migrations (template handles this correctly)
|
|
|
|
## Refreshing Docs
|
|
```bash
|
|
# FastHTML
|
|
curl -s https://www.fastht.ml/docs/llms-ctx.txt -o docs/vendor/fasthtml/llms-ctx.txt
|
|
|
|
# MonsterUI
|
|
curl -s https://raw.githubusercontent.com/AnswerDotAI/MonsterUI/refs/heads/main/docs/llms.txt -o docs/vendor/monsterui/llms.txt
|
|
```
|
|
|
|
## E2E Tests
|
|
The spec defines 8 authoritative acceptance tests in §21. These are the source of truth for correct behavior. When in doubt, refer to the spec.
|
|
|
|
Numeric comparisons on REAL values use tolerance `±0.001`.
|