| ANSWERS from HUMAN_REVIEW never reached the designer | FIXED 2026-07-05 | human-review-recovery.md |
| Generated tests used string literals for datetime | FIXED 2026-07-05 | render-py-bugs-2026-07-05.md |
mock.patch at module level / Mock without call inspection | FIXED — pre-judge static gate | three-layer-defense-2026-07-05.md |
| Judge distrust gave no actionable reason text | FIXED 2026-07-05 | three-layer-defense-2026-07-05.md |
| Quality-lint failures routed straight to HUMAN_REVIEW | FIXED 2026-07-05 | quality-lint-redesign-2026-07-05.md |
| GLM-5.2 returned bare strings for assumptions/open_questions | FIXED 2026-07-05 | glm-charter-bare-strings-2026-07-05.md |
| Calendar-quick-add passed unit tests but failed against real gws CLI | MITIGATED | e2e-verification-gap-2026-07-05.md |
| Charter under-decomposed named deliverables | MITIGATED | validation-run-learnings-2026-07-05.md |
| All-unit criteria missed integration surfaces | MITIGATED | validation-run-learnings-2026-07-05.md |
| Rich journaling / commit message extraction was incomplete | FIXED 2026-07-05 | rich-journaling-advisor-review-2026-07-05.md |
| Overfit audit was sequential and dominated wall-clock | FIXED 2026-07-05 | validation-run-learnings-2026-07-05.md |
| Zero progress output during long runs | FIXED 2026-07-06, expanded 2026-07-07 | advisor-review-progress-phase1-2026-07-06.md |
| Progress mechanism: open-append-close-per-event | FIXED 2026-07-07 (sync cron) | references/progress-jsonl-test-patterns.md |
Digest schema mismatch: parser expected kind=tool_ok, actual format is {ts, step, ...data} | FIXED 2026-07-07 | references/progress-jsonl-test-patterns.md, references/progress-jsonl-contract-2026-07-08.md |
| Calendar-quick-add e2e dry-run gate | AGAINST by advisors | advisor-consensus-fixes-2026-07-05.md |
| Ruff not found on PATH — lint gate silently fell back to py-syntax-only | FIXED 2026-07-08 | references/linter-reference.md |
| 9 phases ran with no progress marker (design result, lint, frozen_tests, rebuild, replan, test_repair, commit_scope, evidence rebuild, lint_discovery) | FIXED 2026-07-08 | references/observability-testing.md |
| 13 phases had only single markers (start OR complete, not both) — user couldn't tell when long phases like judge (21s) or implement (34s) began vs finished | FIXED 2026-07-08 (start/completed pairing) | references/observability-testing.md |
| Lint discovery probed all 15 file types on every run; unknown file types silently skipped with no research flag | FIXED 2026-07-08 (discover(paths) fast path + research flag) | references/linter-reference.md |
Pre-clarify hook checked wrong NBQ key (result["questions"]) — always found empty list, skipped even on vague requests | FIXED 2026-07-08 (check bucket then all_scored then questions as fallback) | references/nbq-investigator-integration.md |
Pre-clarify hook not gated behind DEVLOOP_RUN_REAL=1 — deterministic tests with real judges hung on NBQ model call | FIXED 2026-07-08 (gate behind same env var as e2e tests) | references/nbq-investigator-integration.md |
No automated test to prevent drift between linter-reference.md and lint._LANGUAGES | FIXED 2026-07-08 (10 sync tests: extension coverage, linter names, discover(paths), research flag, py linter availability) | references/linter-reference.md |
| Pre-clarify hook added as default, then removed — deterministic gates already handled underspecification for free; the hook was solving a solved problem | FIXED 2026-07-08 (made opt-in; lesson: check if existing architecture already covers the need before adding a new layer) | references/nbq-investigator-integration.md |
| 7 of 23 progress markers were unpaired (3 begin-no-end bugs: charter, ambiguity_gate, complete; 4 end-no-begin: coverage, lint_discovery, quality_lint, stop_check) — user couldn't tell when phases started vs finished | FIXED 2026-07-08 (added ✅ end markers for charter/ambiguity_gate/complete, ⏳ begin marker for lint_discovery; coverage/quality_lint/stop_check are instant single-call checks that don't need begin markers) | references/observability-testing.md |
Pipeline return type annotations missing — consolidate_questions returns list[dict] not tuple, but no annotation enforced this; a mock returning a tuple caused a silent hang | FIXED 2026-07-08 (12 stage functions annotated with from __future__ import annotations; contract test + MOCKING.md + _helpers.py) | references/nbq-investigator-integration.md |
Mocking full NBQ pipeline is brittle — mocking individual stages works for fast-rank but the full pipeline path calls internal functions (reset_usage, get_usage, voi.question_similarity) that aren't easily mockable; the _run_mocked helper pattern isolates mock setup from test assertions | MITIGATED 2026-07-08 (_run_mocked helper in test_nbq_contract.py; _mock_pipeline(n) + _fake_round(n) helpers; _helpers.py shared module) | references/nbq-investigator-integration.md |
| Control channel markers were thin on insight — begin markers said "coder attempt 0" without saying how many criteria, end markers said "linting" without saying how many files checked/skipped, complete marker was missing entirely | FIXED 2026-07-09 (enriched 8 markers with "what and why": implement begin/end, lint begin/end, evidence begin, judge end, overfit_audit end, complete end; every marker now carries file counts, criterion counts, and outcome context) | references/observability-testing.md |
| 5 high-risk functions had zero tests (gate.audit_tests, gate.stop_condition, loop._do_implement, devloop_bridge._regression_check, dispatch.resolve) — advisor review identified them as P1 gaps | FIXED 2026-07-09 (28 new tests across 4 files; 528→556 tests; patterns: sys.modules mocking for lazy imports, fake implement lambdas, mock _chat for dispatch, deterministic gate tests with fake Evidence) | references/observability-testing.md |
| 3 P2 areas had zero tests (worktree._resolve_conflicts, worktree._sync_and_verify, core-pipeline integration) — advisor review identified them as P2 gaps | FIXED 2026-07-09 (18 new tests across 2 files; 556→574 tests; patterns: real git repos with _init_repo, check=False for merge commands, cross-module integration pipeline, state lifecycle round-trip) | references/observability-testing.md |
| No correlation IDs in progress markers — parallel runs or retries produced interleaved markers impossible to attribute to a specific run | FIXED 2026-07-09 (8-char hex run_id from uuid.uuid4().hex[:8] in every _progress/_progress_event call; visible in stderr markers as [a3f1] prefix and in progress.jsonl records) | references/observability-testing.md |
| No crash markers — a mid-phase crash left the last marker as ⏳, indistinguishable from a hung run | FIXED 2026-07-09 (_progress_crash(run_dir, step, exc) emits ❌ with exception type + truncated traceback; wired into 3 exception handlers in loop.py + runner.py's top-level BaseException handler) | references/observability-testing.md |
| No automated validation of control channel markers — manual audit was the only way to detect unpaired begin/end markers | FIXED 2026-07-09 (test_marker_validation.py: validates begin/end pairing, run_id presence, crash marker traceback, and end-to-end marker emission; 590 tests total) | references/observability-testing.md |
| Multi-file E2E test flaky (~50% HUMAN_REVIEW due to judge non-determinism) — poisoned CI signal | MITIGATED 2026-07-09 (quarantined behind DEVLOOP_RUN_MULTIFILE=1; per-judge verdict logging to judge_verdicts.jsonl for 20-run diagnostic sprint; advisors explicitly warned against retry-wrapping — the flakiness IS the signal) | references/observability-testing.md |
Per-judge verdict log written to run_dir (inside worktree) — destroyed on finalize; E2E tests bypass the bridge so _preserve_trace never copies it out | FIXED 2026-07-09 (dual-write: run_dir + persistent /opt/data/devloop-diagnostics/judge_verdicts.jsonl; survives worktree cleanup and test teardown regardless of invocation path) | references/observability-testing.md |
No way to keep worktree directory for inspection — keep_branch only controls the git branch, not the directory; E2E tests and direct runner.run_task calls bypass the bridge's _preserve_trace | FIXED 2026-07-09 (keep_worktree=True parameter threaded through runner.run_task → devloop_bridge._run → run_build/run_debug; skips worktree.finalize() on both happy and crash paths; complements keep_branch) | references/observability-testing.md |
| Judge non-determinism causes ~50% HUMAN_REVIEW on multi-criteria runs — split votes (judge_a YES, judge_b NO) with no resolution mechanism; retry-wrapping would mask the signal | MITIGATED 2026-07-09 (tiebreaker judge: 3rd model called ONLY on split votes; majority 2-of-3 wins; TIEBREAKER model config in dispatch.py defaults to deepseek-reasoner:cloud — different provider from both judges and coder; tiebreaker votes + reasons logged to judge_verdicts.jsonl; cost added only on disagreements, not every criterion) | references/observability-testing.md |
lint_discovery progress marker always reports "0 linter(s) available" — lint.discover() returns a list of dicts, but loop.py:757 calls .get("linters", {}) as if it were a dict, so the count is always zero regardless of actual available linters | FIXED 2026-07-09 (iterate the list: sum(len(r["available"]) for r in _discovery if r.get("covered")); independently caught by all 3 advisor seats — DeepSeek, Kimi, GLM — in a structured 3-area review) | references/advisor-review-2026-07-09.md |
| No end-of-run summary — COMPLETE marker was missing entirely, HUMAN_REVIEW marker said only "test fault" without criteria counts, untrusted breakdown, or overfit/quality-lint findings; user had to read the grounding block to understand the full outcome | FIXED 2026-07-09 (_run_summary helper builds a one-line rollup from charter criteria + test_to_criterion + overfit suspects + quality findings; emitted as ✅ complete or ❌ HUMAN_REVIEW marker; degrades gracefully to "done" when charter is unavailable) | references/end-of-run-summary.md |