docs(01): create phase 1 foundation plans
Phase 1: Foundation - 3 plans created - 9 total tasks defined - Ready for execution Plan 01: Project scaffolding (pyproject.toml, pre-commit, src layout) Plan 02: SQLAlchemy models (Project, Discussion, Round, Message, Consensus) Plan 03: Database setup and model tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
048278e46b
commit
c48eb1cea7
3 changed files with 479 additions and 0 deletions
132
.planning/phases/01-foundation/01-01-PLAN.md
Normal file
132
.planning/phases/01-foundation/01-01-PLAN.md
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
---
|
||||||
|
phase: 01-foundation
|
||||||
|
plan: 01
|
||||||
|
type: execute
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Set up project scaffolding with pyproject.toml, ruff, pre-commit, and src layout.
|
||||||
|
|
||||||
|
Purpose: Establish consistent tooling from day one—linting, formatting, testing infrastructure.
|
||||||
|
Output: Working Python project structure with `uv sync` installing all deps, ruff/pre-commit configured.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-phase.md
|
||||||
|
~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@SPEC.md
|
||||||
|
@CLAUDE.md
|
||||||
|
|
||||||
|
**Constraints from PROJECT.md:**
|
||||||
|
- Python 3.11+
|
||||||
|
- ruff (line length 100)
|
||||||
|
- pytest, 80%+ coverage on core logic
|
||||||
|
- Type hints required on public functions
|
||||||
|
- Docstrings required on modules and classes
|
||||||
|
- Dependencies unpinned unless security required
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create pyproject.toml with dependencies and tool config</name>
|
||||||
|
<files>pyproject.toml</files>
|
||||||
|
<action>
|
||||||
|
Create pyproject.toml with:
|
||||||
|
|
||||||
|
**[project] section:**
|
||||||
|
- name = "moai"
|
||||||
|
- version = "0.1.0"
|
||||||
|
- description = "Multi-AI collaborative brainstorming platform"
|
||||||
|
- requires-python = ">=3.11"
|
||||||
|
- dependencies: python-telegram-bot, sqlalchemy, httpx, aiosqlite (for async SQLite)
|
||||||
|
|
||||||
|
**[project.optional-dependencies]:**
|
||||||
|
- dev: pytest, pytest-cov, pytest-asyncio, ruff, pre-commit
|
||||||
|
|
||||||
|
**[tool.ruff] section:**
|
||||||
|
- line-length = 100
|
||||||
|
- target-version = "py311"
|
||||||
|
|
||||||
|
**[tool.ruff.lint]:**
|
||||||
|
- select = ["E", "F", "I", "N", "W", "UP"]
|
||||||
|
|
||||||
|
**[tool.pytest.ini_options]:**
|
||||||
|
- testpaths = ["tests"]
|
||||||
|
- asyncio_mode = "auto"
|
||||||
|
|
||||||
|
**[build-system]:**
|
||||||
|
- requires = ["hatchling"]
|
||||||
|
- build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
Use hatchling as build backend (modern, works well with uv).
|
||||||
|
Do NOT pin dependency versions.
|
||||||
|
</action>
|
||||||
|
<verify>uv sync completes without errors</verify>
|
||||||
|
<done>pyproject.toml valid, all dependencies installable</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create pre-commit configuration</name>
|
||||||
|
<files>.pre-commit-config.yaml</files>
|
||||||
|
<action>
|
||||||
|
Create .pre-commit-config.yaml with:
|
||||||
|
|
||||||
|
**Hooks:**
|
||||||
|
1. ruff (linting): repo = https://github.com/astral-sh/ruff-pre-commit, hooks = [ruff, ruff-format]
|
||||||
|
2. Standard pre-commit hooks: trailing-whitespace, end-of-file-fixer, check-yaml
|
||||||
|
|
||||||
|
Use latest rev for ruff-pre-commit (check GitHub for current version, approximately v0.11.x).
|
||||||
|
|
||||||
|
Do NOT add pytest hook—running tests on every commit is too slow. Tests run manually or in CI.
|
||||||
|
</action>
|
||||||
|
<verify>pre-commit install && pre-commit run --all-files passes</verify>
|
||||||
|
<done>Pre-commit hooks installed and passing</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Create src layout and package structure</name>
|
||||||
|
<files>src/moai/__init__.py, src/moai/bot/__init__.py, src/moai/bot/handlers/__init__.py, src/moai/core/__init__.py, tests/__init__.py</files>
|
||||||
|
<action>
|
||||||
|
Create directory structure per SPEC.md:
|
||||||
|
|
||||||
|
src/moai/__init__.py - Package marker with __version__ = "0.1.0"
|
||||||
|
src/moai/bot/__init__.py - Bot subpackage marker (docstring: "Telegram bot handlers and entry point")
|
||||||
|
src/moai/bot/handlers/__init__.py - Handlers subpackage marker
|
||||||
|
src/moai/core/__init__.py - Core subpackage marker (docstring: "Core business logic, models, and services")
|
||||||
|
tests/__init__.py - Test package marker
|
||||||
|
|
||||||
|
Each __init__.py should have a module docstring describing its purpose.
|
||||||
|
Use triple-quoted docstrings at the top of each file.
|
||||||
|
</action>
|
||||||
|
<verify>python -c "import moai; print(moai.__version__)" prints "0.1.0"</verify>
|
||||||
|
<done>Package importable, structure matches SPEC.md</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `uv sync` succeeds without errors
|
||||||
|
- [ ] `pre-commit run --all-files` passes
|
||||||
|
- [ ] `python -c "import moai"` succeeds
|
||||||
|
- [ ] `ruff check src tests` passes
|
||||||
|
- [ ] Directory structure matches SPEC.md file structure
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All verification checks pass
|
||||||
|
- No linting errors
|
||||||
|
- Package installable and importable
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`
|
||||||
|
</output>
|
||||||
163
.planning/phases/01-foundation/01-02-PLAN.md
Normal file
163
.planning/phases/01-foundation/01-02-PLAN.md
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
---
|
||||||
|
phase: 01-foundation
|
||||||
|
plan: 02
|
||||||
|
type: execute
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Create SQLAlchemy models for Project, Discussion, Round, Message, and Consensus.
|
||||||
|
|
||||||
|
Purpose: Define the data model that powers all discussion features.
|
||||||
|
Output: Complete models.py with all relationships, ready for database creation.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-phase.md
|
||||||
|
~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@SPEC.md
|
||||||
|
@CLAUDE.md
|
||||||
|
|
||||||
|
**Data model from SPEC.md:**
|
||||||
|
```
|
||||||
|
Project (has many) -> Discussion (has many) -> Round (has many) -> Message
|
||||||
|
\-> Discussion (has one) -> Consensus
|
||||||
|
```
|
||||||
|
|
||||||
|
**Field specifications:**
|
||||||
|
- Project: id (uuid), name, created_at, updated_at, models (JSON array), settings (JSON)
|
||||||
|
- Discussion: id, project_id (FK), question, type (open|discuss), status (active|completed), created_at
|
||||||
|
- Round: id, discussion_id (FK), round_number, type (parallel|sequential)
|
||||||
|
- Message: id, round_id (FK), model, content, timestamp, is_direct
|
||||||
|
- Consensus: id, discussion_id (FK), agreements (JSON array), disagreements (JSON array), generated_at, generated_by
|
||||||
|
|
||||||
|
**Constraints:**
|
||||||
|
- Use SQLAlchemy 2.0 style (mapped_column, DeclarativeBase)
|
||||||
|
- Type hints required
|
||||||
|
- SQLite compatible (use JSON type, not ARRAY)
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create base model and enums</name>
|
||||||
|
<files>src/moai/core/models.py</files>
|
||||||
|
<action>
|
||||||
|
Create src/moai/core/models.py with:
|
||||||
|
|
||||||
|
**Imports:** SQLAlchemy 2.0 style (DeclarativeBase, Mapped, mapped_column, relationship), uuid, datetime, enum
|
||||||
|
|
||||||
|
**Base class:**
|
||||||
|
- class Base(DeclarativeBase): pass
|
||||||
|
|
||||||
|
**Enums (use Python Enum, store as string):**
|
||||||
|
- DiscussionType: OPEN = "open", DISCUSS = "discuss"
|
||||||
|
- DiscussionStatus: ACTIVE = "active", COMPLETED = "completed"
|
||||||
|
- RoundType: PARALLEL = "parallel", SEQUENTIAL = "sequential"
|
||||||
|
|
||||||
|
**UUID helper:**
|
||||||
|
- Use uuid4() for default IDs
|
||||||
|
- Store as String(36) for SQLite compatibility (NOT native UUID type)
|
||||||
|
|
||||||
|
Add module docstring explaining the data model.
|
||||||
|
</action>
|
||||||
|
<verify>python -c "from moai.core.models import Base, DiscussionType, DiscussionStatus, RoundType"</verify>
|
||||||
|
<done>Base class and enums importable</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create Project and Discussion models</name>
|
||||||
|
<files>src/moai/core/models.py</files>
|
||||||
|
<action>
|
||||||
|
Add to models.py:
|
||||||
|
|
||||||
|
**Project model:**
|
||||||
|
- id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||||||
|
- name: Mapped[str] = mapped_column(String(255))
|
||||||
|
- created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||||
|
- updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
- models: Mapped[list] = mapped_column(JSON, default=list) - stores ["claude", "gpt", "gemini"]
|
||||||
|
- settings: Mapped[dict] = mapped_column(JSON, default=dict) - stores {default_rounds, consensus_threshold, system_prompt_override}
|
||||||
|
- discussions: Mapped[list["Discussion"]] = relationship(back_populates="project", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
**Discussion model:**
|
||||||
|
- id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4()))
|
||||||
|
- project_id: Mapped[str] = mapped_column(ForeignKey("project.id"))
|
||||||
|
- question: Mapped[str] = mapped_column(Text)
|
||||||
|
- type: Mapped[DiscussionType] = mapped_column(Enum(DiscussionType))
|
||||||
|
- status: Mapped[DiscussionStatus] = mapped_column(Enum(DiscussionStatus), default=DiscussionStatus.ACTIVE)
|
||||||
|
- created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||||
|
- project: Mapped["Project"] = relationship(back_populates="discussions")
|
||||||
|
- rounds: Mapped[list["Round"]] = relationship(back_populates="discussion", cascade="all, delete-orphan")
|
||||||
|
- consensus: Mapped["Consensus"] = relationship(back_populates="discussion", uselist=False, cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
Use __tablename__ = "project" and "discussion" (singular, lowercase).
|
||||||
|
</action>
|
||||||
|
<verify>python -c "from moai.core.models import Project, Discussion; print(Project.__tablename__, Discussion.__tablename__)"</verify>
|
||||||
|
<done>Project and Discussion models defined with bidirectional relationships</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Create Round, Message, and Consensus models</name>
|
||||||
|
<files>src/moai/core/models.py</files>
|
||||||
|
<action>
|
||||||
|
Add to models.py:
|
||||||
|
|
||||||
|
**Round model:**
|
||||||
|
- id: Mapped[str] (uuid, primary key)
|
||||||
|
- discussion_id: Mapped[str] = mapped_column(ForeignKey("discussion.id"))
|
||||||
|
- round_number: Mapped[int]
|
||||||
|
- type: Mapped[RoundType] = mapped_column(Enum(RoundType))
|
||||||
|
- discussion: Mapped["Discussion"] = relationship(back_populates="rounds")
|
||||||
|
- messages: Mapped[list["Message"]] = relationship(back_populates="round", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
**Message model:**
|
||||||
|
- id: Mapped[str] (uuid, primary key)
|
||||||
|
- round_id: Mapped[str] = mapped_column(ForeignKey("round.id"))
|
||||||
|
- model: Mapped[str] = mapped_column(String(50)) - e.g., "claude", "gpt", "gemini"
|
||||||
|
- content: Mapped[str] = mapped_column(Text)
|
||||||
|
- timestamp: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||||
|
- is_direct: Mapped[bool] = mapped_column(Boolean, default=False) - true if @mentioned
|
||||||
|
- round: Mapped["Round"] = relationship(back_populates="messages")
|
||||||
|
|
||||||
|
**Consensus model:**
|
||||||
|
- id: Mapped[str] (uuid, primary key)
|
||||||
|
- discussion_id: Mapped[str] = mapped_column(ForeignKey("discussion.id"), unique=True)
|
||||||
|
- agreements: Mapped[list] = mapped_column(JSON, default=list) - bullet point strings
|
||||||
|
- disagreements: Mapped[list] = mapped_column(JSON, default=list) - [{topic, positions: {model: position}}]
|
||||||
|
- generated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
||||||
|
- generated_by: Mapped[str] = mapped_column(String(50)) - which model summarized
|
||||||
|
- discussion: Mapped["Discussion"] = relationship(back_populates="consensus")
|
||||||
|
|
||||||
|
Use __tablename__ = "round", "message", "consensus" (singular, lowercase).
|
||||||
|
</action>
|
||||||
|
<verify>python -c "from moai.core.models import Round, Message, Consensus; print('All models imported')"</verify>
|
||||||
|
<done>All 5 models defined with complete relationships</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `python -c "from moai.core.models import Base, Project, Discussion, Round, Message, Consensus"` succeeds
|
||||||
|
- [ ] `ruff check src/moai/core/models.py` passes
|
||||||
|
- [ ] All foreign keys reference correct tables
|
||||||
|
- [ ] All relationships are bidirectional
|
||||||
|
- [ ] All fields have type hints
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All 5 models importable
|
||||||
|
- No linting errors
|
||||||
|
- Relationships match SPEC.md data model diagram
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`
|
||||||
|
</output>
|
||||||
184
.planning/phases/01-foundation/01-03-PLAN.md
Normal file
184
.planning/phases/01-foundation/01-03-PLAN.md
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
---
|
||||||
|
phase: 01-foundation
|
||||||
|
plan: 03
|
||||||
|
type: execute
|
||||||
|
---
|
||||||
|
|
||||||
|
<objective>
|
||||||
|
Create database module with async session management and write model tests.
|
||||||
|
|
||||||
|
Purpose: Enable database operations and validate models work correctly.
|
||||||
|
Output: Working database.py with async session factory, passing model tests.
|
||||||
|
</objective>
|
||||||
|
|
||||||
|
<execution_context>
|
||||||
|
~/.claude/get-shit-done/workflows/execute-phase.md
|
||||||
|
~/.claude/get-shit-done/templates/summary.md
|
||||||
|
</execution_context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
@.planning/PROJECT.md
|
||||||
|
@.planning/ROADMAP.md
|
||||||
|
@SPEC.md
|
||||||
|
@CLAUDE.md
|
||||||
|
@src/moai/core/models.py
|
||||||
|
|
||||||
|
**Tech choices:**
|
||||||
|
- SQLAlchemy 2.0 async (create_async_engine, AsyncSession)
|
||||||
|
- aiosqlite for async SQLite
|
||||||
|
- pytest-asyncio for async tests
|
||||||
|
|
||||||
|
**From CLAUDE.md:**
|
||||||
|
- Testing: pytest, target 80%+ coverage on core logic
|
||||||
|
- Database: SQLAlchemy + SQLite, upgrades to PostgreSQL in Phase 2
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<tasks>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 1: Create database module with async session management</name>
|
||||||
|
<files>src/moai/core/database.py</files>
|
||||||
|
<action>
|
||||||
|
Create src/moai/core/database.py with:
|
||||||
|
|
||||||
|
**Imports:** sqlalchemy.ext.asyncio (create_async_engine, AsyncSession, async_sessionmaker), contextlib
|
||||||
|
|
||||||
|
**Module-level:**
|
||||||
|
- DATABASE_URL: str = "sqlite+aiosqlite:///./moai.db" (default, can be overridden)
|
||||||
|
- engine: AsyncEngine = None (initialized lazily)
|
||||||
|
- async_session_factory: async_sessionmaker = None
|
||||||
|
|
||||||
|
**Functions:**
|
||||||
|
1. init_db(url: str | None = None) -> None:
|
||||||
|
- Creates engine with echo=False
|
||||||
|
- Creates async_session_factory
|
||||||
|
- Stores in module globals
|
||||||
|
- Use: `create_async_engine(url, echo=False)`
|
||||||
|
|
||||||
|
2. async create_tables() -> None:
|
||||||
|
- Imports Base from models
|
||||||
|
- Runs `async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all)`
|
||||||
|
|
||||||
|
3. @contextlib.asynccontextmanager
|
||||||
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
|
- Yields session from factory
|
||||||
|
- Handles commit on success, rollback on exception
|
||||||
|
- Pattern: `async with async_session_factory() as session: yield session; await session.commit()`
|
||||||
|
|
||||||
|
4. async def close_db() -> None:
|
||||||
|
- Disposes engine: `await engine.dispose()`
|
||||||
|
|
||||||
|
Add module docstring explaining session management pattern.
|
||||||
|
</action>
|
||||||
|
<verify>python -c "from moai.core.database import init_db, create_tables, get_session, close_db"</verify>
|
||||||
|
<done>Database module importable with all functions</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 2: Create model tests with in-memory database</name>
|
||||||
|
<files>tests/test_models.py</files>
|
||||||
|
<action>
|
||||||
|
Create tests/test_models.py with:
|
||||||
|
|
||||||
|
**Fixtures:**
|
||||||
|
- @pytest.fixture
|
||||||
|
async def db_session():
|
||||||
|
- init_db("sqlite+aiosqlite:///:memory:")
|
||||||
|
- await create_tables()
|
||||||
|
- async with get_session() as session: yield session
|
||||||
|
- await close_db()
|
||||||
|
|
||||||
|
**Test cases:**
|
||||||
|
|
||||||
|
1. test_create_project:
|
||||||
|
- Create Project(name="Test Project", models=["claude", "gpt"])
|
||||||
|
- Add to session, commit
|
||||||
|
- Assert id is set (UUID string), name correct, models correct
|
||||||
|
|
||||||
|
2. test_create_discussion_with_project:
|
||||||
|
- Create Project, add Discussion linked to it
|
||||||
|
- Assert discussion.project_id matches project.id
|
||||||
|
- Assert project.discussions contains the discussion
|
||||||
|
|
||||||
|
3. test_create_full_discussion_chain:
|
||||||
|
- Create Project -> Discussion -> Round -> Message
|
||||||
|
- Verify all relationships work
|
||||||
|
- Verify cascade (all linked when navigating relationships)
|
||||||
|
|
||||||
|
4. test_create_consensus:
|
||||||
|
- Create Discussion with Consensus
|
||||||
|
- Assert discussion.consensus is set
|
||||||
|
- Assert consensus.discussion links back
|
||||||
|
|
||||||
|
5. test_project_cascade_delete:
|
||||||
|
- Create Project with Discussion with Round with Message
|
||||||
|
- Delete Project
|
||||||
|
- Assert all children deleted (cascade)
|
||||||
|
|
||||||
|
Use pytest.mark.asyncio on all async tests.
|
||||||
|
Import all models and database functions.
|
||||||
|
</action>
|
||||||
|
<verify>pytest tests/test_models.py -v passes all tests</verify>
|
||||||
|
<done>5 model tests passing, cascade behavior verified</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
<task type="auto">
|
||||||
|
<name>Task 3: Add .gitignore entries and verify full test suite</name>
|
||||||
|
<files>.gitignore</files>
|
||||||
|
<action>
|
||||||
|
Update .gitignore to add:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
.pytest_cache/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run full test suite with coverage to verify everything works together.
|
||||||
|
</action>
|
||||||
|
<verify>pytest --cov=moai --cov-report=term-missing shows coverage, all tests pass</verify>
|
||||||
|
<done>.gitignore updated, tests pass with coverage report</done>
|
||||||
|
</task>
|
||||||
|
|
||||||
|
</tasks>
|
||||||
|
|
||||||
|
<verification>
|
||||||
|
Before declaring plan complete:
|
||||||
|
- [ ] `pytest tests/test_models.py -v` passes all 5 tests
|
||||||
|
- [ ] `pytest --cov=moai --cov-report=term-missing` runs successfully
|
||||||
|
- [ ] `ruff check src tests` passes
|
||||||
|
- [ ] Database file (moai.db) is gitignored
|
||||||
|
- [ ] Phase 1 complete: scaffolding, models, database all working
|
||||||
|
</verification>
|
||||||
|
|
||||||
|
<success_criteria>
|
||||||
|
|
||||||
|
- All tasks completed
|
||||||
|
- All tests pass
|
||||||
|
- No linting errors
|
||||||
|
- Phase 1: Foundation complete
|
||||||
|
</success_criteria>
|
||||||
|
|
||||||
|
<output>
|
||||||
|
After completion, create `.planning/phases/01-foundation/01-03-SUMMARY.md` with:
|
||||||
|
- Summary of all 3 plans in Phase 1
|
||||||
|
- Final verification that foundation is complete
|
||||||
|
- Ready for Phase 2: Bot Core
|
||||||
|
</output>
|
||||||
Loading…
Add table
Reference in a new issue