4.0 KiB
Local Dry-Run Foundation Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Make the current pipeline testable on a local machine without Hermes credentials, blog credentials, or live LLM calls.
Architecture: Keep the existing single script as the compatibility entrypoint. Add small, tested helpers for project .env loading, dry-run token behavior, and mock LLM responses. This creates a safe base for later Stage 0-8 modularization.
Tech Stack: Python standard library, unittest, current script/ai_daily_blog_pipeline.py.
Task 1: Add Local .env Loading
Files:
- Modify:
script/ai_daily_blog_pipeline.py - Create:
tests/test_env_loading.py
Step 1: Write the failing test
Test that load_env() reads project-root .env values when Hermes env is absent, and that real process environment variables override file values.
Step 2: Run test to verify it fails
Run: python -m unittest tests.test_env_loading -v
Expected: FAIL because the script currently only reads ~/.hermes/.env.
Step 3: Implement minimal code
Add a helper to parse env files and update load_env() to read:
- Project
.env ~/.hermes/.env- process environment
Later sources override earlier ones.
Step 4: Run test to verify it passes
Run: python -m unittest tests.test_env_loading -v
Expected: PASS.
Task 2: Let Dry-Run Skip Blog Token Requirement
Files:
- Modify:
script/ai_daily_blog_pipeline.py - Create:
tests/test_dry_run_config.py
Step 1: Write the failing test
Extract a small helper such as is_dry_run(env) and require_blog_token(env), then test:
AI_DAILY_DRY_RUN=1does not requireBLOG_SERVICE_TOKEN.- normal publish mode still requires a token.
Step 2: Run test to verify it fails
Run: python -m unittest tests.test_dry_run_config -v
Expected: FAIL because no helper exists and main() checks token before dry-run.
Step 3: Implement minimal code
Move dry-run detection before token validation in main().
Step 4: Run test to verify it passes
Run: python -m unittest tests.test_dry_run_config -v
Expected: PASS.
Task 3: Add Mock LLM Mode
Files:
- Modify:
script/ai_daily_blog_pipeline.py - Create:
tests/test_mock_llm.py
Step 1: Write the failing test
Test that llm_call(prompt, {"AI_DAILY_LLM_MODE": "mock"}) returns valid JSON for:
- semantic dedup prompts
- summary rewrite prompts
- classify prompts
Also test that guide generation can get a non-empty mock response.
Step 2: Run test to verify it fails
Run: python -m unittest tests.test_mock_llm -v
Expected: FAIL because mock mode does not exist.
Step 3: Implement minimal code
Add AI_DAILY_LLM_MODE=mock support in llm_call().
Step 4: Run test to verify it passes
Run: python -m unittest tests.test_mock_llm -v
Expected: PASS.
Task 4: Add Markdown Smoke Test
Files:
- Create:
tests/test_markdown_rendering.py - Modify:
script/ai_daily_blog_pipeline.pyonly if necessary.
Step 1: Write the failing or characterization test
Test that blog_markdown() renders:
## 导览- at least one section
- source links
- no
> > - no
[N]
Step 2: Run test
Run: python -m unittest tests.test_markdown_rendering -v
Expected: If it already passes, keep it as characterization coverage. If it fails because of > >, implement a focused fix.
Step 3: Implement minimal fix if needed
Strip leading > from guide text before adding blockquote syntax.
Step 4: Run test to verify it passes
Run: python -m unittest tests.test_markdown_rendering -v
Expected: PASS.
Task 5: Run Full Verification
Files:
- No new files.
Step 1: Run unit tests
Run: python -m unittest discover -s tests -v
Expected: PASS.
Step 2: Run compile check
Run: python -m py_compile script/ai_daily_blog_pipeline.py
Expected: exit code 0.
Step 3: Check git status
Run: git status --short
Expected: only intended files are modified or added.