From 4c9fc99cd4acff7a352b5b7bba1acdab3bdd2413 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 5 Jul 2026 16:17:13 -0400 Subject: [PATCH] docs(chronology): switch to manual maintenance; delete generator scripts; archive review report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deleted scripts/audit/generate_chronology.py + chronology_quality_gate.py after repeated corruption incidents (auto-classifier drifted from user intent, silently rewrote rows). chronology.md is now maintained by hand: add a row at the top when a track ships/abandons/is archived. Updated conductor/workflow.md §Chronology Maintenance and conductor/tracks.md §Archiving a track to reflect manual maintenance. Added 40 rows to conductor/chronology.md for the 2026-07-05 archive batch, with archive-folder paths and deferral notes where applicable. Removed 12 archived-track rows from conductor/tracks.md Active Tracks table (rows 2, 3, 7c, 16, 17, 23b, 23c, 23d, 25, 26, 29, 29c) and their track-detail anchors. Wrote docs/reports/ARCHIVE_REVIEW_20260705.md: a categorized index of unfinished work items from the archived tracks' state.toml files that remain relevant to the codebase, with a ranked follow-up list. --- conductor/chronology.md | 43 ++- conductor/tracks.md | 34 +- conductor/workflow.md | 8 +- docs/reports/ARCHIVE_REVIEW_20260705.md | 236 ++++++++++++ scripts/audit/chronology_quality_gate.py | 126 ------ scripts/audit/generate_chronology.py | 468 ----------------------- 6 files changed, 285 insertions(+), 630 deletions(-) create mode 100644 docs/reports/ARCHIVE_REVIEW_20260705.md delete mode 100644 scripts/audit/chronology_quality_gate.py delete mode 100644 scripts/audit/generate_chronology.py diff --git a/conductor/chronology.md b/conductor/chronology.md index efab3b69..66cfd6f5 100644 --- a/conductor/chronology.md +++ b/conductor/chronology.md @@ -1,7 +1,48 @@ - + | Date | ID | Status | Summary | Folder | Range | | --- | --- | --- | --- | --- | --- | +| 2026-07-05 | `superpowers_review_apply_high_20260705` | Completed | Phase 1: `26dd9258` Session Start Checklist item 13 added; Phase 2: `670a919e` tests/test_mma_skill_discipline.py (25 cases); Phase 3: `5037f48f` cross-reference + finalization. | `conductor/archive/superpowers_review_apply_high_20260705` | `0522252f..5037f48f` (3) | +| 2026-07-05 | `superpowers_review_20260619` | Completed | 16-section review of the superpowers skill suite: 14 PARITY / 3 PARTIAL / 2 ARCH-DIFF / 1 GAP; 25 decisions logged; 3 side artifacts (decisions.md, comparison_table.md, nagent_takeaways). | `conductor/archive/superpowers_review_20260619` | `eb272cb7..137868a1` (40) | +| 2026-07-05 | `agent_directives_consolidation_20260705` | Completed | AGENTS.md reduced from 202→87 lines; conductor/workflow.md §Process Anti-Patterns promoted to canonical home; conductor/edit_workflow.md §9 + product-guidelines.md subsections thin-pointed to canonical styleguides; 9 atomic commits with git notes. | `conductor/archive/agent_directives_consolidation_20260705` | `48ddd15c..8ab82022` (4) | +| 2026-07-05 | `test_sandbox_hardening_20260619` | Completed | Hard file-I/O sandbox for the test suite so a misbehaving test cannot leak artifacts into the working tree. Adds FR1 runtime guard + addopts redirect to `tests/artifacts/_pytest_tmp`. | `conductor/archive/test_sandbox_hardening_20260619` | `ec0716c9..eec44a09` (9) | +| 2026-07-05 | `test_patch_fixes_20260513` | Abandoned | After the refactor to use `ai_client_stub` as the module alias for `app_controller`, several tests fail because they use `patch('src.ai_client.X')`. Stale; superseded by later test_infrastructure_hardening + result_migration waves. | `conductor/archive/test_patch_fixes_20260513` | `12f16e9a..12f16e9a` (1) | +| 2026-07-05 | `send_result_to_send_20260616` | Completed | Tier 2 migration of the `send()` public API to `Result[str, ErrorInfo]` return type, replacing the str/None return. | `conductor/archive/send_result_to_send_20260616` | `c1d9a966..e2e57036` (15) | +| 2026-07-05 | `post_module_taxonomy_de_cruft_20260627` | Completed | Followup to module_taxonomy_refactor_20260627: removed leftover cruft, dead imports, and stale references after the models.py split. | `conductor/archive/post_module_taxonomy_de_cruft_20260627` | `05647d94..e4f652a7` (3) | +| 2026-07-05 | `phase2_4_5_call_site_completion_20260621` | Completed | Tier 2 autonomous completion of the phase 2/4/5 call-site migration left over from any_type_componentization_20260621. | `conductor/archive/phase2_4_5_call_site_completion_20260621` | `1a739ece..6e734a49` (3) | +| 2026-07-05 | `cruft_elimination_20260627` | Partially Completed | Goal: make Python behave as close to C11/Odin/Jai as possible. Phases 2, 4, 5, 6, 7 DEFERRED (ProjectContext dataclass; _do_generate return type; rag_engine.search() return type; 30 Optional[T] sites; 69 Any/dict[str,Any] sites). | `conductor/archive/cruft_elimination_20260627` | `f219616f..0a65056f` (8) | +| 2026-07-05 | `fable_review_20260617` | Completed | 10-cluster review of the "Fable" system-prompt artifact; 42 commits; 7-phase structure producing comparison_table, decisions, and per-cluster research notes. Section 16 (deferred nagent-rebuild recommendations) PENDING. | `conductor/archive/fable_review_20260617` | `058e2c93..22d3234b` (42) | +| 2026-07-05 | `context_preview_fixes_20260516` | Abandoned | Fix critical failures in the context composition feature (Preview button + Inspect/Slices buttons). Superseded by later context_composition_ux_20260601 + structural_file_editor_20260601 work. | `conductor/archive/context_preview_fixes_20260516` | `45de48bc..2249606e` (5) | +| 2026-07-05 | `public_api_migration_and_ui_polish_20260615` | Completed | First public-API migration sub-track: Result[T] adoption in the UI layer + polish. | `conductor/archive/public_api_migration_and_ui_polish_20260615` | `3febdab4..bbd4c7b5` (8) | +| 2026-07-05 | `code_path_audit_polish_20260622` | Completed | Tight surgical follow-up to code_path_audit_20260607 v2 (the MVP brute-force state). | `conductor/archive/code_path_audit_polish_20260622` | `1e92fbe9..ca219163` (12) | +| 2026-07-05 | `tier2_leak_prevention_20260620` | Completed | Prevents Tier 2 autonomous sandbox from leaking into AppData/Temp/Documents. Establishes the 3-layer hard-ban enforcement (OpenCode + OS + git hook). | `conductor/archive/tier2_leak_prevention_20260620` | `9224be7a..9224be7a` (1) | +| 2026-07-05 | `type_alias_unfuck_20260626` | Completed | The MINIMAL track to fix the type-usage problem that metadata_promotion_20260624 left as a tar pit. Replaces opaque aliases with typed dataclasses; vc4_codepaths_drop metric deferred. | `conductor/archive/type_alias_unfuck_20260626` | `f47be0ec..c0f30f28` (3) | +| 2026-07-05 | `data_oriented_error_handling_20260606` | Completed | The Fleury-pattern data-oriented error handling convention: Result[T] + NIL_T sentinels + ErrorInfo classification. Path C (mcp_client.py tool surface assert-removal) DEFERRED to follow-up. | `conductor/archive/data_oriented_error_handling_20260606` | `494f68f9..92cff705` (20) | +| 2026-07-05 | `data_structure_strengthening_20260606` | Completed | TypeAlias conventions + per-aggregate dataclass migration. Adds the audit_weak_types.py gate. typed_dict_migration_followup + public_api_migration_followup sections retained. | `conductor/archive/data_structure_strengthening_20260606` | `ed42a97a..1dce3203` (8) | +| 2026-07-05 | `code_path_audit_20260607` | Completed | First-pass brute-force code-path audit. Identifies NG2 (Optional[T] returns) and other anti-pattern sites; baseline for phase_2 + phase_3 + polish follow-ups. | `conductor/archive/code_path_audit_20260607` | `f069a8b2..5ac0618a` (22) | +| 2026-07-05 | `code_path_audit_phase_2_20260624` | Completed | The actual follow-up to code_path_audit_20260607. Snapshots pre-Phase-3 baseline and addresses NG2 violations. | `conductor/archive/code_path_audit_phase_2_20260624` | `7c352e1c..705cb50d` (2) | +| 2026-07-05 | `code_path_audit_phase_3_provider_state_20260624` | Completed | The fix for the 4 NG2 violations and 1 partial NG2 violation left by code_path_audit_phase_2_20260624. | `conductor/archive/code_path_audit_phase_3_provider_state_20260624` | `f7a29179..c3d575de` (10) | +| 2026-07-05 | `result_migration_20260616` | Completed | Umbrella track for the public-API Result[T] migration campaign (8 sub-tracks; 7 shipped + 1 Active per 2026-07-02). | `conductor/archive/result_migration_20260616` | `4c0b19b4..9c30ef64` (14) | +| 2026-07-05 | `result_migration_review_pass_20260617` | Completed | Audit + documentation pass over the Result[T] migration; informational, no production code change. | `conductor/archive/result_migration_review_pass_20260617` | `396eb82c..33479267` (19) | +| 2026-07-05 | `result_migration_baseline_cleanup_20260620` | Completed | Final baseline cleanup of the Result[T] migration campaign; 18 commits. Phase 10-14 invariant tests marked in_progress (per state.toml). | `conductor/archive/result_migration_baseline_cleanup_20260620` | `e9016749..9c30ef64` (18) | +| 2026-07-05 | `exception_handling_audit_20260616` | Completed | Audit of try/except/finally/raise sites per the data-oriented convention; adds the audit_exception_handling.py classifier + CI gate. | `conductor/archive/exception_handling_audit_20260616` | `e81413a2..ed660227` (5) | +| 2026-07-05 | `fix_mma_concurrent_tracks_sim_20260627` | Completed | Single-test fix track addressing the 1 remaining tier-3 failure after post_module_taxonomy_de_cruft_20260627. | `conductor/archive/fix_mma_concurrent_tracks_sim_20260627` | `ee185758..9d22c37c` (4) | +| 2026-07-05 | `fix_test_failures_20260624` | Completed | 3 surgical fixes to make the full test suite green after the polish merge. | `conductor/archive/fix_test_failures_20260624` | `7a9261c4..45876aef` (7) | +| 2026-07-05 | `live_gui_test_fixes_20260618` | Completed | Addresses 2 test failures reported as "documented issues" by result_migration_small_files_20260617 Phase 13. | `conductor/archive/live_gui_test_fixes_20260618` | `ff40138f..6ce55cba` (2) | +| 2026-07-05 | `default_layout_extract_20260629` | Completed | Extract tier-2's GOOD work on the default layout setup (layouts/ directory, install-on-empty-INI helpers, pre-run install timing fix, orphan-end-child cleanup). panel_defs_fleury_migration + render_persona_editor_window_fix DEFERRED. | `conductor/archive/default_layout_extract_20260629` | `466d2656..410d81fb` (2) | +| 2026-07-05 | `default_layout_install_20260629` | Completed | Fix GUI panels becoming invisible at startup whenever manualslop_layout.ini is missing/empty/stale. User Manual Verification DEFERRED. | `conductor/archive/default_layout_install_20260629` | `5ad062b1..4bf5ecd6` (10) | +| 2026-07-05 | `default_layout_install_followup_20260629` | Completed | Followup to default_layout_install_20260629: restore docking structure (strip stale dockspace IDs, force live-session apply). | `conductor/archive/default_layout_install_followup_20260629` | `34538639..4bf5ecd6` (2) | +| 2026-07-05 | `doeh_test_thinking_cleanup_20260615` | Completed | Cleanup of test-thinking-trace handling after the data-oriented error handling convention landed. | `conductor/archive/doeh_test_thinking_cleanup_20260615` | `925e366c..a8c81251` (5) | +| 2026-07-05 | `metadata_nil_sentinel_20260624` | Completed | Child 1 of metadata_ssdl_defusing_20260624 campaign. Introduces NIL_T sentinels for the Metadata aggregate. | `conductor/archive/metadata_nil_sentinel_20260624` | `84c0b4ec..7c352e1c` (3) | +| 2026-07-05 | `metadata_promotion_20260624` | Partially Completed | Promotes 5 sub-aggregates (CommsLogEntry, HistoryMessage, FileItem, ToolDefinition, ToolCall) to typed dataclasses. 3 open blockers (rag return type, tool builders dicts, drifted field types) deferred to follow-up tracks. | `conductor/archive/metadata_promotion_20260624` | `e50bebdd..b4bd772d` (16) | +| 2026-07-05 | `ai_loop_regressions_20260614` | Completed | Fixes regressions in the AI loop after the Result[T] migration; 11 commits. | `conductor/archive/ai_loop_regressions_20260614` | `7a4dcc96..6edeb2b5` (11) | +| 2026-07-05 | `module_taxonomy_refactor_20260627` | Completed | The user-reported models.py "dumping ground" (1044 lines, 36 classes, 5+ unrelated domains). Splits into per-system files (mma.py, project_files.py, type_aliases.py, mcp_tool_specs.py, result_types.py). | `conductor/archive/module_taxonomy_refactor_20260627` | `cba6e7d7..91a61288` (13) | +| 2026-07-05 | `any_type_componentization_20260621` | Partially Completed | Componentize `Any`-typed call sites across src/. The phase 2/4/5 call-site completion was deferred to phase2_4_5_call_site_completion_20260621 (shipped). | `conductor/archive/any_type_componentization_20260621` | `ed0d198a..751b94d4` (12) | +| 2026-07-05 | `chronology_v2_20260701` | Completed | The v2 chronology rewrite spec (354 lines — designed but never executed as a track; the v2 design informed the manual-maintenance switch on 2026-07-05). | `conductor/archive/chronology_v2_20260701` | `c1da0f99..c6593278` (6) | +| 2026-07-05 | `sqlite_docs_gui_2_20260612` | Completed | SQLite-granularity inline docs for gui_2.py (the original gui_2 doc track). | `conductor/archive/sqlite_docs_gui_2_20260612` | `99e7b6e8..56e1950b` (8) | +| 2026-07-05 | `sqlite_docs_gui_2_continued_20260613` | Completed | The ai_client.py continuation of the SQLite-granularity inline docs campaign. | `conductor/archive/sqlite_docs_gui_2_continued_20260613` | `cb129aae..e02a865d` (3) | +| 2026-07-05 | `directive_hotswap_harness_20260627` | Partially Completed | Harness for hot-swapping agent directive presets at session warm. Phase 3.2 (manual verification: does the LLM follow warm-with) DEFERRED to user per directive. 3 deferred + 2 in_progress per state.toml. | `conductor/archive/directive_hotswap_harness_20260627` | `03c7cfd5..03c7cfd5` (1) | +| 2026-07-02 | `intent_dsl_survey_20260612` | Completed | Intent-based scripting-languages survey (spec); Tier 1 authored, Tier 2 executed. 12 commits. | `conductor/tracks/intent_dsl_survey_20260612` | `b389f1be..45144872` (12) | | 2026-07-01 | `chronology_v2_20260701` | Completed | - `conductor/tracks/chronology_20260619/spec.md` (the v2 rewrite spec, 354 lines — designed but never executed) | `conductor/tracks/chronology_v2_20260701` | `c1da0f99..c6593278` (6) | | 2026-07-01 | `mma_quarantine_rag_test_decoupling_20260701` | Active | Two surgical interventions: | `conductor/tracks/mma_quarantine_rag_test_decoupling_20260701` | `e5f37e74..e5f37e74` (1) | | 2026-06-29 | `default_layout_extract_20260629` | In Progress | Extract tier-2's GOOD work on the default layout setup (the `layouts/` directory, the install-on-empty-INI helpers, the pre-run install timing fix, and the orphan-end-child cleanup) into… | `conductor/tracks/default_layout_extract_20260629` | `466d2656..410d81fb` (2) | diff --git a/conductor/tracks.md b/conductor/tracks.md index 2490f2be..5ccd0c31 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -18,45 +18,19 @@ Tracks that are unblocked and ready to start. Ordered by **dependency** (blocked | # | Priority | Track | Status | Blocked By | |---|---|---|---|---| | 36 | A (sunset) | [MMA Quarantine + RAG Test Decoupling](#track-mma-quarantine--rag-test-decoupling) | spec ✓, plan pending | (none) | -| 2 | A | [Qwen, Llama & Grok Vendor Integration](#track-qwen-llama-grok-vendor-integration) | **Completed** (per chronology.md; Phase 6 follow-up shipped) — row retained for cross-ref; archive candidate | test_infrastructure_hardening_20260609 (merged) | -| 3 | A | [Data-Oriented Error Handling (Fleury Pattern)](#track-data-oriented-error-handling) | **Completed** (per chronology.md) — archive candidate | test_infrastructure_hardening_20260609 (merged), qwen_llama_grok | -| 4 | A | [MCP Architecture Refactor (Sub-MCP Extraction)](#track-mcp-architecture-refactor) | spec ✓, plan pending | test_infrastructure_hardening_20260609 (merged), data_oriented_error_handling, data_structure_strengthening | -| 16 | A | [Test Sandbox Hardening](#track-test-sandbox-hardening) | spec ✓, plan ✓, ready to start | (none) | -| 17 | A | [Code Path Audit](#track-code-path-audit) | **Completed** (per chronology.md) — archive candidate | test_infrastructure_hardening_20260609 (merged), any_type_componentization (shipped), phase2_4_5_call_site_completion (shipped) | +| 4 | A | [MCP Architecture Refactor (Sub-MCP Extraction)](#track-mcp-architecture-refactor) | spec ✓, plan pending | (none) | | 22b | A | [Meta-Tooling Workflow Review](#track-meta-tooling-workflow-review) | spec ✓, plan ✓, parked | (none) | | 23 | A | [Intent-Based Scripting Languages Survey](#track-intent-dsl-survey) | spec ✓, plan pending | (none) | -| 23b | B | [Superpowers Skills Review](#track-superpowers-skills-review) | **Completed** (Phase 10 finalize `deecd931`; current_phase=10; 16 sections + 3 side artifacts; 25 decisions; verdict distribution 14 PARITY / 3 PARTIAL / 2 ARCH-DIFF / 1 GAP) — archive candidate | (none) | -| 23c | B | [Apply HIGH-Priority Recommendations](#track-superpowers-apply-high) | **Completed** (Phase 1: `26dd9258` Session Start Checklist item 13 added; Phase 2: `670a919e` tests/test_mma_skill_discipline.py (25 cases); Phase 3: `5037f48f` cross-reference + finalization) — archive candidate | superpowers_review_20260619 (shipped) | -| 23d | B | [Agent Directives Consolidation](#track-agent-directives-consolidation) | **Completed** (4 phases: AGENTS.md reduced from 202→87 lines; conductor/workflow.md §Process Anti-Patterns promoted to canonical home; conductor/edit_workflow.md §9 + product-guidelines.md subsections thin-pointed to canonical styleguides; 9 atomic commits with git notes) — archive candidate | (none) | -| 25 | B | [Fable System Prompt Review](#track-fable-review) | **Completed** (shipped 2026-06-17 per Phase 7 commit `22d3234b`; state.toml stale) — retained in tracks/ per user; will be archived later; reports kept for future reference | (none) | -| 26 | A | [Video Analysis Campaign (Pass 1 of 3)](#track-video-analysis-campaign) | **Completed** (archived 2026-06-24 → `archive/analysis/` with 22 sibling video_analysis tracks) — archive candidate | (none) | -| 29 | A | [Video Analysis De-obfuscation Campaign (Pass 2 of 3)](#track-video-analysis-deob) | **Completed** (archived 2026-06-24 → `archive/analysis/`) — archive candidate | (none) | -| 29c | A | [Pass 3 — C11/Python Projection](#track-pass-3-c11python-projection) | **Completed** (archived 2026-06-24 → `archive/analysis/`) — archive candidate | deob_apply (shipped), lexicon_v2 (shipped), c11_reference (shipped) | | 7 | — | [UI Polish (Five Issues)](#track-ui-polish-five-issues) | spec ✓, plan ✓, ready to start | (none) | -| 7c | B | [SQLite-Granularity Inline Docs for ai_client.py](#track-sqlite-docs-ai-client) | **Completed** (shipped 2026-06-13 per commit `e02a865d`; archived) — archive candidate | (none) | | 19 | — | [Context First Message Fix](#track-context-first-message-fix) | spec TBD | (none) | -> **Stale-row cleanup (2026-07-02):** rows 2, 3, 17 marked Completed per `conductor/chronology.md` (which is the canonical status source). They are retained here as archive candidates pending a `git mv` to `conductor/archive/`. `data_structure_strengthening_20260606` (also Completed per chronology) was already dropped from this table. - ### Track detail anchors - **MMA Quarantine + RAG Test Decoupling** → `conductor/tracks/mma_quarantine_rag_test_decoupling_20260701/` -- **Qwen, Llama & Grok Vendor Integration** → `conductor/tracks/qwen_llama_grok_integration_20260606/` (Phase 6 in progress) -- **Data-Oriented Error Handling** → `conductor/tracks/data_oriented_error_handling_20260606/` - **MCP Architecture Refactor** → `conductor/tracks/mcp_architecture_refactor_20260606/` -- **Test Sandbox Hardening** → `conductor/tracks/test_sandbox_hardening_20260619/` -- **Code Path Audit** → `conductor/tracks/code_path_audit_20260607/` - **Meta-Tooling Workflow Review** → `conductor/tracks/meta_tooling_workflow_review_20260620/` - **Intent-Based Scripting Languages Survey** → `conductor/tracks/intent_dsl_survey_20260612/` -- **Superpowers Skills Review** → `conductor/tracks/superpowers_review_20260619/` -- **Apply HIGH-Priority Recommendations** → `conductor/tracks/superpowers_review_apply_high_20260705/` -- **Agent Directives Consolidation** → `conductor/tracks/agent_directives_consolidation_20260705/` -- **Fable System Prompt Review** → `conductor/tracks/fable_review_20260617/` -- **Video Analysis Campaign (Pass 1)** → `conductor/tracks/video_analysis_campaign_20260621/` -- **Video Analysis De-obfuscation (Pass 2)** → `conductor/tracks/video_analysis_deob_20260621/` -- **Pass 3 — C11/Python Projection** → `conductor/tracks/video_analysis_deob_pass3_20260623/` - **UI Polish (Five Issues)** → `conductor/tracks/` (see spec for details) -- **SQLite-Granularity Inline Docs for ai_client.py** → `conductor/archive/sqlite_docs_gui_2_continued_20260613/` (7c is the ai_client continuation; the original gui_2 track is `conductor/archive/sqlite_docs_gui_2_20260612/`) - **Context First Message Fix** → `conductor/tracks/context_first_message_fix_20260604/` --- @@ -65,7 +39,7 @@ Tracks that are unblocked and ready to start. Ordered by **dependency** (blocked | # | Priority | Track | Status | Blocked By | |---|---|---|---|---| -| 6 | D | [Public API Result Migration](#track-public-api-result-migration) | **Largely Completed** (umbrella + 6 sub-tracks shipped per chronology): `public_api_migration_and_ui_polish_20260615` ✓, `send_result_to_send_20260616` ✓, `result_migration_review_pass_20260617` ✓, `result_migration_small_files_20260617` ✓, `result_migration_app_controller_20260618` ✓, `result_migration_gui_2_20260619` ✓, `result_migration_baseline_cleanup_20260620` ✓; only `result_migration_cruft_removal_20260620` still Active (Round 4 corrections applied; user-confirmed closeout; state.toml stale) | data_oriented_error_handling (deprecated send()) | +| 6 | D | [Public API Result Migration](#track-public-api-result-migration) | **Largely Completed** (umbrella + 6 sub-tracks shipped per chronology): `public_api_migration_and_ui_polish_20260615` ✓, `send_result_to_send_20260616` ✓, `result_migration_review_pass_20260617` ✓, `result_migration_small_files_20260617` ✓, `result_migration_app_controller_20260618` ✓, `result_migration_gui_2_20260619` ✓, `result_migration_baseline_cleanup_20260620` ✓; only `result_migration_cruft_removal_20260620` still Active (Round 4 corrections applied; user-confirmed closeout; state.toml stale) | (none) | | 8 | — | [Bootstrap gencpp Python Bindings](#track-gencpp-python-bindings) | spec TBD | (none) | | 9 | — | [Tree-Sitter Lua MCP Tools](#track-tree-sitter-lua-mcp-tools) | spec TBD | (none) | | 10 | — | [GDScript Language Support Tools](#track-gdscript-language-support-tools) | spec TBD | (none) | @@ -97,7 +71,7 @@ Tracks that are unblocked and ready to start. Ordered by **dependency** (blocked --- -> **Full project history:** see [`chronology.md`](./chronology.md) — the canonical index of all 244 tracks (active, shipped, superseded, abandoned), sorted newest-first, with git-history-evidence-backed status per row. Generated by `scripts/audit/generate_chronology.py`; quality-gated by `scripts/audit/chronology_quality_gate.py`. +> **Full project history:** see [`chronology.md`](./chronology.md) — the canonical index of all tracks (active, shipped, superseded, abandoned), sorted newest-first, with git-history-evidence-backed status per row. Maintained manually (the generator scripts were deleted 2026-07-05 after repeated corruption incidents). --- @@ -118,4 +92,4 @@ Tracks that are unblocked and ready to start. Ordered by **dependency** (blocked **Archiving a track (3 steps):** When a track ships and its folder moves from `conductor/tracks//` to `conductor/archive//`, complete all 3 steps in order: 1. Move the folder: `git mv conductor/tracks/ conductor/archive/` (preserves history as a rename). 2. Remove the row from this file (`conductor/tracks.md`). -3. Run `uv run python scripts/audit/generate_chronology.py --draft > conductor/chronology.md` to regenerate the chronology (the new row appears automatically). Commit with `docs(chronology): regenerate after shipped`. Run `uv run python -m scripts.audit.chronology_quality_gate --strict` before committing to verify the quality gate passes. \ No newline at end of file +3. Add a row to `conductor/chronology.md` (top of the table, newest-first) summarizing the track: Date, ID, Status, one-line Summary, Folder path, commit Range. Commit with `docs(chronology): add row for archive`. (Chronology is maintained manually as of 2026-07-05 — the generator scripts were deleted after repeated corruption incidents.) \ No newline at end of file diff --git a/conductor/workflow.md b/conductor/workflow.md index d4ba6e6c..a2795a21 100644 --- a/conductor/workflow.md +++ b/conductor/workflow.md @@ -624,17 +624,15 @@ The recommended execution order is the topological sort of the `blocked_by` grap ## Chronology Maintenance -**Chronology regeneration cadence.** After every track ships (completion commit + TRACK_COMPLETION report), the implementing agent must run `uv run python scripts/audit/generate_chronology.py --draft > conductor/chronology.md` to regenerate `conductor/chronology.md`. The regeneration is a single atomic commit (`docs(chronology): regenerate after shipped`). If the regeneration produces a diff beyond the new row (e.g., status changes on other rows), the agent must investigate before committing — a status drift on an unrelated row indicates a stale classifier, not a chronology bug. +**Manual maintenance (changed 2026-07-05).** The chronology generator scripts (`scripts/audit/generate_chronology.py` + `scripts/audit/chronology_quality_gate.py`) were deleted on 2026-07-05 after repeated corruption incidents (the auto-classifier drifted from the user's intent and silently rewrote rows). `conductor/chronology.md` is now maintained **manually**: when a track ships, is abandoned, is superseded, or its folder is archived, the implementing agent adds a row to the top of the chronology table (newest-first) by hand. Fields: Date, ID, Status, one-line Summary, Folder path, commit Range. Commit with `docs(chronology): add row for archive`. -**Quality gate.** `scripts/audit/chronology_quality_gate.py` runs as part of the regeneration. It fails (exit 1) if >30% of rows are classified as `Needs Review`. A failing quality gate blocks the regeneration commit. Run `uv run python -m scripts.audit.chronology_quality_gate --strict` before committing the regenerated chronology. - -**When to regenerate:** +**When to add a row:** - After a track ships (TRACK_COMPLETION report committed) - After a track is abandoned (TRACK_ABORTED report committed) - After a track is superseded (state.toml status = "superseded") - After a track folder is archived (moved to `conductor/archive/`) -**When NOT to regenerate:** +**When NOT to add a row:** - Mid-track (the chronology reflects filesystem state; a mid-track folder is correctly "In Progress" or "Active") - After a plan.md edit (the chronology doesn't track plan content) diff --git a/docs/reports/ARCHIVE_REVIEW_20260705.md b/docs/reports/ARCHIVE_REVIEW_20260705.md new file mode 100644 index 00000000..832318a0 --- /dev/null +++ b/docs/reports/ARCHIVE_REVIEW_20260705.md @@ -0,0 +1,236 @@ +# Archive Review: Unfinished Work Still Relevant to the Codebase + +**Date:** 2026-07-05 +**Author:** Tier 1 Orchestrator (post-archive audit) +**Scope:** Tracks archived in the 2026-07-05 batch (commits `98977f5c`..`2f3a8283`, ~21 archive commits). This report enumerates the unfinished work items recorded in each archived track's `state.toml` that remain relevant to the current codebase, grouped by category. + +The intent is a single index the user can scan to decide what (if anything) deserves a follow-up track. Each entry cites the archived track ID + the file:line / scope the deferral points at. + +--- + +## 1. The Python Type Promotion Mandate (the largest cluster) + +The C11/Odin/Jai-in-Python mandate (`conductor/code_styleguides/data_oriented_design.md` §8.5) is the project's Core Value. Several archived tracks deferred sub-scopes of this mandate; the deferrals are still live debt. + +### 1.1 `cruft_elimination_20260627` (Partially Completed) + +The biggest single source of deferred type-promotion work. Per `conductor/archive/cruft_elimination_20260627/state.toml`: + +| Phase | Status | Deferred Scope | +|---|---|---| +| phase_2 | deferred | Add `ProjectContext` dataclass for `flat_config` (spec mismatch) | +| phase_4 | deferred | Fix `_do_generate` return type | +| phase_5 | deferred | Fix `rag_engine.search()` return type (`List[Dict[str, Any]]` → typed) | +| phase_6 | deferred | Eliminate `Optional[T]` returns (30 sites across 14 files) | +| phase_7 | deferred | Eliminate `Any` and `dict[str, Any]` from internal signatures (69 sites) | +| phase_3 (partial) | completed (with deferral) | 13 `hasattr` checks removed in `app_controller.py`; **18 `hasattr` checks in `gui_2.py` deferred** | + +**Relevance now:** the 30 `Optional[T]` sites and 69 `Any`/`dict[str, Any]` sites are still present in `src/`. The audit scripts `scripts/audit_weak_types.py --strict` and `scripts/audit_optional_in_3_files.py` continue to enforce the boundary; these deferred sites are the remaining work the audits surface. + +### 1.2 `metadata_promotion_20260624` (Partially Completed) + +Per `conductor/archive/metadata_promotion_20260624/state.toml`, three open blockers remain: + +| Blocker | Location | Deferral | +|---|---|---| +| `blocker_3_rag_return_type` | `src/rag_engine.py:367` | `rag_engine.search()` returns `List[Dict[str, Any]]`; `RAGChunk` dataclass exists but consumers read dict keys directly (`chunk['document']`, `chunk['metadata']['path']`). Cascading return-type change affects 3+ sites. Deferred to `typed_rag_return_type_followup`. | +| `blocker_4_tool_builders_dicts` | `src/ai_client.py:609,615,665,671,1132,1138` | Per-vendor tool builders construct wire-format dicts directly (`raw_tools.append({'type': 'function', ...})`); `ToolDefinition` dataclass exists but isn't used. Deferred to `typed_tool_builders_followup`. | +| `blocker_5_drifted_field_types` | `src/type_aliases.py:10-148` | Field types drifted from the plan: `CommsLogEntry.kind` default, `CommsLogEntry.direction` default, `CommsLogEntry.content` type, `HistoryMessage.ts` type, `HistoryMessage.tool_calls` type, `HistoryMessage.role` default, no `@dataclass(slots=True)`, `PathInfo.logs_dir` type. Deferred to `field_type_alignment_followup`. | + +Also: `typed_dispatcher_boundaries_followup_20260625` was planned (typed parameters at function boundaries) but never opened. + +**Relevance now:** these are the most concrete unfinished type-promotion items. Each has a specific file:line and a specific migration target. They would compose into a single follow-up track or three small ones. + +### 1.3 `data_oriented_error_handling_20260606` (Completed, with deferrals) + +Per `conductor/archive/data_oriented_error_handling_20260606/state.toml`: + +- `t2_7` cancelled: the 30+ `assert p is not None` chain in the `mcp_client.py` tool functions is **not** removed. Deferred to "a follow-up track that will refactor the full `mcp_client.py` tool surface." +- `t2_8` cancelled: `async_dispatch` internals are not changed; the old str-returning API is preserved. + +**Relevance now:** `src/mcp_client.py` still has the `assert p is not None` chain in its tool dispatch. The audit_exception_handling.py gate continues to allow it under the existing baseline; a follow-up would tighten the baseline. + +### 1.4 `type_alias_unfuck_20260626` + +- `vc4_codepaths_drop = "not_measured"` — the required metric computation (number of value-class codepaths dropped) was deferred. The track shipped without the metric. + +### 1.5 `any_type_componentization_20260621` (Partially Completed) + +- The phase 2/4/5 call-site completion **was** deferred to `phase2_4_5_call_site_completion_20260621` (which shipped). +- `phase2_4_5_call_site_completion_20260621` has its own deferral: `OpenAICompatibleRequest.tools: list[dict] -> list[ToolSpec]; deferred` (cross_phase_coupling). + +**Relevance now:** `OpenAICompatibleRequest.tools` is still `list[dict]`, not `list[ToolSpec]`. This is the same site as `blocker_4_tool_builders_dicts` above (§1.2). + +--- + +## 2. The Metadata SSDL Campaign (parent + 2 of 3 children still Active) + +The `metadata_ssdl_defusing_20260624` campaign was a 3-child effort to defuse the `Metadata` aggregate's combinatoric explosion (4.01e22 effective codepaths). State: + +| Track | Status | Folder | +|---|---|---| +| `metadata_ssdl_defusing_20260624` (parent) | **Active** | `conductor/tracks/metadata_ssdl_defusing_20260624` | +| `metadata_nil_sentinel_20260624` (child 1) | Completed (archived) | `conductor/archive/metadata_nil_sentinel_20260624` | +| `metadata_generational_handle_20260624` (child 2) | **Active** | `conductor/tracks/metadata_generational_handle_20260624` | +| `metadata_field_cache_20260624` (child 3) | **Active** | `conductor/tracks/metadata_field_cache_20260624` | + +**Note:** these three Active tracks were NOT archived in the 2026-07-05 batch. They remain in `conductor/tracks/`. The user may want to either resume or formally abandon them; their state is currently stale (last commit `7c352e1c`, 2026-06-24). + +--- + +## 3. The Result[T] Migration Campaign (umbrella still Active) + +The umbrella `result_migration_20260616` and `result_migration_cruft_removal_20260620` were NOT archived and remain in `conductor/tracks/`. The archived children: + +- `public_api_migration_and_ui_polish_20260615` ✓ +- `send_result_to_send_20260616` ✓ +- `result_migration_review_pass_20260617` ✓ +- `result_migration_small_files_20260617` ✓ +- `result_migration_app_controller_20260618` ✓ +- `result_migration_gui_2_20260619` ✓ +- `result_migration_baseline_cleanup_20260620` — Phase 10-14 invariant tests marked `in_progress` per state.toml. The track shipped, but the invariant tests were never committed as checkpoints. + +**Relevance now:** the umbrella and `result_migration_cruft_removal_20260620` are the two remaining Active tracks in this campaign. The user previously confirmed closeout of the cruft_removal track; state.toml is stale. + +--- + +## 4. Provider Integration: Qwen / Llama / Grok (deferrals + 1 cancellation) + +### `qwen_llama_grok_followup_20260611` (archived via earlier commit `8ac8e64d`) + +Per its `[deferred_work]` section: +- **Anthropic + Gemini + DeepSeek** — deferred (use vendored call paths; the v2 matrix fields weren't wired into these providers' send functions). Only `gemini_cli` got the v2 wiring. +- **Qwen `_dashscope_call`** — deferred (uses `_dashscope_call`, not `send_openai_compatible`). Qwen v2 field wiring was not done. +- **8 of 9 UX adaptations** — deferred from `qwen_llama_grok_integration_20260606` Phase 5 (only 1 of 9 shipped: "Screenshot button iff vision"). +- **Per-field UI** (toggles, attachment buttons, panels) — design work deferred to a follow-up track. Only visibility-only badges shipped (`t5_4`). +- **Meta Llama API adapter** — `t4_3` / `t6_1` CANCELLED permanently. Meta does not publish a public OpenAI-compat surface; waiting for Meta. + +### `qwen_llama_grok_integration_20260606` (archived via earlier commit `8ac8e64d`) + +- `t1_11` in_progress: `dashscope>=1.14.0,<2.0.0` dependency was never added to `pyproject.toml`. +- Phase 5 was partial: 1 of 9 UX adaptations done. + +**Relevance now:** the v2 capability matrix is wired only for `gemini_cli`. Anthropic, Gemini (direct), DeepSeek, and Qwen still need the v2 wiring if the user wants full v2 coverage. The `dashscope` dependency still needs to be pinned. The 8 deferred UX adaptations (interactive per-field toggles/panels) are still open design work. + +--- + +## 5. Default Layout Campaign (3 tracks, multiple deferrals) + +### `default_layout_extract_20260629` +- `panel_defs_fleury_migration = "deferred (consumes LayoutFile + get_layouts_dir)"` — panel_defs still uses the old structure, not the Fleury-pattern dataclass migration. +- `render_persona_editor_window_fix = "deferred (Layer 1 sentinel catches the empty-content bug)"` — the persona editor window has an empty-content bug that's masked by a Layer 1 sentinel, not actually fixed. + +### `default_layout_install_20260629` +- `t2_9` deferred: User Manual Verification — needs a desktop session, can't run in headless Tier 2 sandbox. + +### `default_layout_install_followup_20260629` +- `t4_5` / `t4_6` in_progress: commit final plan + state + tracks.md row. (The track shipped functionally; the bookkeeping was never finished.) + +**Relevance now:** the persona editor empty-content bug is still masked, not fixed. The panel_defs Fleury migration is still open. + +--- + +## 6. Superpowers Review + Apply (the apply-high track has 1 in_progress task) + +### `superpowers_review_apply_high_20260705` +- `t3_4 = { status = "in_progress", commit_sha = "PENDING", description = "Commit + git notes" }` — the final commit + git notes for the apply-high track was never made. The work itself is done (Phase 1-3 shipped), but the bookkeeping commit is missing. + +### `superpowers_review_20260619` +- `research_only = "Per user Q1 = A (2026-06-19): no src/, tests/, or agent-directive changes. Recommendations go in decisions.md for the deferred rebuild."` — the deferred rebuild (nagent-rebuild) is a user-deferred decision; no track exists yet. + +**Relevance now:** minor. The `t3_4` bookkeeping commit is the only outstanding item; it's a 1-line git operation. + +--- + +## 7. Fable Review (1 pending section) + +### `fable_review_20260617` +- `t3_16 = { status = "pending", commit_sha = "", description = "Section 16: Recommendations for the deferred nagent-rebuild. Source: all clusters. Approx LOC: 200." }` — the report is complete through Section 15; Section 16 (the recommendations for the deferred nagent-rebuild) was never written. +- `deferred_nagent_rebuild = "user-deferred (no track yet); the Fable review's decisions.md is one of several inputs"` — the nagent-rebuild is a user-deferred decision that would consume Fable + Superpowers + nagent_review_20260608 outputs. + +**Relevance now:** if/when the user decides to do the nagent-rebuild, the Fable review's Section 16 is one of the inputs that doesn't exist yet. + +--- + +## 8. Directive Hotswap Harness (Partially Completed) + +### `directive_hotswap_harness_20260627` +- `t3_2 = { status = "deferred", ... "Manual verification: does the LLM follow the warm with: instruction? DEFERRED to user per directive" }` — the harness was built but never verified end-to-end with a live LLM session. +- `t3_4 = { status = "in_progress", ... "Commit the end-of-track report + this state.toml update atomically" }` — the end-of-track report + state.toml final commit was never made. +- 3 additional deferred items + 2 in_progress items per state.toml. + +**Relevance now:** the directive hotswap harness is functional but unverified. The user would need to test it in a live OpenCode session to confirm the LLM follows the `warm with:` instruction. This is the user-deferred verification gate. + +--- + +## 9. Chronology Maintenance Switch (this session) + +The chronology generator scripts (`scripts/audit/generate_chronology.py` + `scripts/audit/chronology_quality_gate.py`) were **deleted** in this session (2026-07-05) after repeated corruption incidents. `conductor/chronology.md` is now maintained manually: + +- `conductor/workflow.md` §"Chronology Maintenance" updated to reflect manual maintenance. +- `conductor/tracks.md` §"Archiving a track (3 steps)" step 3 updated to "Add a row to `conductor/chronology.md` (top of the table, newest-first) by hand." +- The footer of `conductor/tracks.md` updated: the "Full project history" pointer now says "Maintained manually (the generator scripts were deleted 2026-07-05...)". + +**Relevance now:** future agents must NOT try to regenerate the chronology via a script. The convention is now: add a row by hand when a track ships/abandons/is superseded/is archived. + +The archived tracks `chronology_20260619` and `chronology_v2_20260701` contain the design history for the deleted scripts; they're retained as reference but the scripts themselves are gone. + +--- + +## 10. Test Infrastructure (minor deferrals) + +### `test_sandbox_hardening_20260619` +- `phase_8 = { status = "partial", ... "Full suite verification (Tier-1 smoke run showed FR1 guard catches real corruption; full suite deferred to user)" }` — the full-suite verification was deferred to the user; only a Tier-1 smoke run was done. + +### `fix_mma_concurrent_tracks_sim_20260627` +- `t2_3 = { status = "in_progress", ... "Update TRACK_COMPLETION_fix_mma_concurrent_tracks_sim_20260627.md to include all 5 fixes" }` — the TRACK_COMPLETION report was never updated with all 5 fixes. +- `phase_1` is marked in_progress despite the track being functionally complete. + +### `result_migration_baseline_cleanup_20260620` +- Phases 10-14 invariant tests marked `in_progress` — never committed as checkpoints. + +**Relevance now:** minor. These are bookkeeping deferrals, not functional debt. + +--- + +## 11. Other Minor Deferrals + +### `tier2_leak_prevention_20260620` +- `[deferred]` section exists in state.toml (content not enumerated here; the track's primary work — the 3-layer hard-ban enforcement — shipped). + +### `data_structure_strengthening_20260606` +- `[typed_dict_migration_followup]` and `[public_api_migration_followup]` sections retained as forward-pointers; both were consumed by later tracks (the Result[T] migration campaign). + +### `post_module_taxonomy_de_cruft_20260627` +- `out_of_scope = "VC4/VC13 (full batched suite deferred); 2 pre-existing audit failures (main_thread_imports + exception_handling)"` — two pre-existing audit failures were noted as out-of-scope. They may still be failing. + +### `phase2_4_5_call_site_completion_20260621` +- `cross_phase_coupling = "OpenAICompatibleRequest.tools: list[dict] -> list[ToolSpec]; deferred"` — same as §1.2 `blocker_4_tool_builders_dicts`. + +### `code_path_audit_phase_2_20260624` +- `t3_1` was a snapshot task deferred to post-Phase-3 (the metric was captured post-phase instead). + +--- + +## Summary: What Deserves a Follow-Up Track? + +Ranked by codebase relevance (highest first): + +1. **`typed_rag_return_type_followup`** — `src/rag_engine.py:367` returns `List[Dict[str, Any]]`; `RAGChunk` exists but isn't used. Cascading change across 3+ consumer sites. (From §1.2 blocker_3.) +2. **`typed_tool_builders_followup`** — `src/ai_client.py:609,615,665,671,1132,1138` construct wire-format dicts directly; `ToolDefinition` exists but isn't used. Affects `OpenAICompatibleRequest.tools: list[dict]`. (From §1.2 blocker_4 + §1.5 + §4.) +3. **`field_type_alignment_followup`** — `src/type_aliases.py:10-148` has drifted field types vs the plan. Consumer migration could work or break. (From §1.2 blocker_5.) +4. **`cruft_elimination_phase_6_followup`** — 30 `Optional[T]` return sites across 14 files. (From §1.1 phase_6.) +5. **`cruft_elimination_phase_7_followup`** — 69 `Any`/`dict[str, Any]` internal-signature sites. (From §1.1 phase_7.) +6. **`mcp_client_tool_surface_assert_removal`** — the 30+ `assert p is not None` chain in `mcp_client.py` tool dispatch. (From §1.3.) +7. **`gui_2_hasattr_removal`** — 18 `hasattr` checks in `gui_2.py` (the deferred half of cruft_elimination phase_3). (From §1.1.) +8. **`qwen_v2_wiring` + `anthropic_gemini_deepseek_v2_wiring`** — v2 capability matrix fields not wired into Qwen/Anthropic/Gemini-direct/DeepSeek send functions. (From §4.) +9. **`dashscope_dependency_pin`** — add `dashscope>=1.14.0,<2.0.0` to `pyproject.toml`. (From §4, 1-line fix.) +10. **`v2_ux_interactive_toggles`** — per-field UI toggles/attachment buttons/panels (design work; the visibility-only badges shipped). (From §4.) +11. **`persona_editor_empty_content_fix`** — the persona editor window has an empty-content bug masked by a Layer 1 sentinel. (From §5.) +12. **`metadata_ssdl_defusing_campaign_resume_or_abandon`** — parent + 2 of 3 children still Active; state stale since 2026-06-24. User decision needed. (From §2.) +13. **`result_migration_cruft_removal_closeout`** — umbrella + cruft_removal still Active per state.toml; user confirmed closeout. Update state.toml. (From §3.) +14. **`fable_section_16`** — write Section 16 (nagent-rebuild recommendations, ~200 LOC). Only relevant if the user decides to do the nagent-rebuild. (From §7.) + +Items 1-3 are the most concrete type-promotion work and have specific file:line targets. Items 4-6 are the bulk type-promotion sweeps. Items 7-10 are provider-integration debt. Items 11-14 are smaller / decision-gated. + +The user should pick which (if any) of these to open as follow-up tracks. The archive review is complete; this report is the index for that decision. \ No newline at end of file diff --git a/scripts/audit/chronology_quality_gate.py b/scripts/audit/chronology_quality_gate.py deleted file mode 100644 index def690cc..00000000 --- a/scripts/audit/chronology_quality_gate.py +++ /dev/null @@ -1,126 +0,0 @@ -"""Quality gate for conductor/chronology.md. - -Checks: - 1. Needs Review threshold: >30% of rows are Needs Review -> FAIL - 2. Status distribution sanity: 0 rows are Completed -> FAIL - 3. Summary quality: >20% of summaries contain metadata-field text -> FAIL - 4. Per-row evidence: every row must have a non-empty reason -> FAIL - -Modes: - default: informational (exits 0, prints report) - --strict: CI gate (exits 1 on any violation) -""" -from __future__ import annotations -from dataclasses import dataclass, field -from pathlib import Path -import argparse -import sys - - -_METADATA_FIELD_PREFIXES = ( - "**Priority:**", - "**Date:**", - "**Initialized:**", - "**Track:**", - "**Track ID:**", - "**Parent umbrella:**", - "**Status:**", - "**Confidence:**", - "**Ancestors:**", -) - - -@dataclass(frozen=True, slots=True) -class QualityGateResult: - passed: bool - exit_code: int - violations: list[str] = field(default_factory=list) - total_rows: int = 0 - needs_review_count: int = 0 - completed_count: int = 0 - metadata_field_count: int = 0 - empty_reason_count: int = 0 - - -def run_quality_gate(rows: list[dict]) -> QualityGateResult: - violations: list[str] = [] - total: int = len(rows) - if total == 0: - return QualityGateResult(passed=False, exit_code=1, violations=["0 rows provided"]) - needs_review_count: int = sum(1 for r in rows if r.get("status") == "Needs Review") - completed_count: int = sum(1 for r in rows if r.get("status") == "Completed") - metadata_field_count: int = sum( - 1 for r in rows - if any(str(r.get("summary", "")).startswith(p) for p in _METADATA_FIELD_PREFIXES) - ) - empty_reason_count: int = sum(1 for r in rows if not r.get("reason", "").strip()) - # Check 1: Needs Review threshold (>30%) - if total > 0 and (needs_review_count / total) > 0.30: - violations.append( - f"Needs Review threshold exceeded: {needs_review_count}/{total} " - f"({needs_review_count/total*100:.0f}%) > 30%" - ) - # Check 2: 0 rows are Completed - if completed_count == 0: - violations.append("0 rows are Completed (classifier may be misclassifying everything)") - # Check 3: Summary quality (>20% contain metadata-field text) - if total > 0 and (metadata_field_count / total) > 0.20: - violations.append( - f"Summary quality: {metadata_field_count}/{total} " - f"({metadata_field_count/total*100:.0f}%) contain metadata-field text > 20%" - ) - # Check 4: Per-row evidence (every row must have non-empty reason) - if empty_reason_count > 0: - violations.append(f"{empty_reason_count} rows have empty reason (no evidence)") - passed: bool = len(violations) == 0 - return QualityGateResult( - passed=passed, - exit_code=0 if passed else 1, - violations=violations, - total_rows=total, - needs_review_count=needs_review_count, - completed_count=completed_count, - metadata_field_count=metadata_field_count, - empty_reason_count=empty_reason_count, - ) - - -def _load_rows_from_chronology(chronology_path: Path) -> list[dict]: - from scripts.audit.generate_chronology import walk_track_folders, _repo_root - # chronology_path is conductor/chronology.md; walk_track_folders expects the conductor dir - conductor_dir: Path = chronology_path.parent.resolve() - if not (conductor_dir / "tracks").is_dir(): - # Fallback: resolve from repo root - repo_root: Path = _repo_root(conductor_dir) - conductor_dir = repo_root / "conductor" - return walk_track_folders(conductor_dir) - - -def main() -> None: - parser = argparse.ArgumentParser(description="Quality gate for conductor/chronology.md") - parser.add_argument("--chronology", type=Path, default=Path("conductor/chronology.md")) - parser.add_argument("--rows-json", type=Path, default=None, help="Load rows from JSON file instead of re-walking") - parser.add_argument("--strict", action="store_true", help="Exit 1 on any violation") - args = parser.parse_args() - if args.rows_json and args.rows_json.is_file(): - import json - rows = json.loads(args.rows_json.read_text(encoding="utf-8")) - else: - rows = _load_rows_from_chronology(args.chronology) - result = run_quality_gate(rows) - print(f"Quality gate: {'PASS' if result.passed else 'FAIL'}") - print(f" Total rows: {result.total_rows}") - print(f" Needs Review: {result.needs_review_count}") - print(f" Completed: {result.completed_count}") - print(f" Metadata-field summaries: {result.metadata_field_count}") - print(f" Empty reasons: {result.empty_reason_count}") - if result.violations: - print(" Violations:") - for v in result.violations: - print(f" - {v}") - if args.strict and result.exit_code != 0: - sys.exit(result.exit_code) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/audit/generate_chronology.py b/scripts/audit/generate_chronology.py deleted file mode 100644 index 63f57e9c..00000000 --- a/scripts/audit/generate_chronology.py +++ /dev/null @@ -1,468 +0,0 @@ -#!/usr/bin/env python3 -"""Generate chronology for Manual Slop conductor tracks. - -Walks conductor/tracks/ and conductor/archive/, extracts per-track data -(date, ID, status, summary, commit range), and emits a markdown chronology -to stdout. - -The v2 classifier uses git-history evidence (work-commit count + report -overrides) instead of stale metadata.json.status. Returns -(status, confidence, reason) per row. - -Usage: - uv run python scripts/audit/generate_chronology.py --draft - uv run python scripts/audit/generate_chronology.py --root conductor/ - uv run python scripts/audit/generate_chronology.py # JSON dump -""" -from __future__ import annotations - -import argparse -import json -import re -import subprocess -import sys -from pathlib import Path -from typing import Optional - -_SLUG_DATE_RE = re.compile(r"\d{8}$") -_SENTENCE_END_RE = re.compile(r"\.\s") -_GIT_TIMEOUT = 30 -_DEFAULT_ROOT = "conductor/" - -_METADATA_FIELD_PREFIXES = ( - "**Priority:**", - "**Date:**", - "**Initialized:**", - "**Track:**", - "**Track ID:**", - "**Parent umbrella:**", - "**Status:**", - "**Confidence:**", - "**Ancestors:**", -) - -_WORK_COMMIT_PREFIXES = ("feat", "fix", "refactor", "perf", "test", "docs(report)") -_METADATA_COMMIT_PREFIXES = ("conductor(plan):", "conductor(state):", "conductor(track):", "docs(spec):", "docs(plan):") - - -def _is_work_commit(msg: str) -> bool: - """Check if a commit message is a work commit (feat/fix/refactor/perf/test with optional scope).""" - for prefix in _WORK_COMMIT_PREFIXES: - if msg.startswith(prefix + ":") or msg.startswith(prefix + "("): - if not any(msg.startswith(m) for m in _METADATA_COMMIT_PREFIXES): - return True - return False - - -def extract_slug_date(folder_name: str) -> Optional[str]: - m = _SLUG_DATE_RE.search(folder_name) - if not m: - return None - raw: str = m.group(0) - return f"{raw[:4]}-{raw[4:6]}-{raw[6:]}" - - -def _md_escape(text: str) -> str: - return text.replace("|", "\\|").replace("\n", " ").replace("\r", " ") - - -def _to_posix(path_str: str) -> str: - return path_str.replace("\\", "/") - - -def _first_sentence(line: str) -> str: - m = _SENTENCE_END_RE.search(line) - if m: - return line[: m.start() + 1].strip() - return line.strip() - - -def _truncate_to_25_words(text: str) -> str: - words: list[str] = text.split() - if len(words) <= 25: - return text - return " ".join(words[:25]) + "\u2026" - - -def extract_summary(folder_path: Path) -> str: - md_path = folder_path / "metadata.json" - if md_path.is_file(): - try: - data = json.loads(md_path.read_text(encoding="utf-8")) - desc = str(data.get("description", "")).strip() - if desc and not desc.startswith(_METADATA_FIELD_PREFIXES): - return _truncate_to_25_words(_first_sentence(desc)) - except (json.JSONDecodeError, OSError): - pass - for fname in ("spec.md", "plan.md"): - fpath = folder_path / fname - if not fpath.is_file(): - continue - try: - text = fpath.read_text(encoding="utf-8") - except OSError: - continue - for line in text.splitlines(): - stripped = line.strip() - if not stripped: - continue - if stripped.startswith("#"): - continue - if stripped.startswith(">"): - continue - bare = stripped.lstrip(">").strip() - if bare.startswith(_METADATA_FIELD_PREFIXES): - continue - return _truncate_to_25_words(_first_sentence(bare)) - return "Imported from archive (no spec)" - - -def _git_log(folder_relpath: str, *args: str) -> str: - try: - result = subprocess.run( - ["git", "log", *args, "--", folder_relpath], - capture_output=True, - text=True, - timeout=_GIT_TIMEOUT, - check=False, - ) - if result.returncode != 0: - return "" - return result.stdout - except (subprocess.SubprocessError, OSError): - return "" - - -def _git_log_multi(*folder_relpaths: str) -> str: - """Get git log for multiple paths in a single subprocess call.""" - try: - result = subprocess.run( - ["git", "log", "--oneline", "--", *folder_relpaths], - capture_output=True, - text=True, - timeout=_GIT_TIMEOUT, - check=False, - ) - if result.returncode != 0: - return "" - return result.stdout - except (subprocess.SubprocessError, OSError): - return "" - - -def _git_first_line(folder_relpath: str, *args: str) -> str: - out = _git_log(folder_relpath, *args) - stripped = out.strip() - if not stripped: - return "" - return stripped.splitlines()[0] - - -def _repo_root(start: Path) -> Path: - try: - result = subprocess.run( - ["git", "rev-parse", "--show-toplevel"], - capture_output=True, - text=True, - timeout=10, - check=False, - cwd=str(start), - ) - if result.returncode == 0 and result.stdout.strip(): - return Path(result.stdout.strip()) - except (subprocess.SubprocessError, OSError): - pass - return start.parent - - -def _parse_state_phase(state_path: Path) -> str: - if not state_path.is_file(): - return "no-state-toml" - try: - for line in state_path.read_text(encoding="utf-8").splitlines(): - if line.startswith("current_phase"): - v = line.split("=", 1)[1].strip().split("#")[0].strip().strip('"') - return v - except (OSError, Exception): - pass - return "?" - - -def _parse_state_status(state_path: Path) -> str: - if not state_path.is_file(): - return "" - try: - text = state_path.read_text(encoding="utf-8") - except OSError: - return "" - for line in text.splitlines(): - stripped = line.strip() - if stripped.startswith("status") and "=" in stripped: - parts = stripped.split("=", 1) - if len(parts) == 2: - val: str = parts[1].split("#")[0].strip() - val = val.strip('"').strip("'").strip() - return val - return "" - - -def _last_commit_date(folder_relpath: str) -> str: - try: - result = subprocess.run( - ["git", "log", "-1", "--format=%ad", "--date=short", "--", folder_relpath], - capture_output=True, text=True, timeout=_GIT_TIMEOUT, check=False, - ) - return result.stdout.strip() - except (subprocess.SubprocessError, OSError): - return "never" - - -def _count_work_commits_from_log(log: str) -> int: - count: int = 0 - for line in log.splitlines(): - msg: str = line.split(" ", 1)[1] if " " in line else "" - if _is_work_commit(msg): - count += 1 - return count - - -def _count_work_commits(folder_relpath: str) -> int: - log: str = _git_log(folder_relpath, "--oneline") - return _count_work_commits_from_log(log) - - -def _has_report_matching(reports_dir: Path, track_id: str, prefix: str) -> bool: - if not reports_dir.is_dir(): - return False - for f in reports_dir.iterdir(): - if f.is_file() and f.name.startswith(prefix) and track_id in f.name: - return True - return False - - -def classify_status( - folder_link: str, - current: str, - track_id: str, - repo_root: Path, - reports_dir: Path, - has_abort_report: bool = False, - state_status: str = "", - work_commits: int = -1, -) -> tuple[str, str, str]: - """Git-history evidence classifier returning (status, confidence, reason). - - Evidence priority: - 1. Override signals (highest): state.toml status (human-set), TRACK_COMPLETION/TRACK_ABORTED reports - 2. Git commit evidence (medium): work-commit count - 3. Directory location (low): archive/ vs tracks/ - 4. Fallback: Needs Review - """ - if "PLACEHOLDER" in track_id: - return ("Special", "high", "placeholder track") - if "contingency" in current.lower(): - return ("Special", "high", "contingency track") - # 1. Override signals — state.toml is human-set, trust it - if state_status == "superseded": - return ("Superseded", "high", "state.toml status=superseded") - if state_status in ("completed", "complete", "shipped"): - return ("Completed", "high", f"state.toml status={state_status}") - if state_status == "abandoned": - return ("Abandoned", "high", "state.toml status=abandoned") - if state_status == "archived": - return ("Completed", "high", "state.toml status=archived (treated as completed)") - if has_abort_report or _has_report_matching(reports_dir, track_id, "TRACK_ABORTED_"): - return ("Abandoned", "high", "abort report found") - if _has_report_matching(reports_dir, track_id, "TRACK_COMPLETION_"): - return ("Completed", "high", "completion report found") - # 2. Git commit evidence - is_archive = folder_link.startswith("conductor/archive/") - is_tracks = folder_link.startswith("conductor/tracks/") - if work_commits < 0: - work_commits = _count_work_commits(folder_link) - if work_commits >= 3: - return ("Completed", "medium", f"{work_commits} work commits") - if 1 <= work_commits <= 2 and is_tracks: - return ("In Progress", "medium", f"{work_commits} work commits in tracks/") - if work_commits == 0 and is_tracks: - return ("Active", "medium", "0 work commits in tracks/ (spec/plan only)") - # 3. Directory location - if is_archive: - # Archive tracks: the git mv to archive/ is a signal but not a definitive one. - # Tracks can be archived because they're completed OR because they're abandoned. - # Check the metadata.json status for human-set values, then fall back to Needs Review. - # (The state.toml override and TRACK_ABORTED report check already ran above.) - if work_commits >= 3: - return ("Completed", "medium", f"{work_commits} work commits") - # Check for plan-progression / "mark as completed" heuristics - full_log: str = _git_log(folder_link, "--oneline") - if folder_link.startswith("conductor/archive/"): - original: str = folder_link.replace("conductor/archive/", "conductor/tracks/", 1) - full_log = _git_log(original, "--oneline") + full_log - plan_progression: int = sum( - 1 for line in full_log.splitlines() - if ("mark" in line.lower() and "complete" in line.lower()) - or "complete" in line.lower() and ("phase" in line.lower() or "track" in line.lower() or "task" in line.lower() or "verification" in line.lower() or "audit" in line.lower()) - ) - if plan_progression >= 1: - return ("Completed", "low", f"archived with {plan_progression} completion-signal commits") - archive_move_completed: bool = any( - "completed" in line.lower() and ("archive" in line.lower() or "move" in line.lower()) - for line in full_log.splitlines()[:3] - ) - if archive_move_completed: - return ("Completed", "low", "archived with 'completed' in archive-move commit") - # No evidence of completion (no mark-complete, no feat commits, no report). - # If the track folder has planning commits only, it was likely planned but never - # implemented (abandoned). The work would have shown up as feat/fix commits. - if work_commits == 0: - # Last resort: check if "complete" appears in any commit message at all - has_any_complete: bool = any("complete" in line.lower() for line in full_log.splitlines()) - if has_any_complete: - return ("Completed", "low", "archived with 'complete' in commit messages") - return ("Abandoned", "low", "archived with 0 work commits and 0 completion signals") - return ("Completed", "low", f"archived with {work_commits} work commits on track folder") - # 4. Fallback - return ("Needs Review", "none", "classifier inconclusive") - - -def walk_track_folders(root: Path) -> list[dict]: - repo_root: Path = _repo_root(root) - reports_dir: Path = repo_root / "docs" / "reports" - rows: list[dict] = [] - for parent_dir, default_status in ( - (root / "tracks", "Active"), - (root / "archive", "Completed"), - ): - if not parent_dir.is_dir(): - continue - for folder in sorted(parent_dir.iterdir()): - if not folder.is_dir(): - continue - try: - folder_relpath = _to_posix(str(folder.relative_to(repo_root))) - except ValueError: - folder_relpath = _to_posix(str(folder)) - track_id: str = folder.name - slug_date = extract_slug_date(track_id) - # Get the full oneline log once. For archive folders, include both the - # archive path and the original tracks/ path (git mv preserves history - # but git log -- alone may miss pre-move commits) - if folder_relpath.startswith("conductor/archive/"): - original_path: str = folder_relpath.replace("conductor/archive/", "conductor/tracks/", 1) - oneline_log: str = _git_log_multi(folder_relpath, original_path) - else: - oneline_log = _git_log(folder_relpath, "--oneline") - log_lines: list[str] = [l for l in oneline_log.splitlines() if l.strip()] - commit_count: int = len(log_lines) - if slug_date: - date = slug_date - elif log_lines: - # First commit date via reverse log - first_commit = _git_first_line(folder_relpath, "--reverse", "--format=%aI") - date = first_commit[:10] if first_commit else "" - else: - date = "" - # Derive init_sha and end_sha from the oneline log - if log_lines: - init_sha: str = log_lines[-1].split(" ", 1)[0] # oldest (last in reverse-chronological git log) - end_sha: str = log_lines[0].split(" ", 1)[0] # newest (first in git log) - else: - init_sha = "" - end_sha = "" - metadata_path = folder / "metadata.json" - meta_status: str = "" - if metadata_path.is_file(): - try: - data = json.loads(metadata_path.read_text(encoding="utf-8")) - meta_status = str(data.get("status", "")).strip() - except (json.JSONDecodeError, OSError): - pass - state_status: str = _parse_state_status(folder / "state.toml") - work_commits: int = _count_work_commits_from_log(oneline_log) - status, confidence, reason = classify_status( - folder_link=folder_relpath, - current=meta_status or default_status, - track_id=track_id, - repo_root=repo_root, - reports_dir=reports_dir, - state_status=state_status, - work_commits=work_commits, - ) - summary: str = extract_summary(folder) - try: - folder_link = _to_posix(str(folder.relative_to(repo_root))) - except ValueError: - folder_link = _to_posix(str(folder)) - rows.append({ - "date": date, - "track_id": track_id, - "status": status, - "confidence": confidence, - "reason": reason, - "summary": summary, - "init_sha": init_sha, - "end_sha": end_sha, - "commit_count": commit_count, - "folder_link": folder_link, - }) - rows.sort(key=lambda r: r["track_id"]) - rows.sort(key=lambda r: r["date"], reverse=True) - return rows - - -def format_markdown(rows: list[dict]) -> str: - from datetime import date as today_date - lines: list[str] = [] - lines.append(f"") - lines.append("") - lines.append("| Date | ID | Status | Summary | Folder | Range |") - lines.append("| --- | --- | --- | --- | --- | --- |") - for r in rows: - range_str: str = f"`{r['init_sha']}..{r['end_sha']}` ({r['commit_count']})" if r["init_sha"] else "n/a" - lines.append( - f"| {r['date']} | `{r['track_id']}` | {r['status']} | " - f"{_md_escape(r['summary'])} | `{r['folder_link']}` | {range_str} |" - ) - needs_review = [r for r in rows if r["status"] == "Needs Review"] - if needs_review: - lines.append("") - lines.append("## Needs Review") - lines.append("") - for r in needs_review: - lines.append(f"- `{r['track_id']}` (`{r['folder_link']}`): {r['reason']}") - return "\n".join(lines) + "\n" - - -def main() -> None: - if hasattr(sys.stdout, "reconfigure"): - try: - sys.stdout.reconfigure(encoding="utf-8") - except (OSError, ValueError): - pass - parser = argparse.ArgumentParser( - description="Generate chronology for Manual Slop conductor tracks.", - ) - parser.add_argument( - "--draft", - action="store_true", - help="Emit markdown table to stdout.", - ) - parser.add_argument( - "--root", - default=_DEFAULT_ROOT, - help=f"Path to conductor root (default: {_DEFAULT_ROOT}).", - ) - args = parser.parse_args() - root = Path(args.root) - if not root.is_absolute(): - root = Path.cwd() / root - rows = walk_track_folders(root) - if args.draft: - sys.stdout.write(format_markdown(rows)) - else: - sys.stdout.write(json.dumps(rows, indent=2)) - - -if __name__ == "__main__": - main() \ No newline at end of file