Files
ai-daily-report/docs/plans/2026-06-04-local-dry-run-foundation.md
2026-06-04 15:21:56 +08:00

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:

  1. Project .env
  2. ~/.hermes/.env
  3. 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=1 does not require BLOG_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.py only 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.