94 lines
3.7 KiB
Python
94 lines
3.7 KiB
Python
"""
|
|
Idea Lifecycle & Workflow State Machine Tests
|
|
PRD Section 10, 11, 28, 30, 31, 34:
|
|
- Separation of Lifecycle State and Processing State
|
|
- Claiming (AVAILABLE -> CLAIMED)
|
|
- Activation (CLAIMED -> ACTIVE)
|
|
- Work tracks & outputs
|
|
"""
|
|
|
|
import pytest
|
|
import asyncio
|
|
from thinkstorm.database import init_db, get_db, next_sequence, get_utc_now
|
|
from thinkstorm.processors.pipeline import execute_intake_pipeline, execute_work_track_workflow
|
|
from thinkstorm.models import LifecycleState, ProcessingState
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_full_idea_intake_and_claim_lifecycle():
|
|
init_db()
|
|
idea_id = next_sequence("idea")
|
|
raw_text = f"Quantum biological sensor interface for monitoring mitochondrial ATP flux oscillations in real-time {idea_id} https://example.com/sensor"
|
|
now = get_utc_now()
|
|
|
|
# 1. Anonymous submission
|
|
with get_db() as conn:
|
|
conn.execute(
|
|
"""
|
|
INSERT INTO ideas (id, original_text, submitted_at, title, summary, lifecycle_state, processing_state, enrichment_level, created_at, updated_at)
|
|
VALUES (?, ?, ?, 'Pending', 'Pending', 'SUBMITTED', 'QUEUED', 0, ?, ?)
|
|
""",
|
|
(idea_id, raw_text, now, now, now)
|
|
)
|
|
|
|
# 2. Run intake pipeline
|
|
await execute_intake_pipeline(idea_id)
|
|
|
|
# 3. Verify Idea reached AVAILABLE
|
|
with get_db() as conn:
|
|
idea = conn.execute("SELECT * FROM ideas WHERE id = ?", (idea_id,)).fetchone()
|
|
assert idea["lifecycle_state"] == LifecycleState.AVAILABLE.value
|
|
assert idea["processing_state"] == ProcessingState.IDLE.value
|
|
assert idea["enrichment_level"] >= 4
|
|
assert len(idea["title"]) > 0
|
|
assert idea["opengist_id"] is not None
|
|
|
|
# Verify raw original text was NEVER mutated
|
|
assert idea["original_text"] == raw_text
|
|
|
|
# Verify runs were recorded
|
|
runs = conn.execute("SELECT * FROM processor_runs WHERE idea_id = ?", (idea_id,)).fetchall()
|
|
assert len(runs) >= 4
|
|
total_tokens = sum(r["total_tokens"] for r in runs)
|
|
assert total_tokens > 0
|
|
|
|
# 4. Claim Idea (AVAILABLE -> CLAIMED)
|
|
claim_time = get_utc_now()
|
|
with get_db() as conn:
|
|
conn.execute(
|
|
"UPDATE ideas SET lifecycle_state = 'CLAIMED', claimed_by = 'researcher', claimed_at = ? WHERE id = ?",
|
|
(claim_time, idea_id)
|
|
)
|
|
claimed_idea = conn.execute("SELECT * FROM ideas WHERE id = ?", (idea_id,)).fetchone()
|
|
assert claimed_idea["lifecycle_state"] == LifecycleState.CLAIMED.value
|
|
assert claimed_idea["claimed_by"] == "researcher"
|
|
|
|
# 5. Activate Idea (CLAIMED -> ACTIVE)
|
|
with get_db() as conn:
|
|
conn.execute(
|
|
"UPDATE ideas SET lifecycle_state = 'ACTIVE' WHERE id = ?",
|
|
(idea_id,)
|
|
)
|
|
active_idea = conn.execute("SELECT * FROM ideas WHERE id = ?", (idea_id,)).fetchone()
|
|
assert active_idea["lifecycle_state"] == LifecycleState.ACTIVE.value
|
|
|
|
# 6. Add Work Track
|
|
track_id = next_sequence("work_track")
|
|
with get_db() as conn:
|
|
conn.execute(
|
|
"""
|
|
INSERT INTO work_tracks (id, idea_id, work_type_id, name, state, created_at)
|
|
VALUES (?, ?, 'CODING_PROJECT', 'Core Architecture Blueprint', 'PLANNED', ?)
|
|
""",
|
|
(track_id, idea_id, get_utc_now())
|
|
)
|
|
|
|
# 7. Execute Work Track Workflow
|
|
await execute_work_track_workflow(track_id)
|
|
|
|
# 8. Verify Work Track completed and outputs produced
|
|
with get_db() as conn:
|
|
track = conn.execute("SELECT * FROM work_tracks WHERE id = ?", (track_id,)).fetchone()
|
|
assert track["state"] == "COMPLETED"
|
|
outputs = conn.execute("SELECT * FROM work_track_outputs WHERE work_track_id = ?", (track_id,)).fetchall()
|
|
assert len(outputs) >= 2
|