Date: YYYY-MM-DD Status: Draft / Final — approved for implementation Author: Decompose → Critique → Refine across N reviews + live benchmarking Implementation: Fresh kiro-cli session implements. Original session reviews.
You are implementing [brief description of what is being built/refactored]. [One sentence on what is being replaced and why.] Every decision in this plan was made through Decompose → Critique → Refine and validated against real data. Follow the plan exactly.
ACCURACY OVER SPEED. This tool runs in production environments.
If you are unsure about a method signature, a return type, an edge case,
or any behavior — STOP. Verify using the code tool. Never guess.
A wrong assumption that ships is worse than a delay that catches it.
| Term | Meaning |
|---|---|
| Phase A-E | Implementation phases of THIS PLAN |
| DCR | Decompose → Critique → Refine methodology |
| [Add project-specific terms here] | [Definitions] |
Use this method for EVERY non-trivial decision during implementation:
- DECOMPOSE: Break the problem into components. What are the moving parts?
- CRITIQUE: What could go wrong? What edge cases exist? What assumptions am I making?
- REFINE: Adjust the approach based on the critique. Then implement.
If you find yourself writing code without having done this for the current task, STOP. Back up. Decompose first.
Before calling ANY function from another module:
- VERIFY the function exists:
code search_symbols <function_name> - READ the actual signature:
code goto_definitionorcode get_hover - CONFIRM parameter names and types match what you're passing
- CONFIRM return type matches what you're assigning to
If you cannot verify → DO NOT WRITE THE CALL. Ask the user or flag it.
This is not optional. This is the #1 source of LLM-generated bugs.
If you change how ANY pattern works:
grep -rn "<pattern>" <relevant_dirs>— find ALL occurrences- Verify EACH occurrence is consistent with the new pattern
- Fix ALL of them, not just the one you found
One instance fixed, nine left broken = the bug is still there.
After writing any function, verify:
- Code does → what does the function actually do? Trace the logic.
- Docstring claims → does the docstring match the actual behavior?
- Plan says → does the implementation match what the plan specifies?
If ANY of these three disagree → fix the discrepancy before moving on.
-
NEVER call external APIs during implementation or testing unless explicitly gated by
@pytest.mark.integration. All external responses come from fixture files. All tests use patched network.SAFETY NET (implement FIRST, before anything else): Add environment variable guards to every external API entry point:
if os.environ.get("NO_EXTERNAL_CALLS"): raise RuntimeError("External calls blocked by NO_EXTERNAL_CALLS")
The implementor MUST set the env var before ANY work:
export NO_EXTERNAL_CALLS=1This is a HARD TECHNICAL BLOCK. Not a rule — a runtime crash.
-
NEVER write to [deprecated state file/system]. It is being replaced. If you find yourself importing from it — STOP. You are implementing the OLD system.
-
NEVER auto-correct an unknown state. If the system returns something you don't recognize, display it raw with a warning and log it. Do not default to any state.
-
NEVER guess method signatures. Before calling ANY function, verify the signature exists using the
codetool orgrep. -
NEVER commit secrets or client data to git. All test fixtures must be scrubbed. Run post-redaction scan before committing.
-
NEVER skip error handling. Every network call has a timeout. Every file read handles missing/corrupt. Every JSON parse handles malformed. No bare
except:. Noexcept Exception: pass. -
NEVER write a test that passes when the code is removed. After writing each test, verify: "If I delete the code this tests, does the test fail?" If no, the test is useless.
[Add project-specific guardrails as needed]
- [Core module] exists and [key function] returns correct results for all N states
- All Tier 1 tests pass
- All Tier 2 tests pass
-
pytest tests/<project>/test_<tier1>.py tests/<project>/test_<tier2>.py -v→ 0 failures
- [UI/integration layer] displays correct state
- [Background processes] work without issues
- All Tier 3 + Tier 4 tests pass
- [Pipeline/automation] produces correct outputs
- [Marker files/state] written correctly on success
- All Tier 5 tests pass
- No imports of [deprecated module] remain in modified files (grep verify)
- [Deprecated module] removed/gutted
- [Dead code files] deleted
-
git grep "<deprecated_import>" src/returns 0 results - All existing tests still pass
- E2E tests pass
-
pytest tests/<project>/ -x -q→ 0 failures -
grep -rn "<deprecated_import>" <modified_files>→ 0 results - All new functions have ENTER/EXIT/EXCEPTION trace logging
- All new functions have type hints on signature and return
-
encoding="utf-8"on all file I/O - No
print()except via approved display library - No hardcoded IPs, domains, credentials, or client data
Before moving to the next file, verify:
-
python3 -c "import <module>"succeeds (no import errors) - ENTER/EXIT in all functions >5 lines
-
grep -n "except:" <file>→ 0 bare excepts -
grep -n "except Exception: pass" <file>→ 0 swallowed exceptions - RUNTIME CONTEXT SIMULATION:
- Run from repo root
- Run from data dir
- With missing config: verify graceful error, not crash
- With empty data: verify no crash
- THREE-WAY CROSS-REFERENCE: code behavior matches docstring matches plan
The implementor MUST NOT take shortcuts to achieve expected output:
-
NEVER hardcode display strings to match expected output. All display text must be derived from real data. If the expected output says "7 items" the code must COUNT them, not print the string "7".
-
NEVER stub a function to return a fixed value. If a function is supposed to query/compute, it must actually do so (or replay a fixture).
-
NEVER skip the derivation logic. Every state must go through the full derivation chain. No
if name == 'foo': return 'done'shortcuts. -
NEVER mock at a higher level than necessary. Mock the network boundary (
requests.post), not the business logic. The logic between the network call and the display must execute for real.
Maintain this checklist as you work. Update after each task:
PHASE A: [Name]
[ ] A1: [file] — [description]
[ ] A2: [file] — [description]
...
[ ] GATE A→B: all checks pass
PHASE B: [Name]
[ ] B1: [file] — [description]
...
[ ] GATE B→C: all checks pass
PHASE C: [Name]
[ ] C1: [file] — [description]
...
[ ] GATE C→D: all checks pass
PHASE D: Cleanup
[ ] D1: [deprecated file] — gutted/deleted
...
[ ] GATE D→E: all checks pass
PHASE E: Documentation
[ ] E1: README updated
[ ] E2: Steering/docs updated
[ ] FINAL: expected end state verified against live app
Is the import for [deprecated functions]?
YES → STOP. You are implementing the old system. Use [new module] instead.
NO → Is it for [utility that was extracted]?
YES → Use [new standalone module]
NO → Ask the user.
Expected end state: See docs/plans/expected-end-state.md for exact
screen mockups the implementation must produce. All data must be derived
from real sources. Hardcoding strings to match expected output is FORBIDDEN.
Steering files to load (implementation guidance):
- [List relevant steering files]
DO NOT load (contain credentials/engagement-specific data):
- [List files to avoid]
Git workflow: All commits via bash tools/git-ship.sh <branch> "<message>" [files].
Then merge locally to main, push, delete branch.
[Describe the current broken data flow. Where does state live? Who writes
it? What conflicts arise?]
Why it breaks: [Root cause analysis — be specific about the architectural flaw, not just symptoms.]
| File | Role | Status after refactor |
|---|---|---|
| [path] | [what it does now] | GUTTED / DELETED / MODIFIED / UNCHANGED |
[2-3 sentences: What is broken? Why can't it be patched incrementally? Include quantified evidence — number of bugs, time wasted, root cause.]
[The architectural change in one sentence.]
| Question | Answer | How |
|---|---|---|
| [What state does the system need?] | [Where it comes from] | [Mechanism] |
| File | Written Once | Purpose |
|---|---|---|
| [marker_file] | [When] | [What it represents] |
[Describe the display/performance cache. Emphasize it is deletable and will be rebuilt from source of truth.]
{
"item-name": {
"state": "value",
"polled_at": 1700000000.0
}
}1. [Highest priority check] → [State] (no expensive call)
2. [Next priority check] → [State]
3. [Requires external call] → [State]
...
N. Doesn't match any known pattern → UNKNOWN (display raw, log)
[Note which steps are file checks (0ms) vs which require network calls.]
[How concurrent access is handled. Lockfiles, queues, single-writer, etc.]
[State A] detected → auto [action] → show "⏳ Working..."
[State B] detected → auto [action] → write [terminal marker]
Failure handling: max N retries per item. After N failures → surface error.
| Layer | Reads | Writes |
|---|---|---|
| [Component] | [What it reads] | [What it writes] |
[One source of truth, one cache, N readers, zero conflicts.]
[How the system handles missing dependencies, proxies, configs. Must work on a fresh machine without manual setup.]
[ASCII mockup of the primary interface]
| Internal State | Display Label | Bucket/Category |
|---|---|---|
| [state] | [emoji + label] | [grouping] |
- [Refresh interval]
- [What triggers refresh]
- [How to avoid flicker — diff-based redraw]
[ASCII mockup of the detail/drill-down view]
| # | As a... | I want to... | So that... | Acceptance |
|---|---|---|---|---|
| U1 | [role] | [action] | [benefit] | [criterion] |
[Item created]
└─ State: NOT_STARTED → "▶️ Start"
[First action taken]
└─ State: IN_PROGRESS → "⏳ Working..."
[External system responds]
└─ State: NEEDS_INPUT → "❓ Action Required"
[Pipeline completes]
└─ State: DONE → item disappears from active list
[External system unavailable]
└─ If cached data exists: State = CACHED_RESULT
└─ If no cached data: State = NOT_STARTED (redo)
| Task | File | Action | Lines |
|---|---|---|---|
| A1 | [path] | NEW — [description] | ~N |
| A2 | [path] | MODIFY — [description] | ~N |
Creates: [What this module does]
Functions to implement:
| Function | Signature | Purpose | Calls |
|---|---|---|---|
| [name] | (param: Type) -> ReturnType |
[purpose] | [dependencies] |
Imports from existing code:
from [module] import [func]— verify signature:[expected signature]
Must NOT import: [deprecated modules]
| Task | File | Action | Lines |
|---|
| Task | File | Action | Lines |
|---|
| Task | File | Action | Lines |
|---|
| Task | File | Action | Lines |
|---|
- [State file] renamed to
.bakduring migration (kept 2 weeks) - All deleted code is in git history
- If critical bug:
git revertthe merge commit + restore.bak - Old tests also in git history for restoration
- Test real behavior, not mock behavior. Assert on OUTCOMES, not mock calls.
- Don't mock what you don't own. Responses replayed from real captures.
- Every test uses real data. Real captures as fixtures (redacted).
- E2E via pexpect. Spawn real app, drive with keystrokes.
- No sunny-day-only tests. Every function has negative/edge case variants.
[Describe the fixture source, redaction process, and what each fixture represents.]
| State | Capture Source | Signal |
|---|---|---|
| [state] | [fixture file] | [what makes it this state] |
| Tier | File | Tests | Type | Priority |
|---|---|---|---|---|
| 1 | [test file] | ~N | Unit + real data | P0 |
| 2 | [test file] | ~N | Unit | P1 |
| 3 | [test file] | ~N | Integration | P0 |
| ... | ||||
| Total | ~N |
Source: [Fixture file] Flow: [State transitions] Expected result: [What function returns / files written]
Source: [Fixture or synthetic] Expected: [Graceful behavior]
| # | Scenario | Expected |
|---|---|---|
| N1 | [bad input/condition] | [graceful handling, not crash] |
- External call blockers are set in shell
- Test fixtures contain NO real sensitive data
- No production identifiers in test code
-
pytest <test_file> -v→ all pass - No real API URLs in test output
- All external calls inside
mock.patchblocks - Every test creating external resources has cleanup in
finally:
- Full suite passes
- Total count matches plan
- Mutation check: comment out core function → test fails
- No asserting on mock call args as primary assertion
- No sunny-day-only tests
- No tests that pass when code is removed
- No mocking business logic — mock only the network boundary
- No skipping error paths
- [List tests that test deprecated code]
- [List existing tests that remain valid]
Remove from tracking: [List] Scrub in-place: [List] Add to .gitignore: [Patterns]
[Describe redaction process and validation.]
[Operation]: [measured time]
[Another operation]: [measured time]
Production load:
[Fast path]: [time] (no external calls)
[Slow path]: [time] (requires calls)
[Refresh]: [time] every [interval] = [duty cycle]
Before writing ANY function call:
- Verify the method exists
- Verify parameter names match
- Verify return type matches
- NEVER guess
Every function >5 lines gets ENTER/EXIT/EXCEPTION:
def my_function(arg: str) -> Result:
_t0 = time.monotonic()
logger.debug("my_function: ENTER arg=%s", arg)
try:
# ... logic ...
logger.debug("my_function: EXIT result=%s elapsed=%.3fs", result, time.monotonic() - _t0)
return result
except Exception as exc:
logger.error("my_function: EXCEPTION %s elapsed=%.3fs", exc, time.monotonic() - _t0, exc_info=True)
raise- Type hints on ALL signatures and returns
pathlib.Pathfor all file opsloggingmodule only — noprint()- No bare
except:— catch specific exceptions encoding="utf-8"on all file I/O
- Network: timeout + retry on transient failure
- File reads: handle missing, corrupt, permission denied
- JSON: handle malformed with logged warning
- Never silently swallow
| Category | Lines |
|---|---|
| Deleted | ~N |
| Added (code) | ~N |
| Added (tests) | ~N |
| Added (docs) | ~N |
| Net code change | ~N |
| Total new tests | ~N |
| File | Purpose |
|---|---|
| [path] | [description] |
| File | What changes |
|---|---|
| [path] | [description] |
| File | Reason |
|---|---|
| [path] | [reason] |
[Document the signatures and return types of critical functions. Include dataclass definitions for complex return types.]
@dataclass
class ResultType:
field: str
count: int[If a working prototype exists from benchmarking, include the code. This gives the implementor a concrete starting point.]
def key_function(input: Path) -> tuple[str, str]:
"""[Docstring matching plan section N.N]"""
# ... implementation ...| Old system | New system | Display |
|---|---|---|
| [old state/route] | [new state] | [label] |
| Line | Current import | Action |
|---|---|---|
| N | from old_module import X |
DELETE / REPLACE |
[Document any reconciliation work done before the plan was written. The implementor must not redo or conflict with these.]
| Item | Change | Notes |
|---|---|---|
| [item] | [what was done] | [don't overwrite] |