diff --git a/conductor/directives/adapt_test_not_skip_test/meta.md b/conductor/directives/adapt_test_not_skip_test/meta.md new file mode 100644 index 00000000..3a317332 --- /dev/null +++ b/conductor/directives/adapt_test_not_skip_test/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/adapt_test_not_skip_test/v1.md b/conductor/directives/adapt_test_not_skip_test/v1.md new file mode 100644 index 00000000..36867313 --- /dev/null +++ b/conductor/directives/adapt_test_not_skip_test/v1.md @@ -0,0 +1,30 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/audit_script_as_gate/meta.md b/conductor/directives/audit_script_as_gate/meta.md new file mode 100644 index 00000000..7287ee11 --- /dev/null +++ b/conductor/directives/audit_script_as_gate/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/audit_script_as_gate/v1.md b/conductor/directives/audit_script_as_gate/v1.md new file mode 100644 index 00000000..1ec9c2ef --- /dev/null +++ b/conductor/directives/audit_script_as_gate/v1.md @@ -0,0 +1,32 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/audit_walks_filesystem_fresh/meta.md b/conductor/directives/audit_walks_filesystem_fresh/meta.md new file mode 100644 index 00000000..3d676ec1 --- /dev/null +++ b/conductor/directives/audit_walks_filesystem_fresh/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/audit_walks_filesystem_fresh/v1.md b/conductor/directives/audit_walks_filesystem_fresh/v1.md new file mode 100644 index 00000000..c643348b --- /dev/null +++ b/conductor/directives/audit_walks_filesystem_fresh/v1.md @@ -0,0 +1,24 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/baseline_capture_before_work/meta.md b/conductor/directives/baseline_capture_before_work/meta.md new file mode 100644 index 00000000..0c34bb5a --- /dev/null +++ b/conductor/directives/baseline_capture_before_work/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/baseline_capture_before_work/v1.md b/conductor/directives/baseline_capture_before_work/v1.md new file mode 100644 index 00000000..51017a29 --- /dev/null +++ b/conductor/directives/baseline_capture_before_work/v1.md @@ -0,0 +1,25 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/directive_one_concept_per_file/meta.md b/conductor/directives/directive_one_concept_per_file/meta.md new file mode 100644 index 00000000..d28c4942 --- /dev/null +++ b/conductor/directives/directive_one_concept_per_file/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/directive_one_concept_per_file/v1.md b/conductor/directives/directive_one_concept_per_file/v1.md new file mode 100644 index 00000000..f3880de6 --- /dev/null +++ b/conductor/directives/directive_one_concept_per_file/v1.md @@ -0,0 +1,14 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/doc_update_after_track_ships/meta.md b/conductor/directives/doc_update_after_track_ships/meta.md new file mode 100644 index 00000000..67831c19 --- /dev/null +++ b/conductor/directives/doc_update_after_track_ships/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/doc_update_after_track_ships/v1.md b/conductor/directives/doc_update_after_track_ships/v1.md new file mode 100644 index 00000000..7a93428b --- /dev/null +++ b/conductor/directives/doc_update_after_track_ships/v1.md @@ -0,0 +1,14 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/ideation_leads_with_recommended/meta.md b/conductor/directives/ideation_leads_with_recommended/meta.md new file mode 100644 index 00000000..75c27f30 --- /dev/null +++ b/conductor/directives/ideation_leads_with_recommended/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/ideation_leads_with_recommended/v1.md b/conductor/directives/ideation_leads_with_recommended/v1.md new file mode 100644 index 00000000..e196c5fe --- /dev/null +++ b/conductor/directives/ideation_leads_with_recommended/v1.md @@ -0,0 +1,14 @@ +# 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 is 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 are structured choices, not ideation) \ No newline at end of file diff --git a/conductor/directives/media_analysis_neutral_voice/meta.md b/conductor/directives/media_analysis_neutral_voice/meta.md new file mode 100644 index 00000000..7c1efab1 --- /dev/null +++ b/conductor/directives/media_analysis_neutral_voice/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/media_analysis_neutral_voice/v1.md b/conductor/directives/media_analysis_neutral_voice/v1.md new file mode 100644 index 00000000..f870d5f6 --- /dev/null +++ b/conductor/directives/media_analysis_neutral_voice/v1.md @@ -0,0 +1,14 @@ +# 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 is 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) \ No newline at end of file diff --git a/conductor/directives/media_source_cited_in_output/meta.md b/conductor/directives/media_source_cited_in_output/meta.md new file mode 100644 index 00000000..8e09726a --- /dev/null +++ b/conductor/directives/media_source_cited_in_output/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/media_source_cited_in_output/v1.md b/conductor/directives/media_source_cited_in_output/v1.md new file mode 100644 index 00000000..57fec907 --- /dev/null +++ b/conductor/directives/media_source_cited_in_output/v1.md @@ -0,0 +1,14 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/meta_tooling_no_app_imports/meta.md b/conductor/directives/meta_tooling_no_app_imports/meta.md new file mode 100644 index 00000000..86418f75 --- /dev/null +++ b/conductor/directives/meta_tooling_no_app_imports/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/meta_tooling_no_app_imports/v1.md b/conductor/directives/meta_tooling_no_app_imports/v1.md new file mode 100644 index 00000000..eed8f404 --- /dev/null +++ b/conductor/directives/meta_tooling_no_app_imports/v1.md @@ -0,0 +1,14 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/refactor_one_subsystem_per_phase/meta.md b/conductor/directives/refactor_one_subsystem_per_phase/meta.md new file mode 100644 index 00000000..2a6a68af --- /dev/null +++ b/conductor/directives/refactor_one_subsystem_per_phase/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/refactor_one_subsystem_per_phase/v1.md b/conductor/directives/refactor_one_subsystem_per_phase/v1.md new file mode 100644 index 00000000..83cd1d93 --- /dev/null +++ b/conductor/directives/refactor_one_subsystem_per_phase/v1.md @@ -0,0 +1,25 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/refactor_preserves_behavior/meta.md b/conductor/directives/refactor_preserves_behavior/meta.md new file mode 100644 index 00000000..28f49216 --- /dev/null +++ b/conductor/directives/refactor_preserves_behavior/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/refactor_preserves_behavior/v1.md b/conductor/directives/refactor_preserves_behavior/v1.md new file mode 100644 index 00000000..a74798f1 --- /dev/null +++ b/conductor/directives/refactor_preserves_behavior/v1.md @@ -0,0 +1,26 @@ +# 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 is 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 \ No newline at end of file diff --git a/conductor/directives/regression_bisect_to_clean_baseline/meta.md b/conductor/directives/regression_bisect_to_clean_baseline/meta.md new file mode 100644 index 00000000..7aaa3e40 --- /dev/null +++ b/conductor/directives/regression_bisect_to_clean_baseline/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/regression_bisect_to_clean_baseline/v1.md b/conductor/directives/regression_bisect_to_clean_baseline/v1.md new file mode 100644 index 00000000..56a1331c --- /dev/null +++ b/conductor/directives/regression_bisect_to_clean_baseline/v1.md @@ -0,0 +1,29 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/scripts_audit_pattern/meta.md b/conductor/directives/scripts_audit_pattern/meta.md new file mode 100644 index 00000000..3e47957e --- /dev/null +++ b/conductor/directives/scripts_audit_pattern/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/scripts_audit_pattern/v1.md b/conductor/directives/scripts_audit_pattern/v1.md new file mode 100644 index 00000000..ea9857f5 --- /dev/null +++ b/conductor/directives/scripts_audit_pattern/v1.md @@ -0,0 +1,19 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/scripts_namespace_isolated/meta.md b/conductor/directives/scripts_namespace_isolated/meta.md new file mode 100644 index 00000000..8539cf1c --- /dev/null +++ b/conductor/directives/scripts_namespace_isolated/meta.md @@ -0,0 +1,9 @@ +# 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 \ No newline at end of file diff --git a/conductor/directives/scripts_namespace_isolated/v1.md b/conductor/directives/scripts_namespace_isolated/v1.md new file mode 100644 index 00000000..4f725349 --- /dev/null +++ b/conductor/directives/scripts_namespace_isolated/v1.md @@ -0,0 +1,23 @@ +# 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 are 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; do not split for modularity \ No newline at end of file diff --git a/conductor/directives/tags.toml b/conductor/directives/tags.toml index 95603b14..346660ad 100644 --- a/conductor/directives/tags.toml +++ b/conductor/directives/tags.toml @@ -551,3 +551,50 @@ tags = ["python", "editing", "all-tiers", "threading", "mandatory", "lifted-from [directive.workspace_paths] tags = ["python", "testing", "all-tiers", "styleguide", "mandatory", "lifted-from-code_styleguides.workspace_paths.md"] + +# 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"] \ No newline at end of file