diff --git a/conductor/archive/superpowers/specs/2026-07-05-directive-preset-system-design.md b/conductor/archive/superpowers/specs/2026-07-05-directive-preset-system-design.md new file mode 100644 index 00000000..af64d62c --- /dev/null +++ b/conductor/archive/superpowers/specs/2026-07-05-directive-preset-system-design.md @@ -0,0 +1,322 @@ +# Directive Preset System Design + +**Date:** 2026-07-05 +**Status:** Draft +**Scope:** Replace the single `current_baseline.md` preset (which lists all 172 directives indiscriminately) with a layered preset system: one baseline preset containing only the directives required to operate in the codebase without entropy, plus engagement-specific presets that inherit baseline and add targeted directives for common work patterns. Also: define new op-specific directives where gaps exist, deduplicate the `.warm.md` agent prompt against the directives, and add a non-directive-context section so agents read the product/tech-stack markdown they tend to skip. + +--- + +## 1. Overview + +### 1.1 The problem + +`conductor/directives/presets/current_baseline.md` lists all 172 directives. Every agent that warms via `manual-slop_aggregate_directives` ingests all 172 (~283K chars, ~75K tokens) regardless of what it's doing. An agent auditing the codebase does not need the 23 test-writing directives; an agent fixing a regression does not need the 5 RAG-specific directives; an agent ideating UX concepts does not need the 20 tier-2-sandbox directives. The preset is the control group from the original harvest — it was never curated for engagement type. + +Two related problems: + +1. **Agents skip non-directive markdown.** `conductor/product.md`, `conductor/product-guidelines.md`, `conductor/tech-stack.md`, and the `conductor/code_styleguides/*.md` files are the original source docs the directives were lifted from. The directives are the granular reinforcement, but the full docs carry product vision and tech-stack context the directives don't fully encode. Agents skip them. There is no preset mechanism to force-read non-directive context. + +2. **The `.warm.md` agent prompt duplicates directive content.** `conductor/tier2/agents/tier2-autonomous.warm.md` (17.9KB) still contains inline bulk-markdown sections that duplicate ~9 directive subject areas (AppData, git restore/stash, timeline-immutable, run_tests_batched, failcount, tier3/tier4 delegation, etc.). The agent reads the directives AND the inline duplicates. The warm prompt should be a thin shell once the directives carry that content. + +### 1.2 The solution + +A layered preset system with three mechanisms: + +1. **Baseline preset** — only the 57 directives required to do anything in the codebase without creating entropy. Plus a non-directive-context section listing `AGENTS.md`, `conductor/product.md`, `conductor/product-guidelines.md`, `conductor/tech-stack.md` for product/tech context. + +2. **Engagement presets** — each inherits baseline and adds the targeted directives for one work pattern (auditing, fixing tests, implementing features, refactoring, scripts, meta-tooling, directives curation, documentation, media analysis, ideation). New op-specific directives are created where gaps exist. + +3. **Dedup of `.warm.md`** — the inline bulk-markdown sections that duplicate directive content get stripped; the warm prompt becomes a thin shell (domain distinction, pre-action reading list, the `warm with:` aggregate call, tier-2-sandbox targeted additions). The directives are the single source of truth. + +### 1.3 The engagement presets (mapping to user-named ops) + +| Preset file | User-named op | Inherits | Adds | +|---|---|---|---| +| `baseline.md` | Codebase knowledge + conventions | — | 57 BASELINE directives + 4 non-directive context files | +| `audit.md` | Auditing the codebase | baseline | 3 new audit directives | +| `fix_tests.md` | Fixing tests based on regressions | baseline | 23 TARGETED:testing + 2 new regression-fix directives | +| `implement_feature.md` | Implementing a new feature into ./src, ./simulation, or ./tests | baseline | 23 TARGETED:testing + 14 APP:architecture + 6 APP:imgui + 3 APP:app-controller + 5 APP:rag-memory + 1 APP:mcp (the agent loads the union; an op-specific subset can be selected at invocation if size matters) | +| `refactor.md` | Refactoring or overhauling the codebase | baseline | 23 TARGETED:testing + 2 new refactor directives | +| `new_script_tool.md` | Making new script tools | baseline | 2 new script-authoring directives | +| `meta_tooling.md` | Adjusting meta-tooling | baseline | 1 APP:mcp + 1 new meta-tooling directive | +| `directives_curation.md` | Improving, curating, or adding workflow directives or context | baseline | 3 META + 3 TARGETED:documentation + 1 new curation directive | +| `documentation.md` | Writing or updating codebase documentation | baseline | 3 TARGETED:documentation + 1 new doc-update directive | +| `media_analysis.md` | Doing analysis on content from various media sources | baseline | 2 new media-analysis directives (no TARGETED:testing — media analysis does not touch the test suite) | +| `ideation.md` | Ideating new concepts or tools or ux with the user | baseline | 7 PROCESS:planning + 1 new ideation directive | +| `tier2_autonomous.md` | Tier-2 autonomous sandbox execution | baseline | 20 TARGETED:tier2-sandbox + 23 TARGETED:testing + 8 PROCESS:delegation | + +--- + +## 2. Current State Audit (as of 2026-07-05) + +### 2.1 Already Implemented (DO NOT re-implement) + +- `conductor/directives/` — 172 directives, each `/v1.md` + `meta.md`. 283K chars total, avg 1.6K chars each. +- `conductor/directives/tags.toml` — 6-dimension classification (layer, operation, tier, subject, severity, provenance) for all 172. +- `conductor/directives/presets/current_baseline.md` — the existing single preset; lists all 172. To be replaced (not deleted — kept as the original control group per its own Notes section). +- `manual-slop_aggregate_directives` MCP tool — resolves a preset's directive list and returns all `v1.md` bodies concatenated as one text blob. Already wired into `conductor/tier2/agents/tier2-autonomous.warm.md` (the `warm with:` block added 2026-07-05). +- `scripts/tier2/setup_tier2_clone_directives.ps1` — the Option A directive-based bootstrap (added 2026-07-05). Copies `.warm.md` into the clone's active agent slot, verifies the preset path resolves. +- `conductor/tier2/agents/tier2-autonomous.warm.md` — the directive-variant agent prompt. Currently 17.9KB; still contains inline bulk-markdown sections that duplicate ~9 directive subject areas. + +### 2.2 Gaps to Fill (This Track's Scope) + +1. **No curated baseline preset.** `current_baseline.md` is a flat list of all 172; no engagement filtering. The 57 BASELINE directives need to be separated out as their own preset. +2. **No engagement presets.** No `audit.md`, `fix_tests.md`, `implement_feature.md`, etc. An agent doing test-fix work warms on the same 172 as an agent doing media analysis. +3. **No non-directive-context section in presets.** The preset format only lists directives. There is no mechanism to force-read `conductor/product.md`, `conductor/tech-stack.md`, etc. — the product/tech context agents skip. +4. **No preset inheritance.** Each preset is a standalone list. Engagement presets re-list baseline directives by hand (or skip them). The `## Inherits` section is missing. +5. **`.warm.md` duplicates directive content.** ~9 inline sections in `tier2-autonomous.warm.md` duplicate directives already in the aggregate blob. The warm prompt is larger than it needs to be. +6. **Missing op-specific directives.** The 172 existing directives do not cover some engagement-specific behavior (audit-gate-as-convention, regression-bisect-to-clean-baseline, refactor-preserves-behavior, scripts-namespace-isolated, media-source-cited-in-output, etc.). New directives are needed for the engagement presets to have something targeted to add beyond the existing tagged subsets. + +### 2.3 The 57 BASELINE directives (the cut) + +Classification of all 172 by engagement relevance. The 57 BASELINE are the rules required to do anything in the codebase without creating entropy — type promotion, edit discipline, git hard bans, research-first, error handling, state management, process anti-patterns. Excludes anything tier-specific (tier1/tier2/tier3/tier4), anything app-subsystem-specific (imgui/rag/mcp/dsl/app-controller), anything testing-specific, anything documentation-specific, anything meta-directive. + +``` +atomic_per_task_commits +git_hard_bans +timeline_is_immutable +verbose_commit_message_ban +verify_before_editing +edit_small_incremental +mandatory_research_first +ast_parse_insufficient +ast_verify_class_methods_after_edit +decorator_orphan_pitfall +preserve_line_endings +contract_change_audit +search_all_call_sites_after_signature_change +anti_entropy_state_audit_before_adding +no_diagnostic_noise +no_comments_in_body +one_space_indent +type_hints_required +no_new_src_files_without_permission +file_naming_convention +large_files_are_fine +core_value_read_first +ban_any_type +ban_dict_any +ban_dict_get_on_known_fields +ban_getattr_dispatch +ban_hasattr_dispatch +ban_optional_returns +ban_local_imports +ban_prefix_aliasing +ban_repeated_from_dict +boundary_layer_exception +metadata_boundary_type +per_aggregate_dataclass_promotion +typed_dataclass_fields +nil_sentinel_pattern +result_error_pattern +missing_data_renders_as_em_dash_not_crash +comprehensive_logging +modular_controller_pattern +strict_state_management +inherited_cruft_ask_first +deduction_loop_limit +report_instead_of_fix_ban +scope_creep_track_doc_ban +reproduction_before_fix +single_hypothesis_minimal_test +three_fix_failures_question_architecture +cheap_fix_first_investigation_phases +evidence_before_completion_claims +verify_clean_baseline_before_starting +master_branch_default +pathlib_read_write_no_newline_kwarg +sdm_dependency_tags +convention_enforcement_4_mechanisms +skill_check_before_clarifying +no_content_duplication_across_agent_docs +``` + +Full classification (all 172 → category) is in §2.4 below for the record. + +### 2.4 Full classification (all 172) + +| Category | Count | Directives | +|---|---|---| +| BASELINE | 57 | (listed in §2.3) | +| TARGETED:testing | 23 | tdd_red_green_required, test_must_fail_for_believed_reason, test_passing_immediately_proves_nothing, test_narrow_not_kitchen_sink, batch_verification_not_isolation, fragile_test_in_batch_is_failing_test, no_skip_markers_as_avoidance, ban_arbitrary_core_mocking, test_instantiation_not_mock_away, adapt_test_mocks_to_production_api_change, live_gui_poll_not_sleep, live_gui_session_scoped_no_restart, no_real_io_during_tests, enforce_no_real_toml_in_tests, test_sandbox, workspace_paths, opt_in_integration_test_via_env_var_marker, deterministic_signal_endpoint_pattern, failure_message_actionable_not_vague, three_tier_test_strategy_for_fragile_subsystems, test_classification_via_import_presence, surface_dirty_state_in_test_runner, imscope_tuple_return_per_scope_override | +| TARGETED:tier2-sandbox | 20 | ban_appdata_paths, use_batched_test_runner, no_output_filtering, prefer_targeted_tier_runs, throwaway_scripts_isolated_subdir, acknowledgment_in_first_commit, end_of_track_report_required, tier2_pre_commit_deletion_and_diff_check, tier2_pre_flight_audit_gates, tier2_post_track_ruff_mypy_audit, per_phase_metric_regression_fix, run_full_tier_after_phase_refactor, user_corrections_log_in_state_toml, surface_gaps_at_discovery_not_checkpoint, chronology_must_regenerate_after_every_track_ship, use_git_history_as_classification_source_of_truth, classifier_must_emit_per_row_evidence, quality_gate_catches_broken_classifier_before_ship, manual_compaction_only_no_auto_summarize, preserve_before_compact_archive | +| APP:architecture | 14 | defer_heavy_sdk_imports_to_subprocess, defer_not_catch_for_native_crashes, graceful_optional_dependency_degradation, submit_io_lazy_pool_recreation, log_pruner_backoff_for_locked_files, undo_redo_100_snapshot_capacity, feature_flag_delete_to_turn_off, runtime_config_flag_vs_test_env_var_gate, interceptor_activates_only_on_matching_shape, quarantine_flag_the_engine_not_shared_types, profile_first_optimize_second, state_visible_at_the_right_layer, per_conversation_scratch_dir, file_id_stable_across_rename | +| PROCESS:delegation | 8 | tier3_worker_amnesia, tier4_qa_compressed_fix, token_firewall_prevents_bloat, never_inherit_session_history_to_subagent, subagent_returns_artifact_not_transcript, agent_prompt_one_independent_domain, decompose_or_isolate_never_offload, worker_three_point_abort_check | +| PROCESS:planning | 7 | brainstorm_even_for_simple_projects, design_leads_with_recommendation, spec_self_review_four_checks, plan_steps_2_to_5_minutes_each, plans_no_placeholders_or_tbds, review_plan_critically_before_executing, surface_upstream_api_limits_honestly_in_spec | +| PROCESS:review | 7 | review_after_each_task_not_end, spec_review_before_quality_review, verify_critique_before_implementing, no_performative_agreement_in_review, clarify_unclear_review_before_partial_impl, verify_tests_before_offering_completion_options, exactly_four_completion_options | +| APP:imgui | 6 | imgui_scope_verification, imgui_scope_entered_flag_for_no_op_return, ui_delegation_for_hot_reload, modal_explicit_opened_list_for_lifecycle, view_composes_does_not_leak_into_theme_get_color, float_only_math_for_visual_transforms | +| APP:rag-memory | 5 | per_dimension_pick_dim_not_tool, cache_stable_to_volatile, rag_six_rules, knowledge_harvest_pattern, chroma_cache_path | +| PROCESS:tier1 | 5 | tier1_orchestrator_no_implementation, tier1_first_commit_6file_acknowledgment, spec_template_required_6_sections, audit_before_claiming_current_state, ban_day_estimates | +| APP:dsl-research | 4 | dsl_uses_first_class_spans_for_errors, intent_signal_postfix_not_xml, pipeline_immediate_mode_no_object, parse_failure_visible_to_conversation | +| APP:app-controller | 3 | controller_property_delegation_no_dual_state, config_state_owner, reset_session_preserves_project_path | +| META | 3 | verbatim_lift_not_rewrite, warm_md_duplicates_not_in_place, generation_script_walks_filesystem_fresh_each_run | +| PROCESS:workflow | 3 | detect_existing_isolation_before_creating, preserve_prior_versions_of_review_docs, system_reminder_redact_don_act | +| TARGETED:documentation | 3 | docs_philosophy_then_boundaries_then_logic_then_verify, neutral_language_for_doc_drift, no_conductor_yaml_for_artifacts | +| APP:mcp | 1 | meta_tooling_app_boundary_check | + +--- + +## 3. Goals + +- **G1:** Curated `baseline.md` preset containing only the 57 BASELINE directives + 4 non-directive context files (`AGENTS.md`, `conductor/product.md`, `conductor/product-guidelines.md`, `conductor/tech-stack.md`). +- **G2:** Engagement presets (12 total) that inherit baseline and add targeted directives per work pattern. +- **G3:** Preset format extension: `## Inherits` (parent preset name) + `## Non-directive context` (full markdown files to read separately from the directive aggregate). +- **G4:** `manual-slop_aggregate_directives` MCP tool extended to resolve `## Inherits` (recursively flatten parent directives into the child's directive list) and to surface non-directive-context files in the returned blob (as a separate prefixed section, so the agent reads them as full docs, not as directives). +- **G5:** 15 new op-specific directives created to fill engagement-preset gaps (audit: 3, fix_tests: 2, refactor: 2, new_script_tool: 2, meta_tooling: 1, directives_curation: 1, documentation: 1, media_analysis: 2, ideation: 1). Each follows the existing `/v1.md + meta.md` convention. +- **G6:** `conductor/tier2/agents/tier2-autonomous.warm.md` deduplicated — inline bulk-markdown sections that duplicate directives (AppData, git restore/stash, timeline-immutable, run_tests_batched, failcount, tier3/tier4 delegation, etc.) stripped. The warm prompt becomes a thin shell: domain distinction, pre-action reading list (the 11 files), the `warm with:` aggregate call pointing at the new `tier2_autonomous.md` preset, and the tier-2-sandbox targeted additions not covered by directives. +- **G7:** `current_baseline.md` retained as the original control-group preset (not deleted); the new `baseline.md` is the curated replacement. The Notes section of `current_baseline.md` is updated to mark it deprecated-but-kept. +- **G8:** `scripts/tier2/setup_tier2_clone_directives.ps1` `-PresetPath` default updated from `conductor/directives/presets/current_baseline.md` to `conductor/directives/presets/tier2_autonomous.md`. + +--- + +## 4. Functional Requirements + +### 4.1 Preset file format + +Each preset is a markdown file in `conductor/directives/presets/`. Structure: + +```markdown +# Preset: + + + +## Inherits + +# (optional — omit if this is baseline) + +## Directives to warm +Read each file below before any action. + +- : conductor/directives//v1.md +- ... + +## Non-directive context +Read each file below as full documents (NOT as directives — these carry product/tech/architecture context the directives reinforce but do not fully encode). + +- : + +## Notes + +``` + +### 4.2 Aggregate tool behavior + +`manual-slop_aggregate_directives(preset_path, max_chars)`: + +1. Parse the preset file. Extract `## Inherits` (if any), `## Directives to warm` (the list), `## Non-directive context` (the list). +2. Recursively resolve `## Inherits`: read the parent preset, append its directives + non-directive-context to this preset's (child wins on conflict — if a directive appears in both, it appears once; if a non-directive file appears in both, it appears once). +3. For each directive in the flattened list, read `conductor/directives//v1.md` and concatenate the body into the output blob (same format as today: `========\n\n========\n\n\n\n`). +4. After the directives section, append a `========\nNON-DIRECTIVE CONTEXT\n========\n\n` section listing each non-directive-context file's full path + the full file body. The agent reads these as full documents, not as directives. +5. Return the concatenated blob. `max_chars` caps total size. + +### 4.3 Engagement preset composition + +Each engagement preset: +- `## Inherits`: `baseline` +- `## Directives to warm`: the targeted subset for that engagement (e.g., `fix_tests.md` lists the 23 TARGETED:testing directives + the 2 new regression-fix directives) +- `## Non-directive context`: engagement-specific docs (e.g., `documentation.md` lists `docs/Readme.md` + `docs/AGENTS.md`; `meta_tooling.md` lists `docs/guide_meta_boundary.md`) +- `## Notes`: hypothesis + provenance + +### 4.4 New op-specific directives (15 total) + +Each follows the existing `/v1.md + meta.md` convention. The `v1.md` is a verbatim lift or a new imperative rule (per `verbatim_lift_not_rewrite`, only lift when there's a source; new rules are written from scratch with the same format). The `meta.md` records the source (or "new rule, no prior source" for the new ones). + +| Directive | Engagement preset | What it says | +|---|---|---| +| `audit_script_as_gate` | audit | Audit scripts that classify or summarize must have a `--strict` quality gate that exits 1 on regression | +| `audit_walks_filesystem_fresh` | audit | Audit scripts walk the filesystem fresh on every run — never pin to a historical snapshot | +| `baseline_capture_before_work` | audit | Before any track, capture the audit baseline numbers to a file so per-task deltas are auditable | +| `regression_bisect_to_clean_baseline` | fix_tests | When fixing a regression, bisect to the last known-green commit before proposing a fix | +| `adapt_test_not_skip_test` | fix_tests | When a test fails due to a production API change, adapt the test to the new contract — never skip it | +| `refactor_preserves_behavior` | refactor | A refactor must preserve observable behavior — tests passing before must pass after | +| `refactor_one_subsystem_per_phase` | refactor | Refactor one subsystem per phase — never touch two subsystems in the same atomic commit | +| `scripts_namespace_isolated` | new_script_tool | Scripts are namespace-isolated by directory — no `from scripts.foo import bar` across script dirs | +| `scripts_audit_pattern` | new_script_tool | New audit scripts follow the `audit_.py` naming + `--json` + `--strict` pattern of the existing 4 | +| `meta_tooling_no_app_imports` | meta_tooling | Meta-tooling scripts must not import `src/` application modules — the meta-tooling domain is distinct from the application domain | +| `directive_one_concept_per_file` | directives_curation | One directive per directory — do not combine two rules in one `v1.md` | +| `doc_update_after_track_ships` | documentation | After a track ships, update the affected `docs/guide_*.md` to reflect the new module structure | +| `media_source_cited_in_output` | media_analysis | Media analysis output must cite the source URL/timestamp for every claim — no unsourced assertions | +| `media_analysis_neutral_voice` | media_analysis | Media analysis output uses neutral voice — value judgments about the source content are the user's call, not the agent's | +| `ideation_leads_with_recommended` | ideation | Ideation sessions lead with a recommended concept + the reasoning, not 3 unranked options | + +### 4.5 `.warm.md` dedup + +Strip these inline sections from `conductor/tier2/agents/tier2-autonomous.warm.md` (their content is in the directives now): +- "Hard Bans" section (covered by `git_hard_bans`, `ban_appdata_paths`, `timeline_is_immutable`) +- "Conventions" section test-runner rules (covered by `use_batched_test_runner`, `no_output_filtering`, `prefer_targeted_tier_runs`, `master_branch_default`, `preserve_line_endings`, `throwaway_scripts_isolated_subdir`, `end_of_track_report_required`) +- "Sub-Agent Delegation" section (covered by `tier3_worker_amnesia`, `tier4_qa_compressed_fix`, `agent_prompt_one_independent_domain`, `decompose_or_isolate_never_offload`) +- "Failcount Contract" section (kept inline — no directive covers the specific thresholds; this is tier-2-sandbox operational detail that belongs in the prompt) +- "TDD Protocol" section (covered by `tdd_red_green_required`, `per_phase_metric_regression_fix`) +- "Pre-Delegation Checkpoint" section (kept inline — no directive covers the specific `git add .` safety net) +- "Per-Task Commit Protocol" section (covered by `atomic_per_task_commits`, `verbose_commit_message_ban`) +- "Limitations" section (kept inline — tier-2-specific scope, no directive) + +After dedup, the `.warm.md` is approximately: frontmatter + domain distinction + pre-action reading list (the 11 files) + the `warm with:` aggregate call (now pointing at `tier2_autonomous.md` preset) + failcount contract (inline, no directive) + pre-delegation checkpoint (inline) + limitations (inline). Estimated ~6KB down from 17.9KB. + +--- + +## 5. Non-Functional Requirements + +- **NFR1:** Preset files are markdown (no YAML, no TOML — per `no_conductor_yaml_for_artifacts`). Parseable by the aggregate tool via simple regex / line-by-line scan. +- **NFR2:** The aggregate tool's `## Inherits` resolution is bounded to 3 levels deep (preset → parent → grandparent) to prevent infinite loops. Baseline has no parent. +- **NFR3:** The aggregate tool's non-directive-context section is prefixed clearly so the agent can distinguish "directive body" from "full document context" in the returned blob. +- **NFR4:** New directives follow the 1-space-indent + type-hints + no-comments-in-body conventions (the directives themselves are markdown, so the Python conventions don't apply to the `v1.md` body, but any code examples inside the `v1.md` must follow them). +- **NFR5:** `tags.toml` is updated for the 15 new directives (6-dim classification per the existing schema). +- **NFR6:** The `current_baseline.md` file is retained; its Notes section is updated to mark it deprecated-but-kept as the original control group. + +--- + +## 6. Architecture Reference + +- **Existing preset mechanism:** `conductor/directives/presets/current_baseline.md` (the single preset; lists all 172 directives). Documented in `conductor/directives/warm_md_duplicates_not_in_place/v1.md`. +- **Aggregate tool:** `manual-slop_aggregate_directives` MCP tool (in `scripts/mcp_server.py` via the `mcp_tool_specs.py` registry). Resolves a preset's directive list, reads each `v1.md`, concatenates. Already supports `max_chars` capping. +- **Warm-up wiring:** `conductor/tier2/agents/tier2-autonomous.warm.md` §"MANDATORY: Directive Warm-up (single aggregate read)" — calls the aggregate tool with the preset path. Added 2026-07-05. +- **Directive conventions:** `conductor/directives/verbatim_lift_not_rewrite/v1.md` (harvest rule: verbatim lift, not rewrite), `conductor/directives/warm_md_duplicates_not_in_place/v1.md` (experimental variants as `.warm.md` duplicates, originals untouched). +- **Tag system:** `conductor/directives/tags.toml` — 6-dim classification (layer / operation / tier / subject / severity / provenance). The 15 new directives need entries here. +- **Bootstrap script:** `scripts/tier2/setup_tier2_clone_directives.ps1` — `-PresetPath` parameter (default `conductor/directives/presets/current_baseline.md`; to be updated to `tier2_autonomous.md`). + +--- + +## 7. Out of Scope + +- **Preset auto-discovery / fuzzy selection.** The user (or the agent's invoker) passes the preset path explicitly. No "auto-detect the engagement type from the task prompt" mechanism in this track. +- **A/B testing harness for presets.** The `current_baseline.md` Notes section mentions "alternative encodings" as a future experiment. This track creates the preset files but does not build the comparison harness. +- **Per-tier-3-worker sub-presets.** Tier-3 workers get surgical prompts from Tier-2; they do not warm on presets themselves. This track is about Tier-1/Tier-2/interactive-agent warm-ups. +- **Non-directive-context for `docs/guide_*.md`.** The 33 deep-dive guides are too large (606K total) to force-read in every warm-up. They remain on-demand. Only the 4 small conductor docs (`AGENTS.md`-equivalent, product, product-guidelines, tech-stack) are in the baseline non-directive-context. Engagement presets may add specific guides (e.g., `documentation.md` adds `docs/Readme.md`). +- **The `tier2-autonomous.md` (bulk-markdown original) prompt.** This track deduplicates `.warm.md`; the bulk-markdown original stays untouched as the rollback target per `warm_md_duplicates_not_in_place`. + +--- + +## 8. Risks + +- **R1: Aggregate tool returns too large a blob for engagement presets that union many categories.** `implement_feature.md` inherits baseline (57) + TARGETED:testing (23) + APP:architecture (14) + APP:imgui (6) + APP:app-controller (3) + APP:rag-memory (5) + APP:mcp (1) = 109 directives + 4 non-directive files. At avg 1.6K chars/directive, that's ~175K chars (~44K tokens) for directives alone, plus the non-directive context. Mitigation: the agent picks the engagement preset at invocation; if size matters, an op-specific subset can be passed. The `max_chars` cap exists. +- **R2: New directives are written from scratch (no prior source to verbatim-lift).** The `verbatim_lift_not_rewrite` rule says "verbatim lift of source text, not rewrite." The 15 new directives have no prior source — they are new rules. The `meta.md` records "new rule, no prior source" per the existing convention (the original harvest also created new directives when no source existed). +- **R3: Dedup of `.warm.md` removes content the agent actually needs inline.** The failcount contract, pre-delegation checkpoint, and limitations sections are kept inline because no directive covers the specific tier-2 operational detail. The risk is removing something that turns out to be load-bearing. Mitigation: the dedup is conservative — only sections whose content is fully covered by a directive are stripped. + +--- + +## 9. Verification + +- **V1:** `manual-slop_aggregate_directives(preset_path="conductor/directives/presets/baseline.md")` returns a blob containing exactly the 57 baseline directive bodies + the 4 non-directive context files. +- **V2:** `manual-slop_aggregate_directives(preset_path="conductor/directives/presets/fix_tests.md")` returns the 57 baseline + 23 TARGETED:testing + 2 new regression-fix directives + the 4 non-directive context files (inherited from baseline). +- **V3:** Each of the 15 new directives has a `v1.md` + `meta.md` + a `tags.toml` entry. +- **V4:** `conductor/tier2/agents/tier2-autonomous.warm.md` is reduced from ~17.9KB to ~6KB; the stripped sections' content is present in the directive aggregate when warming with `tier2_autonomous.md` preset. +- **V5:** `scripts/tier2/setup_tier2_clone_directives.ps1 -PresetPath` defaults to `conductor/directives/presets/tier2_autonomous.md`; the script runs clean and the clone's agent slot has the aggregate call. + +--- + +## 10. Coordination with Pending Tracks + +No blocking tracks. The `directive_hotswap_harness_20260627` track (the original harvest) is complete; its artifacts (`current_baseline.md`, `tags.toml`, the 172 directives) are the inputs to this track. The `tier2_leak_prevention_20260620` track is merged; its spec is referenced by the `.warm.md` pre-action reading list but is not a structural dependency. + +--- + +## 11. See Also + +- `conductor/directives/presets/current_baseline.md` — the original control-group preset (retained) +- `conductor/directives/tags.toml` — the 6-dim classification +- `conductor/directives/verbatim_lift_not_rewrite/v1.md` — the harvest rule +- `conductor/directives/warm_md_duplicates_not_in_place/v1.md` — the `.warm.md` duplicate rule +- `conductor/tier2/agents/tier2-autonomous.warm.md` — the directive-variant agent prompt (to be deduplicated) +- `scripts/tier2/setup_tier2_clone_directives.ps1` — the directive-based bootstrap +- `docs/superpowers/specs/2026-07-05-directive-preset-system-design.md` — this spec \ No newline at end of file diff --git a/docs/superpowers/plans/2026-07-05-directive-preset-system.md b/docs/superpowers/plans/2026-07-05-directive-preset-system.md new file mode 100644 index 00000000..2e9bea24 --- /dev/null +++ b/docs/superpowers/plans/2026-07-05-directive-preset-system.md @@ -0,0 +1,2169 @@ +# Directive Preset System Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Replace the single flat `current_baseline.md` preset with a layered preset system: a curated `baseline.md` (57 directives + 4 non-directive context files), 12 engagement presets that inherit baseline, 15 new op-specific directives, a deduplicated `.warm.md`, and an extended aggregate tool that resolves `## Inherits` and surfaces `## Non-directive context`. + +**Architecture:** The aggregate tool (`scripts/aggregate_directives.py`) is extended to parse two new preset sections (`## Inherits` and `## Non-directive context`), recursively flatten the parent's directives + non-directive files into the child's list (dedup on path), read each directive's `v1.md` and each non-directive file's full body, and return one concatenated blob. Preset files are markdown (no YAML/TOML). Engagement presets list only their targeted additions; baseline provides the foundation. + +**Tech Stack:** Python 3.11+, 1-space indent, type hints, `@dataclass(frozen=True, slots=True)` for any new data types, `re` for preset parsing, `pathlib.Path` for file I/O, `pytest` for tests. + +**Spec:** `docs/superpowers/specs/2026-07-05-directive-preset-system-design.md` + +--- + +## File Structure + +**Files to create:** +- `conductor/directives/presets/baseline.md` — curated 57 BASELINE directives + 4 non-directive context files +- `conductor/directives/presets/audit.md` — inherits baseline, adds 3 audit directives +- `conductor/directives/presets/fix_tests.md` — inherits baseline, adds 23 testing + 2 regression-fix +- `conductor/directives/presets/implement_feature.md` — inherits baseline, adds testing + APP subsets +- `conductor/directives/presets/refactor.md` — inherits baseline, adds testing + 2 refactor +- `conductor/directives/presets/new_script_tool.md` — inherits baseline, adds 2 script directives +- `conductor/directives/presets/meta_tooling.md` — inherits baseline, adds 1 APP:mcp + 1 meta-tooling +- `conductor/directives/presets/directives_curation.md` — inherits baseline, adds META + documentation + 1 curation +- `conductor/directives/presets/documentation.md` — inherits baseline, adds 3 documentation + 1 doc-update +- `conductor/directives/presets/media_analysis.md` — inherits baseline, adds 2 media-analysis +- `conductor/directives/presets/ideation.md` — inherits baseline, adds 7 planning + 1 ideation +- `conductor/directives/presets/tier2_autonomous.md` — inherits baseline, adds tier2-sandbox + testing + delegation +- 15 new directive directories under `conductor/directives//` each with `v1.md` + `meta.md` +- `tests/test_aggregate_directives_presets.py` — tests for Inherits + Non-directive context + +**Files to modify:** +- `scripts/aggregate_directives.py` — add `## Inherits` resolution + `## Non-directive context` section parsing + output +- `conductor/directives/tags.toml` — add 15 new directive entries +- `conductor/directives/presets/current_baseline.md` — mark deprecated in Notes +- `conductor/tier2/agents/tier2-autonomous.warm.md` — strip inline sections covered by directives, update preset path +- `scripts/tier2/setup_tier2_clone_directives.ps1` — change `-PresetPath` default to `tier2_autonomous.md` + +--- + +## Phase 1: Extend aggregate_directives.py (Inherits + Non-directive context) + +Focus: Add `## Inherits` recursive resolution and `## Non-directive context` file reading to the aggregate tool. TDD — write failing tests first, implement to pass. + +### Task 1.1: Write failing tests for Inherits resolution + +**Files:** +- Create: `tests/test_aggregate_directives_presets.py` +- Create: `tests/artifacts/_pytest_tmp/preset_child_test/` (temp preset fixtures) + +- [ ] **Step 1: Write the failing test for Inherits** + +Create `tests/test_aggregate_directives_presets.py`: + +```python +"""Tests for aggregate_directives preset inheritance and non-directive context.""" +from __future__ import annotations + +import sys +from pathlib import Path + +import pytest + +# Add scripts/ to sys.path so we can import aggregate_directives +SCRIPTS_DIR = Path(__file__).resolve().parent.parent / "scripts" +if str(SCRIPTS_DIR) not in sys.path: + sys.path.insert(0, str(SCRIPTS_DIR)) + +from aggregate_directives import parse_preset_sections, resolve_inheritance, aggregate_directives + + +class TestParsePresetSections: + """Test the new section-based parser that extracts Inherits, Directives, Non-directive context.""" + + def test_parse_returns_three_sections(self, tmp_path: Path): + preset = tmp_path / "test_preset.md" + preset.write_text("""# Preset: test + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- foo: conductor/directives/foo/v1.md +- bar: conductor/directives/bar/v1.md + +## Non-directive context +Read each file below as full documents. + +- project rules: AGENTS.md + +## Notes +test +""", encoding="utf-8") + sections = parse_preset_sections(preset) + assert sections.inherits == "baseline" + assert len(sections.directives) == 2 + assert sections.directives[0] == ("foo", Path("conductor/directives/foo/v1.md")) + assert sections.directives[1] == ("bar", Path("conductor/directives/bar/v1.md")) + assert len(sections.non_directive_context) == 1 + assert sections.non_directive_context[0] == ("project rules", Path("AGENTS.md")) + + def test_parse_preset_without_inherits(self, tmp_path: Path): + preset = tmp_path / "test_preset.md" + preset.write_text("""# Preset: test + +## Directives to warm +- foo: conductor/directives/foo/v1.md + +## Non-directive context +- doc: AGENTS.md +""", encoding="utf-8") + sections = parse_preset_sections(preset) + assert sections.inherits == "" + assert len(sections.directives) == 1 + assert len(sections.non_directive_context) == 1 + + def test_parse_preset_without_non_directive_context(self, tmp_path: Path): + preset = tmp_path / "test_preset.md" + preset.write_text("""# Preset: test + +## Directives to warm +- foo: conductor/directives/foo/v1.md +""", encoding="utf-8") + sections = parse_preset_sections(preset) + assert sections.inherits == "" + assert len(sections.directives) == 1 + assert sections.non_directive_context == [] + + +class TestResolveInheritance: + """Test that resolve_inheritance merges parent directives into child, dedup on name.""" + + def test_child_directives_plus_parent_directives(self, tmp_path: Path): + parent = tmp_path / "parent.md" + parent.write_text("""# Preset: parent + +## Directives to warm +- alpha: conductor/directives/alpha/v1.md +- beta: conductor/directives/beta/v1.md +""", encoding="utf-8") + child = tmp_path / "child.md" + child.write_text("""# Preset: child + +## Inherits +parent + +## Directives to warm +- beta: conductor/directives/beta/v1.md +- gamma: conductor/directives/gamma/v1.md +""", encoding="utf-8") + merged = resolve_inheritance(child, root=tmp_path) + names = [n for n, _ in merged.directives] + assert names == ["beta", "gamma", "alpha"] + assert len(merged.non_directive_context) == 0 + + def test_child_wins_on_directive_conflict(self, tmp_path: Path): + parent = tmp_path / "parent.md" + parent.write_text("""# Preset: parent + +## Directives to warm +- shared: conductor/directives/shared_parent/v1.md +""", encoding="utf-8") + child = tmp_path / "child.md" + child.write_text("""# Preset: child + +## Inherits +parent + +## Directives to warm +- shared: conductor/directives/shared_child/v1.md +""", encoding="utf-8") + merged = resolve_inheritance(child, root=tmp_path) + paths = [p for _, p in merged.directives] + assert Path("conductor/directives/shared_child/v1.md") in paths + assert Path("conductor/directives/shared_parent/v1.md") not in paths + + def test_non_directive_context_merges_dedup_on_path(self, tmp_path: Path): + parent = tmp_path / "parent.md" + parent.write_text("""# Preset: parent + +## Directives to warm +- alpha: conductor/directives/alpha/v1.md + +## Non-directive context +- rules: AGENTS.md +- product: conductor/product.md +""", encoding="utf-8") + child = tmp_path / "child.md" + child.write_text("""# Preset: child + +## Inherits +parent + +## Directives to warm +- beta: conductor/directives/beta/v1.md + +## Non-directive context +- rules: AGENTS.md +- tech: conductor/tech-stack.md +""", encoding="utf-8") + merged = resolve_inheritance(child, root=tmp_path) + paths = [p for _, p in merged.non_directive_context] + assert Path("AGENTS.md") in paths + assert Path("conductor/product.md") in paths + assert Path("conductor/tech-stack.md") in paths + assert paths.count(Path("AGENTS.md")) == 1 + + def test_three_level_inheritance(self, tmp_path: Path): + grandparent = tmp_path / "grandparent.md" + grandparent.write_text("""# Preset: grandparent + +## Directives to warm +- alpha: conductor/directives/alpha/v1.md +""", encoding="utf-8") + parent = tmp_path / "parent.md" + parent.write_text("""# Preset: parent + +## Inherits +grandparent + +## Directives to warm +- beta: conductor/directives/beta/v1.md +""", encoding="utf-8") + child = tmp_path / "child.md" + child.write_text("""# Preset: child + +## Inherits +parent + +## Directives to warm +- gamma: conductor/directives/gamma/v1.md +""", encoding="utf-8") + merged = resolve_inheritance(child, root=tmp_path) + names = [n for n, _ in merged.directives] + assert "alpha" in names + assert "beta" in names + assert "gamma" in names + + def test_inheritance_loop_detected(self, tmp_path: Path): + a = tmp_path / "a.md" + a.write_text("""# Preset: a + +## Inherits +b + +## Directives to warm +- alpha: conductor/directives/alpha/v1.md +""", encoding="utf-8") + b = tmp_path / "b.md" + b.write_text("""# Preset: b + +## Inherits +a + +## Directives to warm +- beta: conductor/directives/beta/v1.md +""", encoding="utf-8") + with pytest.raises(ValueError, match="inheritance loop"): + resolve_inheritance(a, root=tmp_path) +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `uv run pytest tests/test_aggregate_directives_presets.py -v` +Expected: FAIL with `ImportError: cannot import name 'parse_preset_sections' from 'aggregate_directives'` + +--- + +### Task 1.2: Implement parse_preset_sections + resolve_inheritance + aggregate with non-directive context + +**Files:** +- Modify: `scripts/aggregate_directives.py` (the full file — rewrite with new functions) + +- [ ] **Step 1: Implement the new parsing + inheritance + non-directive context** + +Replace the full content of `scripts/aggregate_directives.py` with: + +```python +#!/usr/bin/env python3 +"""Aggregate directive bodies from a preset markdown file. + +Supports three preset sections: + ## Inherits — name of parent preset (resolved recursively, 3-level max) + ## Directives to warm — list of : + ## Non-directive context — list of : + +Child directives + non-directive files override parent on name/path conflict. +""" +from __future__ import annotations + +import argparse +import re +import sys +from dataclasses import dataclass, field +from pathlib import Path + +if hasattr(sys.stdout, "reconfigure"): + try: + sys.stdout.reconfigure(encoding="utf-8") + except Exception: + pass +if hasattr(sys.stderr, "reconfigure"): + try: + sys.stderr.reconfigure(encoding="utf-8") + except Exception: + pass + +REPO_ROOT = Path(__file__).resolve().parent.parent +ENTRY_RE = re.compile(r"^\s*-\s+(?P[^\s:]+)\s*:\s*(?P\S+)\s*$") +EXPECTED_PATTERN_TEMPLATE = r"^conductor/directives/{name}/v\d+\.md$" +MAX_INHERIT_DEPTH = 3 + + +@dataclass(frozen=True, slots=True) +class PresetSections: + inherits: str + directives: list[tuple[str, Path]] + non_directive_context: list[tuple[str, Path]] + + +def parse_preset_sections(preset_path: Path) -> PresetSections: + """Parse a preset markdown file into Inherits, Directives, Non-directive context.""" + if not preset_path.exists(): + raise FileNotFoundError("preset file not found: " + str(preset_path)) + text = preset_path.read_text(encoding="utf-8") + inherits: str = "" + directives: list[tuple[str, Path]] = [] + non_directive: list[tuple[str, Path]] = [] + current_section: str = "" + for line in text.splitlines(): + if line.startswith("## Inherits"): + current_section = "inherits" + continue + if line.startswith("## Directives to warm"): + current_section = "directives" + continue + if line.startswith("## Non-directive context"): + current_section = "non_directive" + continue + if line.startswith("## ") or line.startswith("# "): + current_section = "" + continue + if current_section == "inherits" and line.strip(): + inherits = line.strip() + elif current_section in ("directives", "non_directive"): + m = ENTRY_RE.match(line) + if m: + name = m.group("name") + rel_path = Path(m.group("path")) + if current_section == "directives": + directives.append((name, rel_path)) + else: + non_directive.append((name, rel_path)) + return PresetSections(inherits=inherits, directives=directives, non_directive_context=non_directive) + + +def resolve_inheritance( + preset_path: Path, + root: Path | None = None, + _visited: frozenset[str] | None = None, + _depth: int = 0, +) -> PresetSections: + """Resolve a preset, recursively flattening parent directives + non-directive files.""" + if root is None: + root = REPO_ROOT + p = preset_path if preset_path.is_absolute() else (root / preset_path).resolve() + if _visited is None: + _visited = frozenset() + key = str(p) + if key in _visited: + raise ValueError("inheritance loop detected at " + key) + if _depth > MAX_INHERIT_DEPTH: + raise ValueError("inheritance depth exceeds " + str(MAX_INHERIT_DEPTH) + " at " + key) + sections = parse_preset_sections(p) + if not sections.inherits: + return sections + parent_name = sections.inherits + parent_path = (root / "conductor" / "directives" / "presets" / (parent_name + ".md")).resolve() + if not parent_path.exists(): + raise FileNotFoundError("parent preset not found: " + str(parent_path)) + parent = resolve_inheritance(parent_path, root=root, _visited=_visited | {key}, _depth=_depth + 1) + merged_directives: list[tuple[str, Path]] = [] + child_names: set[str] = {n for n, _ in sections.directives} + for name, path in parent.directives: + if name not in child_names: + merged_directives.append((name, path)) + for name, path in sections.directives: + merged_directives.append((name, path)) + merged_non_directive: list[tuple[str, Path]] = [] + child_paths: set[Path] = {p for _, p in sections.non_directive_context} + for desc, path in parent.non_directive_context: + if path not in child_paths: + merged_non_directive.append((desc, path)) + for desc, path in sections.non_directive_context: + merged_non_directive.append((desc, path)) + return PresetSections(inherits="", directives=merged_directives, non_directive_context=merged_non_directive) + + +def aggregate_directives( + preset_path: str | Path, + *, + max_chars: int = 0, + project_root: str | Path | None = None, +) -> str: + """ + Read preset at preset_path, resolve inheritance, read each directive's v1.md + and each non-directive-context file, concatenate into a single text blob. + + Preset format: + ## Inherits + ## Directives to warm (list of : ) + ## Non-directive context (list of : ) + + Directives appear first (same ===== banner format as before), then a + NON-DIRECTIVE CONTEXT section appends each non-directive file's full body. + """ + root = Path(project_root).resolve() if project_root is not None else REPO_ROOT + p = Path(preset_path) + if not p.is_absolute(): + p = (root / p).resolve() + if not p.exists(): + raise FileNotFoundError("preset file not found: " + str(p)) + sections = resolve_inheritance(p, root=root) + if not sections.directives and not sections.non_directive_context: + raise ValueError("no directive or non-directive entries found in " + str(p)) + missing: list[tuple[str, Path]] = [] + directive_bodies: list[tuple[str, str]] = [] + for name, rel in sections.directives: + abs_path = (root / rel).resolve() + if not abs_path.exists(): + missing.append((name, abs_path)) + continue + try: + rel_str = abs_path.relative_to(root).as_posix() + except ValueError: + rel_str = str(abs_path) + pattern = EXPECTED_PATTERN_TEMPLATE.format(name=re.escape(name)) + if not re.match(pattern, rel_str): + print("WARNING: " + name + ": path " + str(abs_path) + " does not match pattern conductor/directives/" + name + "/vN.md; including anyway", file=sys.stderr) + try: + body = abs_path.read_text(encoding="utf-8") + except UnicodeDecodeError as e: + raise ValueError(name + ": UTF-8 decode error in " + str(abs_path) + ": " + str(e)) from e + directive_bodies.append((name, body)) + if missing: + names = ", ".join(n for n, _ in missing) + raise FileNotFoundError("missing v1.md files for directives: " + names) + non_directive_bodies: list[tuple[str, str]] = [] + for desc, rel in sections.non_directive_context: + abs_path = (root / rel).resolve() + if not abs_path.exists(): + print("WARNING: non-directive context file not found: " + str(abs_path), file=sys.stderr) + continue + try: + body = abs_path.read_text(encoding="utf-8") + except UnicodeDecodeError as e: + raise ValueError(desc + ": UTF-8 decode error in " + str(abs_path) + ": " + str(e)) from e + non_directive_bodies.append((desc, body)) + out_lines: list[str] = [] + for name, body in directive_bodies: + out_lines.append("=" * 40) + out_lines.append(name) + out_lines.append("=" * 40) + out_lines.append("") + out_lines.append(body.rstrip("\n")) + out_lines.append("") + out_lines.append("") + if non_directive_bodies: + out_lines.append("=" * 40) + out_lines.append("NON-DIRECTIVE CONTEXT") + out_lines.append("=" * 40) + out_lines.append("") + for desc, body in non_directive_bodies: + out_lines.append("--- " + desc + " ---") + out_lines.append("") + out_lines.append(body.rstrip("\n")) + out_lines.append("") + out_lines.append("") + rendered = "\n".join(out_lines) + if max_chars > 0 and len(rendered) > max_chars: + truncated = rendered[:max_chars] + suffix = "\n\n[truncated: showing " + str(max_chars) + " of " + str(len(rendered)) + " chars; omit max_chars for full text]" + rendered = truncated + suffix + return rendered + + +def aggregate(preset_path: Path, output_path: Path | None) -> int: + try: + rendered = aggregate_directives(preset_path) + except (FileNotFoundError, ValueError) as e: + print("ERROR: " + str(e), file=sys.stderr) + return 1 + if output_path: + output_path.write_text(rendered, encoding="utf-8") + print("Wrote " + str(rendered.count("=" * 40) // 2) + " sections to " + str(output_path), file=sys.stderr) + else: + sys.stdout.write(rendered) + if not rendered.endswith("\n"): + sys.stdout.write("\n") + return 0 + + +def main() -> int: + parser = argparse.ArgumentParser(description="Aggregate directive bodies from a preset markdown file.") + parser.add_argument("preset", type=Path, help="Path to the preset markdown file") + parser.add_argument("-o", "--output", type=Path, default=None, help="Write output to file instead of stdout") + args = parser.parse_args() + if not args.preset.exists(): + print("ERROR: preset file not found: " + str(args.preset), file=sys.stderr) + return 1 + output = args.output.resolve() if args.output else None + return aggregate(args.preset.resolve(), output) + + +if __name__ == "__main__": + sys.exit(main()) +``` + +- [ ] **Step 2: Run tests to verify they pass** + +Run: `uv run pytest tests/test_aggregate_directives_presets.py -v` +Expected: PASS (all 7 tests) + +- [ ] **Step 3: Run existing aggregate to verify backward compat (no Inherits in current_baseline.md)** + +Run: `uv run python scripts/aggregate_directives.py conductor/directives/presets/current_baseline.md -o tests/artifacts/_pytest_tmp/agg_compat_test.txt` +Expected: exit 0, output file contains 172 directive sections, no NON-DIRECTIVE CONTEXT section (current_baseline.md has no `## Non-directive context` section) + +- [ ] **Step 4: Commit** + +```bash +git add scripts/aggregate_directives.py tests/test_aggregate_directives_presets.py +git commit -m "feat(aggregate): add Inherits resolution + Non-directive context to preset parser" +``` + +--- + +### Task 1.3: Write integration test for non-directive context in the aggregate output + +**Files:** +- Modify: `tests/test_aggregate_directives_presets.py` + +- [ ] **Step 1: Add integration test for non-directive context in aggregate_directives output** + +Append to `tests/test_aggregate_directives_presets.py`: + +```python +class TestAggregateWithNonDirectiveContext: + """Integration: aggregate_directives returns non-directive files in a separate section.""" + + def test_aggregate_includes_non_directive_section(self, tmp_path: Path): + directives_dir = tmp_path / "conductor" / "directives" / "alpha" + directives_dir.mkdir(parents=True) + (directives_dir / "v1.md").write_text("# Alpha rule\n\nDo the thing.\n", encoding="utf-8") + context_file = tmp_path / "AGENTS.md" + context_file.write_text("# Project Rules\n\nRule 1.\n", encoding="utf-8") + preset = tmp_path / "test_preset.md" + preset.write_text("""# Preset: test + +## Directives to warm +- alpha: conductor/directives/alpha/v1.md + +## Non-directive context +- project rules: AGENTS.md +""", encoding="utf-8") + rendered = aggregate_directives(str(preset), project_root=str(tmp_path)) + assert "alpha" in rendered + assert "Alpha rule" in rendered + assert "NON-DIRECTIVE CONTEXT" in rendered + assert "Project Rules" in rendered + assert rendered.index("alpha") < rendered.index("NON-DIRECTIVE CONTEXT") + + def test_aggregate_non_directive_section_after_directives(self, tmp_path: Path): + directives_dir = tmp_path / "conductor" / "directives" / "beta" + directives_dir.mkdir(parents=True) + (directives_dir / "v1.md").write_text("# Beta rule\n\nDo beta.\n", encoding="utf-8") + context_file = tmp_path / "conductor" / "product.md" + context_file.parent.mkdir(parents=True, exist_ok=True) + context_file.write_text("# Product\n\nVision.\n", encoding="utf-8") + preset = tmp_path / "test_preset.md" + preset.write_text("""# Preset: test + +## Directives to warm +- beta: conductor/directives/beta/v1.md + +## Non-directive context +- product: conductor/product.md +""", encoding="utf-8") + rendered = aggregate_directives(str(preset), project_root=str(tmp_path)) + assert "Beta rule" in rendered + assert "Product" in rendered + assert rendered.index("Beta rule") < rendered.index("NON-DIRECTIVE CONTEXT") + assert "product" in rendered.lower() or "Product" in rendered +``` + +- [ ] **Step 2: Run tests to verify they pass** + +Run: `uv run pytest tests/test_aggregate_directives_presets.py -v` +Expected: PASS (all 9 tests) + +- [ ] **Step 3: Commit** + +```bash +git add tests/test_aggregate_directives_presets.py +git commit -m "test(aggregate): add integration tests for non-directive context in aggregate output" +``` + +--- + +## Phase 2: Create baseline preset + verify + +Focus: Write `baseline.md` with the 57 BASELINE directives + 4 non-directive context files. Verify the aggregate tool resolves it correctly against the real repo. + +### Task 2.1: Create baseline.md + +**Files:** +- Create: `conductor/directives/presets/baseline.md` + +- [ ] **Step 1: Write baseline.md** + +Create `conductor/directives/presets/baseline.md`: + +```markdown +# Preset: baseline + +The curated baseline — directives required to do anything in the codebase without creating entropy. Type promotion, edit discipline, git hard bans, research-first, error handling, state management, process anti-patterns. Excludes anything tier-specific, app-subsystem-specific, testing-specific, documentation-specific, or meta-directive. Engagement presets inherit this and add targeted subsets. + +## Directives to warm +Read each file below before any action. + +- atomic_per_task_commits: conductor/directives/atomic_per_task_commits/v1.md +- git_hard_bans: conductor/directives/git_hard_bans/v1.md +- timeline_is_immutable: conductor/directives/timeline_is_immutable/v1.md +- verbose_commit_message_ban: conductor/directives/verbose_commit_message_ban/v1.md +- verify_before_editing: conductor/directives/verify_before_editing/v1.md +- edit_small_incremental: conductor/directives/edit_small_incremental/v1.md +- mandatory_research_first: conductor/directives/mandatory_research_first/v1.md +- ast_parse_insufficient: conductor/directives/ast_parse_insufficient/v1.md +- ast_verify_class_methods_after_edit: conductor/directives/ast_verify_class_methods_after_edit/v1.md +- decorator_orphan_pitfall: conductor/directives/decorator_orphan_pitfall/v1.md +- preserve_line_endings: conductor/directives/preserve_line_endings/v1.md +- contract_change_audit: conductor/directives/contract_change_audit/v1.md +- search_all_call_sites_after_signature_change: conductor/directives/search_all_call_sites_after_signature_change/v1.md +- anti_entropy_state_audit_before_adding: conductor/directives/anti_entropy_state_audit_before_adding/v1.md +- no_diagnostic_noise: conductor/directives/no_diagnostic_noise/v1.md +- no_comments_in_body: conductor/directives/no_comments_in_body/v1.md +- one_space_indent: conductor/directives/one_space_indent/v1.md +- type_hints_required: conductor/directives/type_hints_required/v1.md +- no_new_src_files_without_permission: conductor/directives/no_new_src_files_without_permission/v1.md +- file_naming_convention: conductor/directives/file_naming_convention/v1.md +- large_files_are_fine: conductor/directives/large_files_are_fine/v1.md +- core_value_read_first: conductor/directives/core_value_read_first/v1.md +- ban_any_type: conductor/directives/ban_any_type/v1.md +- ban_dict_any: conductor/directives/ban_dict_any/v1.md +- ban_dict_get_on_known_fields: conductor/directives/ban_dict_get_on_known_fields/v1.md +- ban_getattr_dispatch: conductor/directives/ban_getattr_dispatch/v1.md +- ban_hasattr_dispatch: conductor/directives/ban_hasattr_dispatch/v1.md +- ban_optional_returns: conductor/directives/ban_optional_returns/v1.md +- ban_local_imports: conductor/directives/ban_local_imports/v1.md +- ban_prefix_aliasing: conductor/directives/ban_prefix_aliasing/v1.md +- ban_repeated_from_dict: conductor/directives/ban_repeated_from_dict/v1.md +- boundary_layer_exception: conductor/directives/boundary_layer_exception/v1.md +- metadata_boundary_type: conductor/directives/metadata_boundary_type/v1.md +- per_aggregate_dataclass_promotion: conductor/directives/per_aggregate_dataclass_promotion/v1.md +- typed_dataclass_fields: conductor/directives/typed_dataclass_fields/v1.md +- nil_sentinel_pattern: conductor/directives/nil_sentinel_pattern/v1.md +- result_error_pattern: conductor/directives/result_error_pattern/v1.md +- missing_data_renders_as_em_dash_not_crash: conductor/directives/missing_data_renders_as_em_dash_not_crash/v1.md +- comprehensive_logging: conductor/directives/comprehensive_logging/v1.md +- modular_controller_pattern: conductor/directives/modular_controller_pattern/v1.md +- strict_state_management: conductor/directives/strict_state_management/v1.md +- inherited_cruft_ask_first: conductor/directives/inherited_cruft_ask_first/v1.md +- deduction_loop_limit: conductor/directives/deduction_loop_limit/v1.md +- report_instead_of_fix_ban: conductor/directives/report_instead_of_fix_ban/v1.md +- scope_creep_track_doc_ban: conductor/directives/scope_creep_track_doc_ban/v1.md +- reproduction_before_fix: conductor/directives/reproduction_before_fix/v1.md +- single_hypothesis_minimal_test: conductor/directives/single_hypothesis_minimal_test/v1.md +- three_fix_failures_question_architecture: conductor/directives/three_fix_failures_question_architecture/v1.md +- cheap_fix_first_investigation_phases: conductor/directives/cheap_fix_first_investigation_phases/v1.md +- evidence_before_completion_claims: conductor/directives/evidence_before_completion_claims/v1.md +- verify_clean_baseline_before_starting: conductor/directives/verify_clean_baseline_before_starting/v1.md +- master_branch_default: conductor/directives/master_branch_default/v1.md +- pathlib_read_write_no_newline_kwarg: conductor/directives/pathlib_read_write_no_newline_kwarg/v1.md +- sdm_dependency_tags: conductor/directives/sdm_dependency_tags/v1.md +- convention_enforcement_4_mechanisms: conductor/directives/convention_enforcement_4_mechanisms/v1.md +- skill_check_before_clarifying: conductor/directives/skill_check_before_clarifying/v1.md +- no_content_duplication_across_agent_docs: conductor/directives/no_content_duplication_across_agent_docs/v1.md + +## Non-directive context +Read each file below as full documents (NOT as directives — these carry product/tech/architecture context the directives reinforce but do not fully encode). + +- project rules: AGENTS.md +- product vision: conductor/product.md +- product guidelines: conductor/product-guidelines.md +- tech stack: conductor/tech-stack.md + +## Notes +The 57 BASELINE directives — rules required to do anything in the codebase without creating entropy. Classification based on the 2026-07-05 audit of all 172 directives (see docs/superpowers/specs/2026-07-05-directive-preset-system-design.md §2.4). The 4 non-directive context files are the product/tech docs agents tend to skip. Replaces current_baseline.md as the curated default; current_baseline.md is retained as the original control group. +``` + +- [ ] **Step 2: Verify the aggregate resolves baseline.md correctly** + +Run: `uv run python scripts/aggregate_directives.py conductor/directives/presets/baseline.md -o tests/artifacts/_pytest_tmp/agg_baseline_test.txt` +Expected: exit 0, output file contains 57 directive sections + 1 NON-DIRECTIVE CONTEXT section with AGENTS.md, product.md, product-guidelines.md, tech-stack.md bodies. + +- [ ] **Step 3: Verify the directive count is exactly 57** + +Run: `uv run python -c "from pathlib import Path; import sys; sys.path.insert(0, 'scripts'); from aggregate_directives import resolve_inheritance; s = resolve_inheritance(Path('conductor/directives/presets/baseline.md')); print(len(s.directives)); print(len(s.non_directive_context))"` +Expected: `57` then `4`. + +- [ ] **Step 4: Commit** + +```bash +git add conductor/directives/presets/baseline.md +git commit -m "feat(directives): add curated baseline.md preset (57 BASELINE + 4 non-directive context)" +``` + +--- + +## Phase 3: Create 15 new op-specific directives + +Focus: Create the 15 new directives that fill engagement-preset gaps. Each follows the existing `/v1.md + meta.md` convention. These are new rules (no prior source to verbatim-lift); the `meta.md` records "new rule, no prior source." + +### Task 3.1: Create the 3 audit directives + +**Files:** +- Create: `conductor/directives/audit_script_as_gate/v1.md` + `meta.md` +- Create: `conductor/directives/audit_walks_filesystem_fresh/v1.md` + `meta.md` +- Create: `conductor/directives/baseline_capture_before_work/v1.md` + `meta.md` + +- [ ] **Step 1: Write audit_script_as_gate** + +Create `conductor/directives/audit_script_as_gate/v1.md`: + +```markdown +# Audit scripts that classify or summarize must have a `--strict` quality gate that exits 1 on regression + +## What it says + +Every audit script in `scripts/audit_*.py` that produces classified output (weak types, exception handling, tier2 leaks, etc.) MUST implement a `--strict` mode that exits non-zero when the audit finds violations. The default mode (no `--strict`) is informational — it prints a human-readable report and exits 0. The `--strict` mode is the CI gate. + +## Why + +An audit without a gate is a suggestion. An audit with a `--strict` gate is a convention enforced before merge. The project's 4 existing audit scripts (`audit_weak_types.py`, `audit_exception_handling.py`, `audit_main_thread_imports.py`, `audit_no_models_config_io.py`) all follow this pattern. New audit scripts MUST follow it too. + +## The pattern + +```python +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--strict", action="store_true", help="Exit 1 on any violation") + parser.add_argument("--json", action="store_true", help="Machine-readable output") + args = parser.parse_args() + violations = run_audit() + if args.json: + print(json.dumps(violations)) + else: + print_human_report(violations) + if args.strict and violations: + return 1 + return 0 +``` + +## See also + +- `conductor/directives/convention_enforcement_4_mechanisms` — the 4-mechanism enforcement model (styleguide + checklist + audit script + CI gate) +- `conductor/directives/quality_gate_catches_broken_classifier_before_ship` — the quality gate for classifier scripts +``` + +Create `conductor/directives/audit_script_as_gate/meta.md`: + +```markdown +# audit_script_as_gate + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the pattern already followed by the 4 existing audit scripts (`audit_weak_types.py`, `audit_exception_handling.py`, `audit_main_thread_imports.py`, `audit_no_models_config_io.py`) so new audit scripts follow the same `--strict` gate convention. +**Source:** new rule (pattern inferred from existing `scripts/audit_*.py`) + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 2: Write audit_walks_filesystem_fresh** + +Create `conductor/directives/audit_walks_filesystem_fresh/v1.md`: + +```markdown +# Audit scripts walk the filesystem fresh on every run — never pin to a historical snapshot + +## What it says + +Audit scripts MUST walk the filesystem fresh on every invocation. They MUST NOT cache the file list, pin to a historical snapshot, or read from a stale index. Each run is a fresh walk of `src/`, `tests/`, `scripts/`, or whatever directory the audit targets. + +## Why + +A stale audit misses regressions. If the audit reads from a cached file list (e.g., a JSON index written last session), it will not see files added, renamed, or deleted since. The audit's value is "what does the codebase look like RIGHT NOW." A historical snapshot answers the wrong question. + +## The pattern + +```python +# WRONG: read from a cached index +files = json.loads(Path("tests/artifacts/file_index.json").read_text()) + +# RIGHT: walk fresh +files = list(Path("src").rglob("*.py")) +``` + +## See also + +- `conductor/directives/generation_script_walks_filesystem_fresh_each_run` — the same rule for generation/index scripts +- `conductor/directives/audit_script_as_gate` — the `--strict` gate companion +``` + +Create `conductor/directives/audit_walks_filesystem_fresh/meta.md`: + +```markdown +# audit_walks_filesystem_fresh + +## v1 + +**Why this iteration:** New rule, no prior source. Companion to `generation_script_walks_filesystem_fresh_each_run` but scoped to audit scripts specifically. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 3: Write baseline_capture_before_work** + +Create `conductor/directives/baseline_capture_before_work/v1.md`: + +```markdown +# Before any track, capture the audit baseline numbers to a file so per-task deltas are auditable + +## What it says + +Before starting any track that will change the codebase, the agent MUST run the relevant audit scripts (`audit_weak_types.py`, `audit_exception_handling.py`, `audit_main_thread_imports.py`, `audit_no_models_config_io.py`) and save the baseline output to a file. The per-task commits then show the delta against this baseline. + +## Why + +Without a baseline, "did this task introduce a regression?" is unanswerable. The agent commits a change, the audit shows 47 violations, but the agent does not know if it was 47 before or 45 before. The baseline file is the "before" snapshot that makes the "after" meaningful. + +## The pattern + +```bash +# Before the first task +uv run python scripts/audit_weak_types.py --json > tests/artifacts/tier2_state//baseline_weak_types.json +uv run python scripts/audit_exception_handling.py --json > tests/artifacts/tier2_state//baseline_exception_handling.json + +# After each task, compare +uv run python scripts/audit_weak_types.py --json > tests/artifacts/tier2_state//after_task_N_weak_types.json +``` + +## See also + +- `conductor/directives/tier2_pre_flight_audit_gates` — the Tier 2 pre-flight audit protocol +- `conductor/directives/verify_clean_baseline_before_starting` — verify test baseline before starting +``` + +Create `conductor/directives/baseline_capture_before_work/meta.md`: + +```markdown +# baseline_capture_before_work + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the baseline-capture pattern already practiced in `conductor/directives/tier2_pre_flight_audit_gates` but generalized to any track (not just tier2-sandbox). +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 4: Commit** + +```bash +git add conductor/directives/audit_script_as_gate/ conductor/directives/audit_walks_filesystem_fresh/ conductor/directives/baseline_capture_before_work/ +git commit -m "feat(directives): add 3 audit-specific directives (gate, fresh-walk, baseline-capture)" +``` + +--- + +### Task 3.2: Create the 2 fix_tests directives + +**Files:** +- Create: `conductor/directives/regression_bisect_to_clean_baseline/v1.md` + `meta.md` +- Create: `conductor/directives/adapt_test_not_skip_test/v1.md` + `meta.md` + +- [ ] **Step 1: Write regression_bisect_to_clean_baseline** + +Create `conductor/directives/regression_bisect_to_clean_baseline/v1.md`: + +```markdown +# When fixing a regression, bisect to the last known-green commit before proposing a fix + +## What it says + +When a test regresses (was passing, now failing), the agent MUST `git bisect` (or manually bisect by running the test at recent commits) to identify the exact commit that introduced the regression BEFORE proposing a fix. The bisect result tells you what changed; the fix targets the cause, not the symptom. + +## Why + +Without a bisect, the agent is guessing at the cause. "The test fails because X is null" — but WHY is X null? The bisect points to the commit that made X null. The fix is then surgical: revert or repair the specific change. Without the bisect, the agent adds a null check (treating the symptom) and the real cause (a broken initialization in a different module) ships to production. + +## The pattern + +```bash +# Identify the last known-green commit +git log --oneline -20 + +# Run the failing test at recent commits until you find the green->red transition +git stash # if needed to preserve working tree +git switch -c bisect-tmp +uv run pytest tests/test_failing.py -v +# ... repeat until you find the transition commit +git switch - # back to the working branch +git branch -D bisect-tmp +``` + +## See also + +- `conductor/directives/reproduction_before_fix` — reproduce the bug before fixing +- `conductor/directives/single_hypothesis_minimal_test` — test one hypothesis at a time +``` + +Create `conductor/directives/regression_bisect_to_clean_baseline/meta.md`: + +```markdown +# regression_bisect_to_clean_baseline + +## v1 + +**Why this iteration:** New rule, no prior source. The bisect-first pattern is implied by `reproduction_before_fix` but not explicitly stated for regressions. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 2: Write adapt_test_not_skip_test** + +Create `conductor/directives/adapt_test_not_skip_test/v1.md`: + +```markdown +# When a test fails due to a production API change, adapt the test to the new contract — never skip it + +## What it says + +When a test fails because production code changed its public API (function signature, return shape, callable-vs-value), the agent MUST adapt the test to the new contract. The agent MUST NOT add `@pytest.mark.skip` to make the test "pass." Skipping hides the regression; adapting fixes it. + +## Why + +A skipped test is a test that does not run. It provides zero coverage. The production API changed, the test is the only thing that would catch a consumer of the old API, and skipping it means the consumer breakage ships unnoticed. Adapting the test to the new contract keeps the coverage live. + +## The pattern + +```python +# WRONG: skip the test +@pytest.mark.skip(reason="API changed") +def test_old_behavior(): + ... + +# RIGHT: adapt to the new contract +def test_new_behavior(): + # Old: result = C_LBL (value) + # New: result = C_LBL() (callable) + result = C_LBL() + assert isinstance(result, ImVec4) +``` + +## See also + +- `conductor/directives/adapt_test_mocks_to_production_api_change` — the broader rule for adapting test mocks +- `conductor/directives/no_skip_markers_as_avoidance` — skip markers are documentation, not avoidance +``` + +Create `conductor/directives/adapt_test_not_skip_test/meta.md`: + +```markdown +# adapt_test_not_skip_test + +## v1 + +**Why this iteration:** New rule, no prior source. Companion to `adapt_test_mocks_to_production_api_change` but scoped to the test itself (not the mock). Reinforces `no_skip_markers_as_avoidance` for the API-change case specifically. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 3: Commit** + +```bash +git add conductor/directives/regression_bisect_to_clean_baseline/ conductor/directives/adapt_test_not_skip_test/ +git commit -m "feat(directives): add 2 regression-fix directives (bisect-to-baseline, adapt-not-skip)" +``` + +--- + +### Task 3.3: Create the 2 refactor directives + +**Files:** +- Create: `conductor/directives/refactor_preserves_behavior/v1.md` + `meta.md` +- Create: `conductor/directives/refactor_one_subsystem_per_phase/v1.md` + `meta.md` + +- [ ] **Step 1: Write refactor_preserves_behavior** + +Create `conductor/directives/refactor_preserves_behavior/v1.md`: + +```markdown +# A refactor must preserve observable behavior — tests passing before must pass after + +## What it says + +A refactor is a change to internal structure that does NOT change observable behavior. The contract: every test that passed before the refactor MUST pass after. If a test fails after the refactor, either the refactor broke behavior (fix the refactor) or the test was testing an implementation detail (fix the test — but only if the implementation detail was not part of the public contract). + +## Why + +A refactor that breaks tests is not a refactor — it's a behavior change disguised as a refactor. The user reviews "refactor" commits differently than "feature" commits; a refactor is expected to be behavior-neutral. If the refactor breaks tests, the user's review assumption (this is safe) is violated. + +## The pattern + +```bash +# Before refactor: capture the test baseline +uv run python scripts/run_tests_batched.py --tier tier3 > tests/artifacts/tier2_state//before_refactor.log 2>&1 + +# After refactor: run the same tier +uv run python scripts/run_tests_batched.py --tier tier3 > tests/artifacts/tier2_state//after_refactor.log 2>&1 + +# Compare: every test that passed before must pass after +``` + +## See also + +- `conductor/directives/contract_change_audit` — audit all callers when changing a public interface +- `conductor/directives/search_all_call_sites_after_signature_change` — search all call sites +``` + +Create `conductor/directives/refactor_preserves_behavior/meta.md`: + +```markdown +# refactor_preserves_behavior + +## v1 + +**Why this iteration:** New rule, no prior source. The behavior-preservation contract is implicit in the word "refactor" but never explicitly stated. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 2: Write refactor_one_subsystem_per_phase** + +Create `conductor/directives/refactor_one_subsystem_per_phase/v1.md`: + +```markdown +# Refactor one subsystem per phase — never touch two subsystems in the same atomic commit + +## What it says + +A refactor phase targets ONE subsystem (e.g., `src/ai_client.py`, `src/mcp_client.py`, `src/app_controller.py`). Two subsystems in the same phase means the diff is unreviewable: if one subsystem's refactor has a bug, the user cannot revert just that subsystem without also reverting the other. + +## Why + +The atomic-per-task commit principle extends to refactors. A phase that touches `ai_client.py` AND `mcp_client.py` in the same commit is a phase that cannot be bisected. If the post-refactor tests fail, the bisect points at the one commit that touched both — the agent cannot tell which subsystem caused the failure. + +## The pattern + +``` +# WRONG: one phase, two subsystems +Phase 1: refactor ai_client.py type promotion + refactor mcp_client.py type promotion + +# RIGHT: two phases, one subsystem each +Phase 1: refactor ai_client.py type promotion +Phase 2: refactor mcp_client.py type promotion +``` + +## See also + +- `conductor/directives/atomic_per_task_commits` — one task = one commit +- `conductor/directives/scope_creep_track_doc_ban` — scope creep is banned +``` + +Create `conductor/directives/refactor_one_subsystem_per_phase/meta.md`: + +```markdown +# refactor_one_subsystem_per_phase + +## v1 + +**Why this iteration:** New rule, no prior source. Extends `atomic_per_task_commits` to the refactor phase granularity. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 3: Commit** + +```bash +git add conductor/directives/refactor_preserves_behavior/ conductor/directives/refactor_one_subsystem_per_phase/ +git commit -m "feat(directives): add 2 refactor directives (preserves-behavior, one-subsystem-per-phase)" +``` + +--- + +### Task 3.4: Create the 2 new_script_tool directives + +**Files:** +- Create: `conductor/directives/scripts_namespace_isolated/v1.md` + `meta.md` +- Create: `conductor/directives/scripts_audit_pattern/v1.md` + `meta.md` + +- [ ] **Step 1: Write scripts_namespace_isolated** + +Create `conductor/directives/scripts_namespace_isolated/v1.md`: + +```markdown +# Scripts are namespace-isolated by directory — no `from scripts.foo import bar` across script dirs + +## What it says + +Script directories (`scripts/`, `scripts/tier2/`, `scripts/audit/`, `scripts/tier2/artifacts/`) are namespace-isolated. A script in one directory MUST NOT import from a script in another directory. Scripts are not a package; they are standalone tools. + +## Why + +Scripts are throw-away or single-purpose tools. If `scripts/audit_weak_types.py` imports from `scripts/tier2/failcount.py`, then `audit_weak_types.py` depends on the tier2 sandbox's internal state. The dependency makes the audit script fragile (it breaks if tier2 moves) and the tier2 scripts less isolated (they're now part of a graph, not standalone). + +## The pattern + +```python +# WRONG: cross-directory import +from scripts.tier2.failcount import should_give_up + +# RIGHT: copy the needed function into the script, or factor it into src/ +``` + +## See also + +- `conductor/directives/file_naming_convention` — the file naming rules +- `conductor/directives/large_files_are_fine` — large files are fine; don't split for modularity +``` + +Create `conductor/directives/scripts_namespace_isolated/meta.md`: + +```markdown +# scripts_namespace_isolated + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the existing project practice (scripts do not cross-import) as an explicit directive. +**Source:** new rule (pattern inferred from existing `scripts/` structure) + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 2: Write scripts_audit_pattern** + +Create `conductor/directives/scripts_audit_pattern/v1.md`: + +```markdown +# New audit scripts follow the `audit_.py` naming + `--json` + `--strict` pattern of the existing 4 + +## What it says + +A new audit script MUST: +1. Be named `scripts/audit_.py` (not `check_.py`, not `lint_.py`). +2. Have a `--help` that explains what it checks and how to fix violations. +3. Have a `--json` mode for CI integration (machine-readable output). +4. Have a default informational mode (exits 0; prints human-readable report). +5. Have a `--strict` mode (exits 1 on any violation; the CI gate). + +## Why + +The 4 existing audit scripts (`audit_weak_types.py`, `audit_exception_handling.py`, `audit_main_thread_imports.py`, `audit_no_models_config_io.py`) all follow this pattern. A new audit script that breaks the pattern (e.g., named `check_foo.py` with no `--strict`) is inconsistent — the CI pipeline will not know how to gate on it, and the user will not know how to run it. + +## See also + +- `conductor/directives/audit_script_as_gate` — the `--strict` gate rule +- `conductor/directives/convention_enforcement_4_mechanisms` — the 4-mechanism model +``` + +Create `conductor/directives/scripts_audit_pattern/meta.md`: + +```markdown +# scripts_audit_pattern + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the existing audit-script conventions as a directive so new audit scripts follow the same shape. +**Source:** new rule (pattern inferred from existing `scripts/audit_*.py`) + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 3: Commit** + +```bash +git add conductor/directives/scripts_namespace_isolated/ conductor/directives/scripts_audit_pattern/ +git commit -m "feat(directives): add 2 script-authoring directives (namespace-isolated, audit-pattern)" +``` + +--- + +### Task 3.5: Create the remaining 6 directives (meta_tooling, directives_curation, documentation, media_analysis x2, ideation) + +**Files:** +- Create: `conductor/directives/meta_tooling_no_app_imports/v1.md` + `meta.md` +- Create: `conductor/directives/directive_one_concept_per_file/v1.md` + `meta.md` +- Create: `conductor/directives/doc_update_after_track_ships/v1.md` + `meta.md` +- Create: `conductor/directives/media_source_cited_in_output/v1.md` + `meta.md` +- Create: `conductor/directives/media_analysis_neutral_voice/v1.md` + `meta.md` +- Create: `conductor/directives/ideation_leads_with_recommended/v1.md` + `meta.md` + +- [ ] **Step 1: Write meta_tooling_no_app_imports** + +Create `conductor/directives/meta_tooling_no_app_imports/v1.md`: + +```markdown +# Meta-tooling scripts must not import `src/` application modules — the meta-tooling domain is distinct from the application domain + +## What it says + +Scripts in `scripts/` that are part of the META-TOOLING layer (the agent orchestration, the conductor, the directive system) MUST NOT import application modules from `src/` (e.g., `src/ai_client.py`, `src/app_controller.py`, `src/mcp_client.py`). The meta-tooling domain builds the tool; the application domain is the tool being built. + +## Why + +The meta-tooling/application boundary (see `docs/guide_meta_boundary.md`) is load-bearing. If a meta-tooling script imports `src/ai_client`, the meta-tooling domain now depends on the application's internal state. A refactor of `ai_client.py` breaks the meta-tooling script. The two domains evolve independently because they are different concerns. + +## See also + +- `conductor/directives/meta_tooling_app_boundary_check` — the broader boundary-check rule +- `docs/guide_meta_boundary.md` — the canonical boundary guide +``` + +Create `conductor/directives/meta_tooling_no_app_imports/meta.md`: + +```markdown +# meta_tooling_no_app_imports + +## v1 + +**Why this iteration:** New rule, no prior source. Reinforces `meta_tooling_app_boundary_check` at the import level. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 2: Write directive_one_concept_per_file** + +Create `conductor/directives/directive_one_concept_per_file/v1.md`: + +```markdown +# One directive per directory — do not combine two rules in one `v1.md` + +## What it says + +Each directive directory (`conductor/directives//`) contains exactly ONE rule in its `v1.md`. Do not combine two related-but-distinct rules into a single `v1.md`. If a rule has two parts that could be independently tagged, split into two directives. + +## Why + +Directives are independently tagged (the 6-dim `tags.toml`), independently composed into presets, and independently tested. A `v1.md` that combines "ban `dict[str, Any]`" and "ban `Optional[T]` returns" cannot be tagged with a single subject (data-structures vs error-handling) and cannot be independently included in a preset (one without the other). One concept per file keeps the directive atomic. + +## See also + +- `conductor/directives/verbatim_lift_not_rewrite` — the harvest rule +- `conductor/directives/warm_md_duplicates_not_in_place` — the `.warm.md` duplicate rule +``` + +Create `conductor/directives/directive_one_concept_per_file/meta.md`: + +```markdown +# directive_one_concept_per_file + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the existing practice (every directive is one concept) as an explicit rule for future harvesters. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 3: Write doc_update_after_track_ships** + +Create `conductor/directives/doc_update_after_track_ships/v1.md`: + +```markdown +# After a track ships, update the affected `docs/guide_*.md` to reflect the new module structure + +## What it says + +When a track changes the shape of a module (renames a file, moves a system, adds a new system file), the implementing agent MUST update the corresponding `docs/guide_*.md` to reflect the new structure. This is part of the track's final phase — not a follow-up track. + +## Why + +A track that only changes code (not docs) is incomplete. The next agent reads `docs/guide_*.md` to understand the module; if the guide is stale, the agent's mental model is wrong from the start. The documentation refresh is the track's handoff to the next agent. + +## See also + +- `conductor/directives/end_of_track_report_required` — the TRACK_COMPLETION report +- `conductor/directives/chronology_must_regenerate_after_every_track_ship` — the chronology regeneration +``` + +Create `conductor/directives/doc_update_after_track_ships/meta.md`: + +```markdown +# doc_update_after_track_ships + +## v1 + +**Why this iteration:** New rule, no prior source. Encodes the existing "Documentation Refresh Protocol" from `conductor/workflow.md` as a directive. +**Source:** new rule (pattern from `conductor/workflow.md` §"Documentation Refresh Protocol") + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 4: Write media_source_cited_in_output** + +Create `conductor/directives/media_source_cited_in_output/v1.md`: + +```markdown +# Media analysis output must cite the source URL/timestamp for every claim — no unsourced assertions + +## What it says + +When an agent analyzes content from a media source (YouTube transcript, substack article, tweet, user-provided text), every claim in the output MUST cite the source: the URL, the timestamp (for video/audio), or the paragraph number (for text). Unsourced assertions are banned. + +## Why + +Media analysis without citations is indistinguishable from hallucination. The user cannot verify a claim like "the author argues X" without knowing where in the source the author said X. The citation is the provenance; without it, the analysis is unverifiable. + +## See also + +- `conductor/directives/rag_six_rules` — the RAG provenance rule (same principle, different domain) +- `conductor/directives/comprehensive_logging` — comprehensive logging includes source provenance +``` + +Create `conductor/directives/media_source_cited_in_output/meta.md`: + +```markdown +# media_source_cited_in_output + +## v1 + +**Why this iteration:** New rule, no prior source. The citation requirement is the media-analysis equivalent of RAG's provenance rule. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 5: Write media_analysis_neutral_voice** + +Create `conductor/directives/media_analysis_neutral_voice/v1.md`: + +```markdown +# Media analysis output uses neutral voice — value judgments about the source content are the user's call, not the agent's + +## What it says + +When an agent analyzes media content, the output MUST use neutral voice. The agent describes what the source says, summarizes the arguments, extracts the claims — but does NOT evaluate whether the source is "good," "bad," "right," "wrong," "compelling," or "unconvincing." Value judgments are the user's domain. + +## Why + +The agent is a tool for understanding content, not a critic. If the agent says "this is a compelling argument," the user's own judgment is preempted. The user wants the content extracted and organized; the user decides whether it's compelling. + +## See also + +- `conductor/directives/neutral_language_for_doc_drift` — neutral language for documentation drift (same principle) +- `conductor/directives/no_performative_agreement_in_review` — no performative agreement (same principle) +``` + +Create `conductor/directives/media_analysis_neutral_voice/meta.md`: + +```markdown +# media_analysis_neutral_voice + +## v1 + +**Why this iteration:** New rule, no prior source. The neutral-voice principle from `neutral_language_for_doc_drift` applied to media analysis. +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 6: Write ideation_leads_with_recommended** + +Create `conductor/directives/ideation_leads_with_recommended/v1.md`: + +```markdown +# Ideation sessions lead with a recommended concept + the reasoning, not 3 unranked options + +## What it says + +When an agent helps the user ideate new concepts, tools, or UX, the output MUST lead with a single recommended concept and the reasoning for why it's the best fit. The agent MAY present 2-3 alternatives after the recommendation, but the recommendation comes first with the reasoning. + +## Why + +"Here are 3 options, pick one" offloads the synthesis to the user. The user asked for ideation help, not a multiple-choice quiz. The agent has the context; the agent should make the call. The user can reject the recommendation, but starting from a recommendation is faster than starting from a blank list. + +## See also + +- `conductor/directives/design_leads_with_recommendation` — the brainstorming equivalent +- `conductor/directives/exactly_four_completion_options` — completion options are different (they're structured choices, not ideation) +``` + +Create `conductor/directives/ideation_leads_with_recommended/meta.md`: + +```markdown +# ideation_leads_with_recommended + +## v1 + +**Why this iteration:** New rule, no prior source. Companion to `design_leads_with_recommendation` but scoped to ideation (concept generation) rather than design (architecture selection). +**Source:** new rule + +--- +**Lifted:** 2026-07-05 +``` + +- [ ] **Step 7: Commit** + +```bash +git add conductor/directives/meta_tooling_no_app_imports/ conductor/directives/directive_one_concept_per_file/ conductor/directives/doc_update_after_track_ships/ conductor/directives/media_source_cited_in_output/ conductor/directives/media_analysis_neutral_voice/ conductor/directives/ideation_leads_with_recommended/ +git commit -m "feat(directives): add 6 engagement-specific directives (meta-tooling, curation, doc, media x2, ideation)" +``` + +--- + +### Task 3.6: Update tags.toml with the 15 new directives + +**Files:** +- Modify: `conductor/directives/tags.toml` + +- [ ] **Step 1: Add 15 new entries to tags.toml** + +Append to `conductor/directives/tags.toml` (after the last existing entry, before EOF): + +```toml + +# 2026-07-05: 15 new engagement-specific directives (directive_preset_system track) + +[directive.audit_script_as_gate] +tags = ["process", "verifying", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] + +[directive.audit_walks_filesystem_fresh] +tags = ["python", "writing", "all-tiers", "architecture", "mandatory", "lifted-from-new-rule"] + +[directive.baseline_capture_before_work] +tags = ["process", "verifying", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] + +[directive.regression_bisect_to_clean_baseline] +tags = ["process", "debugging", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] + +[directive.adapt_test_not_skip_test] +tags = ["python", "testing", "all-tiers", "styleguide", "mandatory", "lifted-from-new-rule"] + +[directive.refactor_preserves_behavior] +tags = ["python", "editing", "all-tiers", "architecture", "mandatory", "lifted-from-new-rule"] + +[directive.refactor_one_subsystem_per_phase] +tags = ["process", "editing", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] + +[directive.scripts_namespace_isolated] +tags = ["python", "writing", "all-tiers", "imports", "mandatory", "lifted-from-new-rule"] + +[directive.scripts_audit_pattern] +tags = ["process", "writing", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] + +[directive.meta_tooling_no_app_imports] +tags = ["python", "writing", "all-tiers", "mcp", "mandatory", "lifted-from-new-rule"] + +[directive.directive_one_concept_per_file] +tags = ["process", "writing", "all-tiers", "documentation", "mandatory", "lifted-from-new-rule"] + +[directive.doc_update_after_track_ships] +tags = ["process", "writing", "all-tiers", "documentation", "mandatory", "lifted-from-new-rule"] + +[directive.media_source_cited_in_output] +tags = ["process", "writing", "all-tiers", "documentation", "mandatory", "lifted-from-new-rule"] + +[directive.media_analysis_neutral_voice] +tags = ["process", "writing", "all-tiers", "documentation", "mandatory", "lifted-from-new-rule"] + +[directive.ideation_leads_with_recommended] +tags = ["process", "writing", "all-tiers", "conductor", "mandatory", "lifted-from-new-rule"] +``` + +- [ ] **Step 2: Verify tags.toml parses** + +Run: `uv run python -c "import tomllib; tomllib.load(open('conductor/directives/tags.toml','rb')); print('OK')"` +Expected: `OK` + +- [ ] **Step 3: Commit** + +```bash +git add conductor/directives/tags.toml +git commit -m "feat(directives): add 15 new directive entries to tags.toml" +``` + +--- + +## Phase 4: Create 12 engagement presets + +Focus: Write the 12 engagement preset files that inherit baseline and add their targeted subsets. Each is a markdown file with `## Inherits`, `## Directives to warm`, `## Non-directive context`, and `## Notes`. + +### Task 4.1: Create audit.md, fix_tests.md, new_script_tool.md, meta_tooling.md + +**Files:** +- Create: `conductor/directives/presets/audit.md` +- Create: `conductor/directives/presets/fix_tests.md` +- Create: `conductor/directives/presets/new_script_tool.md` +- Create: `conductor/directives/presets/meta_tooling.md` + +- [ ] **Step 1: Write audit.md** + +Create `conductor/directives/presets/audit.md`: + +```markdown +# Preset: audit + +For agents auditing the codebase — running the audit scripts, capturing baselines, classifying violations, and producing audit reports. Adds the 3 audit-specific directives on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- audit_script_as_gate: conductor/directives/audit_script_as_gate/v1.md +- audit_walks_filesystem_fresh: conductor/directives/audit_walks_filesystem_fresh/v1.md +- baseline_capture_before_work: conductor/directives/baseline_capture_before_work/v1.md + +## Notes +Engagement preset for the "auditing the codebase" op. Inherits baseline (57) + adds 3 audit-specific directives. Total: 60 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 2: Write fix_tests.md** + +Create `conductor/directives/presets/fix_tests.md`: + +```markdown +# Preset: fix_tests + +For agents fixing test regressions — bisecting to the clean baseline, adapting tests to production API changes, running the batched test runner, and verifying in batch (not isolation). Adds the 23 TARGETED:testing directives + 2 regression-fix directives on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- tdd_red_green_required: conductor/directives/tdd_red_green_required/v1.md +- test_must_fail_for_believed_reason: conductor/directives/test_must_fail_for_believed_reason/v1.md +- test_passing_immediately_proves_nothing: conductor/directives/test_passing_immediately_proves_nothing/v1.md +- test_narrow_not_kitchen_sink: conductor/directives/test_narrow_not_kitchen_sink/v1.md +- batch_verification_not_isolation: conductor/directives/batch_verification_not_isolation/v1.md +- fragile_test_in_batch_is_failing_test: conductor/directives/fragile_test_in_batch_is_failing_test/v1.md +- no_skip_markers_as_avoidance: conductor/directives/no_skip_markers_as_avoidance/v1.md +- ban_arbitrary_core_mocking: conductor/directives/ban_arbitrary_core_mocking/v1.md +- test_instantiation_not_mock_away: conductor/directives/test_instantiation_not_mock_away/v1.md +- adapt_test_mocks_to_production_api_change: conductor/directives/adapt_test_mocks_to_production_api_change/v1.md +- live_gui_poll_not_sleep: conductor/directives/live_gui_poll_not_sleep/v1.md +- live_gui_session_scoped_no_restart: conductor/directives/live_gui_session_scoped_no_restart/v1.md +- no_real_io_during_tests: conductor/directives/no_real_io_during_tests/v1.md +- enforce_no_real_toml_in_tests: conductor/directives/enforce_no_real_toml_in_tests/v1.md +- test_sandbox: conductor/directives/test_sandbox/v1.md +- workspace_paths: conductor/directives/workspace_paths/v1.md +- opt_in_integration_test_via_env_var_marker: conductor/directives/opt_in_integration_test_via_env_var_marker/v1.md +- deterministic_signal_endpoint_pattern: conductor/directives/deterministic_signal_endpoint_pattern/v1.md +- failure_message_actionable_not_vague: conductor/directives/failure_message_actionable_not_vague/v1.md +- three_tier_test_strategy_for_fragile_subsystems: conductor/directives/three_tier_test_strategy_for_fragile_subsystems/v1.md +- test_classification_via_import_presence: conductor/directives/test_classification_via_import_presence/v1.md +- surface_dirty_state_in_test_runner: conductor/directives/surface_dirty_state_in_test_runner/v1.md +- imscope_tuple_return_per_scope_override: conductor/directives/imscope_tuple_return_per_scope_override/v1.md +- regression_bisect_to_clean_baseline: conductor/directives/regression_bisect_to_clean_baseline/v1.md +- adapt_test_not_skip_test: conductor/directives/adapt_test_not_skip_test/v1.md + +## Notes +Engagement preset for the "fixing tests based on regressions" op. Inherits baseline (57) + adds 23 TARGETED:testing + 2 regression-fix. Total: 82 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 3: Write new_script_tool.md** + +Create `conductor/directives/presets/new_script_tool.md`: + +```markdown +# Preset: new_script_tool + +For agents creating new script tools under `scripts/`. Adds the 2 script-authoring directives on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- scripts_namespace_isolated: conductor/directives/scripts_namespace_isolated/v1.md +- scripts_audit_pattern: conductor/directives/scripts_audit_pattern/v1.md + +## Notes +Engagement preset for the "making new script tools" op. Inherits baseline (57) + adds 2 script-authoring directives. Total: 59 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 4: Write meta_tooling.md** + +Create `conductor/directives/presets/meta_tooling.md`: + +```markdown +# Preset: meta_tooling + +For agents adjusting the meta-tooling layer — the conductor system, the directive harness, the agent prompts, the MCP server. Adds the meta-tooling boundary directive on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- meta_tooling_app_boundary_check: conductor/directives/meta_tooling_app_boundary_check/v1.md +- meta_tooling_no_app_imports: conductor/directives/meta_tooling_no_app_imports/v1.md + +## Non-directive context +Read each file below as full documents. + +- meta boundary guide: docs/guide_meta_boundary.md + +## Notes +Engagement preset for the "adjusting meta-tooling" op. Inherits baseline (57) + adds 1 APP:mcp + 1 new meta-tooling directive + the meta-boundary guide. Total: 59 directives + 5 non-directive context files. +``` + +- [ ] **Step 5: Commit** + +```bash +git add conductor/directives/presets/audit.md conductor/directives/presets/fix_tests.md conductor/directives/presets/new_script_tool.md conductor/directives/presets/meta_tooling.md +git commit -m "feat(directives): add 4 engagement presets (audit, fix_tests, new_script_tool, meta_tooling)" +``` + +--- + +### Task 4.2: Create implement_feature.md, refactor.md, directives_curation.md, documentation.md + +**Files:** +- Create: `conductor/directives/presets/implement_feature.md` +- Create: `conductor/directives/presets/refactor.md` +- Create: `conductor/directives/presets/directives_curation.md` +- Create: `conductor/directives/presets/documentation.md` + +- [ ] **Step 1: Write implement_feature.md** + +Create `conductor/directives/presets/implement_feature.md`: + +```markdown +# Preset: implement_feature + +For agents implementing a new feature into `./src`, `./simulation`, or `./tests`. Adds the full testing set + the APP-subsystem directives (imgui, app-controller, architecture, rag-memory, mcp) on top of baseline. The agent loads the union; if the feature touches only one subsystem, the irrelevant APP directives are still useful as context. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- tdd_red_green_required: conductor/directives/tdd_red_green_required/v1.md +- test_must_fail_for_believed_reason: conductor/directives/test_must_fail_for_believed_reason/v1.md +- test_passing_immediately_proves_nothing: conductor/directives/test_passing_immediately_proves_nothing/v1.md +- test_narrow_not_kitchen_sink: conductor/directives/test_narrow_not_kitchen_sink/v1.md +- batch_verification_not_isolation: conductor/directives/batch_verification_not_isolation/v1.md +- fragile_test_in_batch_is_failing_test: conductor/directives/fragile_test_in_batch_is_failing_test/v1.md +- no_skip_markers_as_avoidance: conductor/directives/no_skip_markers_as_avoidance/v1.md +- ban_arbitrary_core_mocking: conductor/directives/ban_arbitrary_core_mocking/v1.md +- test_instantiation_not_mock_away: conductor/directives/test_instantiation_not_mock_away/v1.md +- adapt_test_mocks_to_production_api_change: conductor/directives/adapt_test_mocks_to_production_api_change/v1.md +- live_gui_poll_not_sleep: conductor/directives/live_gui_poll_not_sleep/v1.md +- live_gui_session_scoped_no_restart: conductor/directives/live_gui_session_scoped_no_restart/v1.md +- no_real_io_during_tests: conductor/directives/no_real_io_during_tests/v1.md +- enforce_no_real_toml_in_tests: conductor/directives/enforce_no_real_toml_in_tests/v1.md +- test_sandbox: conductor/directives/test_sandbox/v1.md +- workspace_paths: conductor/directives/workspace_paths/v1.md +- opt_in_integration_test_via_env_var_marker: conductor/directives/opt_in_integration_test_via_env_var_marker/v1.md +- deterministic_signal_endpoint_pattern: conductor/directives/deterministic_signal_endpoint_pattern/v1.md +- failure_message_actionable_not_vague: conductor/directives/failure_message_actionable_not_vague/v1.md +- three_tier_test_strategy_for_fragile_subsystems: conductor/directives/three_tier_test_strategy_for_fragile_subsystems/v1.md +- test_classification_via_import_presence: conductor/directives/test_classification_via_import_presence/v1.md +- surface_dirty_state_in_test_runner: conductor/directives/surface_dirty_state_in_test_runner/v1.md +- imscope_tuple_return_per_scope_override: conductor/directives/imscope_tuple_return_per_scope_override/v1.md +- imgui_scope_verification: conductor/directives/imgui_scope_verification/v1.md +- imgui_scope_entered_flag_for_no_op_return: conductor/directives/imgui_scope_entered_flag_for_no_op_return/v1.md +- ui_delegation_for_hot_reload: conductor/directives/ui_delegation_for_hot_reload/v1.md +- modal_explicit_opened_list_for_lifecycle: conductor/directives/modal_explicit_opened_list_for_lifecycle/v1.md +- view_composes_does_not_leak_into_theme_get_color: conductor/directives/view_composes_does_not_leak_into_theme_get_color/v1.md +- float_only_math_for_visual_transforms: conductor/directives/float_only_math_for_visual_transforms/v1.md +- controller_property_delegation_no_dual_state: conductor/directives/controller_property_delegation_no_dual_state/v1.md +- config_state_owner: conductor/directives/config_state_owner/v1.md +- reset_session_preserves_project_path: conductor/directives/reset_session_preserves_project_path/v1.md +- defer_heavy_sdk_imports_to_subprocess: conductor/directives/defer_heavy_sdk_imports_to_subprocess/v1.md +- defer_not_catch_for_native_crashes: conductor/directives/defer_not_catch_for_native_crashes/v1.md +- graceful_optional_dependency_degradation: conductor/directives/graceful_optional_dependency_degradation/v1.md +- submit_io_lazy_pool_recreation: conductor/directives/submit_io_lazy_pool_recreation/v1.md +- log_pruner_backoff_for_locked_files: conductor/directives/log_pruner_backoff_for_locked_files/v1.md +- undo_redo_100_snapshot_capacity: conductor/directives/undo_redo_100_snapshot_capacity/v1.md +- feature_flag_delete_to_turn_off: conductor/directives/feature_flag_delete_to_turn_off/v1.md +- runtime_config_flag_vs_test_env_var_gate: conductor/directives/runtime_config_flag_vs_test_env_var_gate/v1.md +- interceptor_activates_only_on_matching_shape: conductor/directives/interceptor_activates_only_on_matching_shape/v1.md +- quarantine_flag_the_engine_not_shared_types: conductor/directives/quarantine_flag_the_engine_not_shared_types/v1.md +- profile_first_optimize_second: conductor/directives/profile_first_optimize_second/v1.md +- state_visible_at_the_right_layer: conductor/directives/state_visible_at_the_right_layer/v1.md +- per_dimension_pick_dim_not_tool: conductor/directives/per_dimension_pick_dim_not_tool/v1.md +- cache_stable_to_volatile: conductor/directives/cache_stable_to_volatile/v1.md +- rag_six_rules: conductor/directives/rag_six_rules/v1.md +- knowledge_harvest_pattern: conductor/directives/knowledge_harvest_pattern/v1.md +- chroma_cache_path: conductor/directives/chroma_cache_path/v1.md +- per_conversation_scratch_dir: conductor/directives/per_conversation_scratch_dir/v1.md +- file_id_stable_across_rename: conductor/directives/file_id_stable_across_rename/v1.md +- meta_tooling_app_boundary_check: conductor/directives/meta_tooling_app_boundary_check/v1.md + +## Notes +Engagement preset for the "implementing a new feature into ./src, ./simulation, or ./tests" op. Inherits baseline (57) + adds 23 TARGETED:testing + 14 APP:architecture + 6 APP:imgui + 3 APP:app-controller + 5 APP:rag-memory + 1 APP:mcp. Total: 109 directives + 4 non-directive context files (inherited). If the blob is too large for the context window, pass a smaller op-specific subset via `max_chars`. +``` + +- [ ] **Step 2: Write refactor.md** + +Create `conductor/directives/presets/refactor.md`: + +```markdown +# Preset: refactor + +For agents refactoring or overhauling the codebase. Adds the testing set + 2 refactor-specific directives on top of baseline. The refactor must preserve behavior (tests pass before and after); one subsystem per phase. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- tdd_red_green_required: conductor/directives/tdd_red_green_required/v1.md +- test_must_fail_for_believed_reason: conductor/directives/test_must_fail_for_believed_reason/v1.md +- test_passing_immediately_proves_nothing: conductor/directives/test_passing_immediately_proves_nothing/v1.md +- test_narrow_not_kitchen_sink: conductor/directives/test_narrow_not_kitchen_sink/v1.md +- batch_verification_not_isolation: conductor/directives/batch_verification_not_isolation/v1.md +- fragile_test_in_batch_is_failing_test: conductor/directives/fragile_test_in_batch_is_failing_test/v1.md +- no_skip_markers_as_avoidance: conductor/directives/no_skip_markers_as_avoidance/v1.md +- ban_arbitrary_core_mocking: conductor/directives/ban_arbitrary_core_mocking/v1.md +- test_instantiation_not_mock_away: conductor/directives/test_instantiation_not_mock_away/v1.md +- adapt_test_mocks_to_production_api_change: conductor/directives/adapt_test_mocks_to_production_api_change/v1.md +- live_gui_poll_not_sleep: conductor/directives/live_gui_poll_not_sleep/v1.md +- live_gui_session_scoped_no_restart: conductor/directives/live_gui_session_scoped_no_restart/v1.md +- no_real_io_during_tests: conductor/directives/no_real_io_during_tests/v1.md +- enforce_no_real_toml_in_tests: conductor/directives/enforce_no_real_toml_in_tests/v1.md +- test_sandbox: conductor/directives/test_sandbox/v1.md +- workspace_paths: conductor/directives/workspace_paths/v1.md +- opt_in_integration_test_via_env_var_marker: conductor/directives/opt_in_integration_test_via_env_var_marker/v1.md +- deterministic_signal_endpoint_pattern: conductor/directives/deterministic_signal_endpoint_pattern/v1.md +- failure_message_actionable_not_vague: conductor/directives/failure_message_actionable_not_vague/v1.md +- three_tier_test_strategy_for_fragile_subsystems: conductor/directives/three_tier_test_strategy_for_fragile_subsystems/v1.md +- test_classification_via_import_presence: conductor/directives/test_classification_via_import_presence/v1.md +- surface_dirty_state_in_test_runner: conductor/directives/surface_dirty_state_in_test_runner/v1.md +- imscope_tuple_return_per_scope_override: conductor/directives/imscope_tuple_return_per_scope_override/v1.md +- refactor_preserves_behavior: conductor/directives/refactor_preserves_behavior/v1.md +- refactor_one_subsystem_per_phase: conductor/directives/refactor_one_subsystem_per_phase/v1.md + +## Notes +Engagement preset for the "refactoring or overhauling the codebase" op. Inherits baseline (57) + adds 23 TARGETED:testing + 2 refactor. Total: 82 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 3: Write directives_curation.md** + +Create `conductor/directives/presets/directives_curation.md`: + +```markdown +# Preset: directives_curation + +For agents improving, curating, or adding workflow directives or context. Adds the 3 META directives + 3 TARGETED:documentation directives + 1 new curation directive on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- verbatim_lift_not_rewrite: conductor/directives/verbatim_lift_not_rewrite/v1.md +- warm_md_duplicates_not_in_place: conductor/directives/warm_md_duplicates_not_in_place/v1.md +- generation_script_walks_filesystem_fresh_each_run: conductor/directives/generation_script_walks_filesystem_fresh_each_run/v1.md +- docs_philosophy_then_boundaries_then_logic_then_verify: conductor/directives/docs_philosophy_then_boundaries_then_logic_then_verify/v1.md +- neutral_language_for_doc_drift: conductor/directives/neutral_language_for_doc_drift/v1.md +- no_conductor_yaml_for_artifacts: conductor/directives/no_conductor_yaml_for_artifacts/v1.md +- directive_one_concept_per_file: conductor/directives/directive_one_concept_per_file/v1.md + +## Notes +Engagement preset for the "improving, curating, or adding workflow directives or context" op. Inherits baseline (57) + adds 3 META + 3 TARGETED:documentation + 1 curation. Total: 64 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 4: Write documentation.md** + +Create `conductor/directives/presets/documentation.md`: + +```markdown +# Preset: documentation + +For agents writing or updating codebase documentation (`docs/guide_*.md`, `docs/Readme.md`, `docs/AGENTS.md`). Adds the 3 TARGETED:documentation directives + 1 new doc-update directive on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- docs_philosophy_then_boundaries_then_logic_then_verify: conductor/directives/docs_philosophy_then_boundaries_then_logic_then_verify/v1.md +- neutral_language_for_doc_drift: conductor/directives/neutral_language_for_doc_drift/v1.md +- no_conductor_yaml_for_artifacts: conductor/directives/no_conductor_yaml_for_artifacts/v1.md +- doc_update_after_track_ships: conductor/directives/doc_update_after_track_ships/v1.md + +## Non-directive context +Read each file below as full documents. + +- docs index: docs/Readme.md +- agent docs mirror: docs/AGENTS.md + +## Notes +Engagement preset for the "writing or updating codebase documentation" op. Inherits baseline (57) + adds 3 TARGETED:documentation + 1 doc-update. Total: 61 directives + 6 non-directive context files (4 inherited + 2 added). +``` + +- [ ] **Step 5: Commit** + +```bash +git add conductor/directives/presets/implement_feature.md conductor/directives/presets/refactor.md conductor/directives/presets/directives_curation.md conductor/directives/presets/documentation.md +git commit -m "feat(directives): add 4 engagement presets (implement_feature, refactor, directives_curation, documentation)" +``` + +--- + +### Task 4.3: Create media_analysis.md, ideation.md, tier2_autonomous.md + +**Files:** +- Create: `conductor/directives/presets/media_analysis.md` +- Create: `conductor/directives/presets/ideation.md` +- Create: `conductor/directives/presets/tier2_autonomous.md` + +- [ ] **Step 1: Write media_analysis.md** + +Create `conductor/directives/presets/media_analysis.md`: + +```markdown +# Preset: media_analysis + +For agents doing analysis on content from various media sources (YouTube, substack, twitter, user-provided text/markdown). Adds 2 media-analysis directives on top of baseline. No testing directives — media analysis does not touch the test suite. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- media_source_cited_in_output: conductor/directives/media_source_cited_in_output/v1.md +- media_analysis_neutral_voice: conductor/directives/media_analysis_neutral_voice/v1.md + +## Notes +Engagement preset for the "doing analysis on content from various media sources" op. Inherits baseline (57) + adds 2 media-analysis. Total: 59 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 2: Write ideation.md** + +Create `conductor/directives/presets/ideation.md`: + +```markdown +# Preset: ideation + +For agents ideating new concepts, tools, or UX with the user. Adds the 7 PROCESS:planning directives + 1 new ideation directive on top of baseline. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- brainstorm_even_for_simple_projects: conductor/directives/brainstorm_even_for_simple_projects/v1.md +- design_leads_with_recommendation: conductor/directives/design_leads_with_recommendation/v1.md +- spec_self_review_four_checks: conductor/directives/spec_self_review_four_checks/v1.md +- plan_steps_2_to_5_minutes_each: conductor/directives/plan_steps_2_to_5_minutes_each/v1.md +- plans_no_placeholders_or_tbds: conductor/directives/plans_no_placeholders_or_tbds/v1.md +- review_plan_critically_before_executing: conductor/directives/review_plan_critically_before_executing/v1.md +- surface_upstream_api_limits_honestly_in_spec: conductor/directives/surface_upstream_api_limits_honestly_in_spec/v1.md +- ideation_leads_with_recommended: conductor/directives/ideation_leads_with_recommended/v1.md + +## Notes +Engagement preset for the "ideating new concepts or tools or ux with the user" op. Inherits baseline (57) + adds 7 PROCESS:planning + 1 ideation. Total: 65 directives + 4 non-directive context files (inherited). +``` + +- [ ] **Step 3: Write tier2_autonomous.md** + +Create `conductor/directives/presets/tier2_autonomous.md`: + +```markdown +# Preset: tier2_autonomous + +The compound preset for Tier-2 autonomous sandbox execution. Inherits baseline + adds the 20 TARGETED:tier2-sandbox + 23 TARGETED:testing + 8 PROCESS:delegation directives. This is the preset the `tier2-autonomous.warm.md` agent prompt warms with. + +## Inherits +baseline + +## Directives to warm +Read each file below before any action. + +- ban_appdata_paths: conductor/directives/ban_appdata_paths/v1.md +- use_batched_test_runner: conductor/directives/use_batched_test_runner/v1.md +- no_output_filtering: conductor/directives/no_output_filtering/v1.md +- prefer_targeted_tier_runs: conductor/directives/prefer_targeted_tier_runs/v1.md +- throwaway_scripts_isolated_subdir: conductor/directives/throwaway_scripts_isolated_subdir/v1.md +- acknowledgment_in_first_commit: conductor/directives/acknowledgment_in_first_commit/v1.md +- end_of_track_report_required: conductor/directives/end_of_track_report_required/v1.md +- tier2_pre_commit_deletion_and_diff_check: conductor/directives/tier2_pre_commit_deletion_and_diff_check/v1.md +- tier2_pre_flight_audit_gates: conductor/directives/tier2_pre_flight_audit_gates/v1.md +- tier2_post_track_ruff_mypy_audit: conductor/directives/tier2_post_track_ruff_mypy_audit/v1.md +- per_phase_metric_regression_fix: conductor/directives/per_phase_metric_regression_fix/v1.md +- run_full_tier_after_phase_refactor: conductor/directives/run_full_tier_after_phase_refactor/v1.md +- user_corrections_log_in_state_toml: conductor/directives/user_corrections_log_in_state_toml/v1.md +- surface_gaps_at_discovery_not_checkpoint: conductor/directives/surface_gaps_at_discovery_not_checkpoint/v1.md +- chronology_must_regenerate_after_every_track_ship: conductor/directives/chronology_must_regenerate_after_every_track_ship/v1.md +- use_git_history_as_classification_source_of_truth: conductor/directives/use_git_history_as_classification_source_of_truth/v1.md +- classifier_must_emit_per_row_evidence: conductor/directives/classifier_must_emit_per_row_evidence/v1.md +- quality_gate_catches_broken_classifier_before_ship: conductor/directives/quality_gate_catches_broken_classifier_before_ship/v1.md +- manual_compaction_only_no_auto_summarize: conductor/directives/manual_compaction_only_no_auto_summarize/v1.md +- preserve_before_compact_archive: conductor/directives/preserve_before_compact_archive/v1.md +- tdd_red_green_required: conductor/directives/tdd_red_green_required/v1.md +- test_must_fail_for_believed_reason: conductor/directives/test_must_fail_for_believed_reason/v1.md +- test_passing_immediately_proves_nothing: conductor/directives/test_passing_immediately_proves_nothing/v1.md +- test_narrow_not_kitchen_sink: conductor/directives/test_narrow_not_kitchen_sink/v1.md +- batch_verification_not_isolation: conductor/directives/batch_verification_not_isolation/v1.md +- fragile_test_in_batch_is_failing_test: conductor/directives/fragile_test_in_batch_is_failing_test/v1.md +- no_skip_markers_as_avoidance: conductor/directives/no_skip_markers_as_avoidance/v1.md +- ban_arbitrary_core_mocking: conductor/directives/ban_arbitrary_core_mocking/v1.md +- test_instantiation_not_mock_away: conductor/directives/test_instantiation_not_mock_away/v1.md +- adapt_test_mocks_to_production_api_change: conductor/directives/adapt_test_mocks_to_production_api_change/v1.md +- live_gui_poll_not_sleep: conductor/directives/live_gui_poll_not_sleep/v1.md +- live_gui_session_scoped_no_restart: conductor/directives/live_gui_session_scoped_no_restart/v1.md +- no_real_io_during_tests: conductor/directives/no_real_io_during_tests/v1.md +- enforce_no_real_toml_in_tests: conductor/directives/enforce_no_real_toml_in_tests/v1.md +- test_sandbox: conductor/directives/test_sandbox/v1.md +- workspace_paths: conductor/directives/workspace_paths/v1.md +- opt_in_integration_test_via_env_var_marker: conductor/directives/opt_in_integration_test_via_env_var_marker/v1.md +- deterministic_signal_endpoint_pattern: conductor/directives/deterministic_signal_endpoint_pattern/v1.md +- failure_message_actionable_not_vague: conductor/directives/failure_message_actionable_not_vague/v1.md +- three_tier_test_strategy_for_fragile_subsystems: conductor/directives/three_tier_test_strategy_for_fragile_subsystems/v1.md +- test_classification_via_import_presence: conductor/directives/test_classification_via_import_presence/v1.md +- surface_dirty_state_in_test_runner: conductor/directives/surface_dirty_state_in_test_runner/v1.md +- imscope_tuple_return_per_scope_override: conductor/directives/imscope_tuple_return_per_scope_override/v1.md +- tier3_worker_amnesia: conductor/directives/tier3_worker_amnesia/v1.md +- tier4_qa_compressed_fix: conductor/directives/tier4_qa_compressed_fix/v1.md +- token_firewall_prevents_bloat: conductor/directives/token_firewall_prevents_bloat/v1.md +- never_inherit_session_history_to_subagent: conductor/directives/never_inherit_session_history_to_subagent/v1.md +- subagent_returns_artifact_not_transcript: conductor/directives/subagent_returns_artifact_not_transcript/v1.md +- agent_prompt_one_independent_domain: conductor/directives/agent_prompt_one_independent_domain/v1.md +- decompose_or_isolate_never_offload: conductor/directives/decompose_or_isolate_never_offload/v1.md +- worker_three_point_abort_check: conductor/directives/worker_three_point_abort_check/v1.md + +## Non-directive context +Read each file below as full documents. + +- tier2 autonomous guide: docs/guide_tier2_autonomous.md + +## Notes +Compound preset for Tier-2 autonomous sandbox execution. Inherits baseline (57) + adds 20 TARGETED:tier2-sandbox + 23 TARGETED:testing + 8 PROCESS:delegation. Total: 108 directives + 5 non-directive context files (4 inherited + 1 added). This is the preset `tier2-autonomous.warm.md` warms with. +``` + +- [ ] **Step 4: Verify each engagement preset resolves correctly via aggregate** + +Run: `uv run python -c "from pathlib import Path; import sys; sys.path.insert(0, 'scripts'); from aggregate_directives import resolve_inheritance; [print(f'{n}: {len(resolve_inheritance(Path(f\"conductor/directives/presets/{n}.md\")).directives)} directives') for n in ['baseline','audit','fix_tests','implement_feature','refactor','new_script_tool','meta_tooling','directives_curation','documentation','media_analysis','ideation','tier2_autonomous']]"` +Expected: baseline=57, audit=60, fix_tests=82, implement_feature=109, refactor=82, new_script_tool=59, meta_tooling=59, directives_curation=64, documentation=61, media_analysis=59, ideation=65, tier2_autonomous=108. + +- [ ] **Step 5: Commit** + +```bash +git add conductor/directives/presets/media_analysis.md conductor/directives/presets/ideation.md conductor/directives/presets/tier2_autonomous.md +git commit -m "feat(directives): add 3 engagement presets (media_analysis, ideation, tier2_autonomous)" +``` + +--- + +### Task 4.4: Mark current_baseline.md deprecated + +**Files:** +- Modify: `conductor/directives/presets/current_baseline.md` (Notes section only) + +- [ ] **Step 1: Update the Notes section of current_baseline.md** + +In `conductor/directives/presets/current_baseline.md`, replace the `## Notes` section's first line. Find the line starting with `All v1 (verbatim lifts from current production docs;` and prepend a deprecation notice above it: + +Insert at the start of the Notes section (after `## Notes`): + +```markdown +**DEPRECATED (2026-07-05):** This preset is the original control group from the `directive_hotswap_harness_20260627` track. It lists all 172 directives indiscriminately. The curated replacement is `baseline.md` (57 BASELINE directives + 4 non-directive context files). Engagement presets (`audit.md`, `fix_tests.md`, etc.) inherit `baseline.md` and add targeted subsets. This file is RETAINED as the original control group for future A/B encoding experiments — do not delete. New agents should warm with `baseline.md` or an engagement preset, not this file. +``` + +- [ ] **Step 2: Commit** + +```bash +git add conductor/directives/presets/current_baseline.md +git commit -m "docs(directives): mark current_baseline.md deprecated (retained as control group)" +``` + +--- + +## Phase 5: Dedup .warm.md + update bootstrap default + +Focus: Strip the inline bulk-markdown sections from `tier2-autonomous.warm.md` that are now covered by directives. Update the preset path to `tier2_autonomous.md`. Update the bootstrap script's default. + +### Task 5.1: Dedup tier2-autonomous.warm.md + +**Files:** +- Modify: `conductor/tier2/agents/tier2-autonomous.warm.md` + +- [ ] **Step 1: Update the warm-with preset path** + +In `conductor/tier2/agents/tier2-autonomous.warm.md`, find the `manual-slop_aggregate_directives(preset_path="conductor/directives/presets/current_baseline.md")` line and change it to: + +``` +manual-slop_aggregate_directives(preset_path="conductor/directives/presets/tier2_autonomous.md") +``` + +- [ ] **Step 2: Strip the "Hard Bans" section** + +Find the `## Hard Bans (cannot run, enforced at 3 layers)` section and its entire body (including the "THE TIMELINE-IS-IMMUTABLE PRINCIPLE" subsection) and remove it. This content is covered by the `git_hard_bans`, `ban_appdata_paths`, and `timeline_is_immutable` directives. + +- [ ] **Step 3: Strip the "Conventions" section** + +Find the `## Conventions (MUST follow - added 2026-06-17; updated 2026-06-27)` section and remove its bullet points about: test runner, never filter test output, prefer targeted tier runs, default branch, line endings, throw-away scripts, end-of-track report, run-time expectation, temp files. These are covered by `use_batched_test_runner`, `no_output_filtering`, `prefer_targeted_tier_runs`, `master_branch_default`, `preserve_line_endings`, `throwaway_scripts_isolated_subdir`, `end_of_track_report_required` directives. Replace the entire section with a one-line pointer: + +```markdown +## Conventions + +The tier2_autonomous.md preset (warmed above) includes the TARGETED:tier2-sandbox directives that encode all sandbox conventions (batched test runner, no output filtering, targeted tier runs, throw-away script paths, end-of-track report, AppData ban, etc.). Follow them. +``` + +- [ ] **Step 4: Strip the "Sub-Agent Delegation" section** + +Find the `## Sub-Agent Delegation (replaces legacy mma_exec.py — updated 2026-06-27)` section and remove it. Covered by `tier3_worker_amnesia`, `tier4_qa_compressed_fix`, `agent_prompt_one_independent_domain`, `decompose_or_isolate_never_offload` directives. + +- [ ] **Step 5: Strip the "TDD Protocol" section** + +Find the `## TDD Protocol` section and remove it. Covered by `tdd_red_green_required` and `per_phase_metric_regression_fix`. + +- [ ] **Step 6: Strip the "Per-Task Commit Protocol" section** + +Find the `## Per-Task Commit Protocol` section and remove it. Covered by `atomic_per_task_commits` and `verbose_commit_message_ban`. + +- [ ] **Step 7: Keep "Failcount Contract", "Pre-Delegation Checkpoint", and "Limitations" inline** + +Do NOT strip these sections. They contain tier-2-specific operational detail (failcount thresholds, `git add .` safety net, scope limitations) that no directive covers. + +- [ ] **Step 8: Verify the file is syntactically valid markdown + reduced in size** + +Run: `uv run python -c "from pathlib import Path; content = Path('conductor/tier2/agents/tier2-autonomous.warm.md').read_text(encoding='utf-8'); print(f'Size: {len(content)} chars, {content.count(chr(10))} lines')"` +Expected: size significantly reduced from ~17940 chars (target ~6-8KB). + +- [ ] **Step 9: Commit** + +```bash +git add conductor/tier2/agents/tier2-autonomous.warm.md +git commit -m "refactor(tier2): dedup tier2-autonomous.warm.md — strip inline sections covered by directives" +``` + +--- + +### Task 5.2: Update setup_tier2_clone_directives.ps1 default preset + +**Files:** +- Modify: `scripts/tier2/setup_tier2_clone_directives.ps1` + +- [ ] **Step 1: Change the -PresetPath default** + +In `scripts/tier2/setup_tier2_clone_directives.ps1`, find the param block: + +```powershell +param( + [string]$MainRepoPath = "C:\projects\manual_slop", + [string]$Tier2ClonePath = "C:\projects\manual_slop_tier2", + [string]$PresetPath = "conductor/directives/presets/current_baseline.md" +) +``` + +Change the `$PresetPath` default to: + +```powershell + [string]$PresetPath = "conductor/directives/presets/tier2_autonomous.md" +``` + +- [ ] **Step 2: Run the script to verify it works with the new default** + +Run: `& "C:\projects\manual_slop\scripts\tier2\setup_tier2_clone_directives.ps1"` +Expected: bootstrap completes, `[tier2-bootstrap-directives] preset resolved at C:\projects\manual_slop_tier2\conductor\directives\presets\tier2_autonomous.md`. + +- [ ] **Step 3: Commit** + +```bash +git add scripts/tier2/setup_tier2_clone_directives.ps1 +git commit -m "feat(tier2): update setup_tier2_clone_directives.ps1 default preset to tier2_autonomous.md" +``` + +--- + +## Phase 6: Final verification + +Focus: Run the full test suite for the new test file, verify all presets resolve, verify the aggregate tool produces correct output for the new presets. + +### Task 6.1: Run all tests + verify all presets resolve + +- [ ] **Step 1: Run the aggregate_directives preset tests** + +Run: `uv run pytest tests/test_aggregate_directives_presets.py -v` +Expected: all 9 tests PASS. + +- [ ] **Step 2: Verify all 12 presets resolve via the aggregate tool** + +Run: `uv run python -c "from pathlib import Path; import sys; sys.path.insert(0, 'scripts'); from aggregate_directives import aggregate_directives; [aggregate_directives(f'conductor/directives/presets/{n}.md') or print(f'{n}: OK') for n in ['baseline','audit','fix_tests','implement_feature','refactor','new_script_tool','meta_tooling','directives_curation','documentation','media_analysis','ideation','tier2_autonomous']]"` +Expected: 12 lines of `: OK`. + +- [ ] **Step 3: Verify baseline.md returns exactly 57 directives + 4 non-directive context** + +Run: `uv run python -c "from pathlib import Path; import sys; sys.path.insert(0, 'scripts'); from aggregate_directives import resolve_inheritance; s = resolve_inheritance(Path('conductor/directives/presets/baseline.md')); assert len(s.directives) == 57, f'expected 57, got {len(s.directives)}'; assert len(s.non_directive_context) == 4, f'expected 4, got {len(s.non_directive_context)}'; print('baseline: 57 directives + 4 non-directive context OK')"` +Expected: `baseline: 57 directives + 4 non-directive context OK`. + +- [ ] **Step 4: Verify tier2_autonomous.md returns the expected count** + +Run: `uv run python -c "from pathlib import Path; import sys; sys.path.insert(0, 'scripts'); from aggregate_directives import resolve_inheritance; s = resolve_inheritance(Path('conductor/directives/presets/tier2_autonomous.md')); assert len(s.directives) == 108, f'expected 108, got {len(s.directives)}'; assert len(s.non_directive_context) == 5, f'expected 5, got {len(s.non_directive_context)}'; print('tier2_autonomous: 108 directives + 5 non-directive context OK')"` +Expected: `tier2_autonomous: 108 directives + 5 non-directive context OK`. + +- [ ] **Step 5: Verify the .warm.md file is reduced** + +Run: `uv run python -c "from pathlib import Path; content = Path('conductor/tier2/agents/tier2-autonomous.warm.md').read_text(encoding='utf-8'); size = len(content); assert size < 10000, f'expected < 10KB, got {size}'; assert 'tier2_autonomous.md' in content, 'preset path not updated'; assert '## Hard Bans' not in content, 'Hard Bans section not stripped'; assert '## Sub-Agent Delegation' not in content, 'Sub-Agent Delegation not stripped'; print(f'.warm.md: {size} chars OK')"` +Expected: `.warm.md: chars OK`. + +- [ ] **Step 6: Commit the final verification state (if any uncommitted test artifacts)** + +If there are uncommitted test artifacts in `tests/artifacts/_pytest_tmp/`, clean them up: + +```bash +Remove-Item -Recurse -Force tests/artifacts/_pytest_tmp/ -ErrorAction SilentlyContinue +``` + +No commit needed if the working tree is clean. + +--- + +## Self-Review Notes + +**Spec coverage check:** +- G1 (baseline preset) → Task 2.1 ✓ +- G2 (12 engagement presets) → Tasks 4.1-4.3 ✓ +- G3 (preset format extension: Inherits + Non-directive context) → Task 1.2 ✓ +- G4 (aggregate tool extended) → Task 1.2 ✓ +- G5 (15 new directives) → Tasks 3.1-3.5 ✓ +- G6 (.warm.md dedup) → Task 5.1 ✓ +- G7 (current_baseline.md retained, marked deprecated) → Task 4.4 ✓ +- G8 (setup script default updated) → Task 5.2 ✓ +- NFR5 (tags.toml updated) → Task 3.6 ✓ +- V1-V5 (verification) → Task 6.1 ✓ + +**Type consistency check:** `PresetSections` dataclass is used consistently in `parse_preset_sections`, `resolve_inheritance`, and the tests. Field names match: `inherits`, `directives`, `non_directive_context`. + +**No placeholders:** All steps contain complete code. No "TBD", "implement later", "similar to Task N". \ No newline at end of file