diff --git a/AGENTS.md b/AGENTS.md index 84a9fd7f..0edbcc7e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,6 +57,7 @@ The 14 deep-dive guides under `docs/` (`guide_architecture.md`, `guide_ai_client - `set_file_slice` IS valid for multi-line content. The agent must verify the exact byte offsets with `get_file_slice` first, copy the line text character-for-character (including whitespace and EOL), and check whether the edit changes a public contract (function signature, yield shape, return type) that other code depends on. See `conductor/edit_workflow.md` for the full contract. - Do not use `git restore` while a user is mid-conversation without first confirming the desired state - HARD BAN: `git restore`, `git checkout -- `, `git reset` are FORBIDDEN without explicit user permission in the same message. They destroyed user in-progress src/* edits twice in one session (2026-06-07). If you think you need one, ASK FIRST. +- HARD BAN: `git stash*` (any form: `git stash`, `git stash pop`, `git stash apply`, `git stash drop`, `git stash clear`) is FORBIDDEN. Stashing inverts the safety net of the working tree: a `git add .` then `git stash` then "fresh start" pattern is exactly how Tier 2 corrupted files in the 2026-06-27 `cruft_elimination_20260627` track. The user explicitly stated "I hate when people fuck with my commits" — stashing throws away the user's in-progress edits silently. If you think you need a stash, you don't — use a NEW BRANCH or a WORKTREE instead. Tier 2 sandbox enforces this via `conductor/tier2/opencode.json.fragment` bash deny rules. - **HARD BAN: Day estimates in track artifacts (Tier 1).** Do NOT include day / hour / minute estimates in spec.md, plan.md, metadata.json, or any other track artifact. Day estimates are inaccurate noise; Tier 2 capacity is bounded by attention, not time. Measure effort by **scope** (N files, M sites, N tasks). The user / Tier 2 agent decides the actual pacing. See `conductor/workflow.md` §"Tier 1 Track Initialization Rules" for the full rule, replacement patterns, and rationale. (Added 2026-06-16 per user feedback: "Day estimates are inaccurate. Tier-2s can only do so much in a single track and there is no way in hell its going to be 'DAYS'.") - **HARD BAN: Opaque types in non-boundary code (added 2026-06-25).** LLMs default to `dict[str, Any]`, `Any`, `Optional[T]`, `hasattr()` polymorphism, and `.get('field', default)` because that's idiomatic Python training data. **All of these are BANNED in non-boundary code.** Use typed `@dataclass(frozen=True, slots=True)` with explicit fields; use `Result[T]` + `NIL_T` sentinels instead of `Optional[T]`; use direct attribute access instead of `.get()`. The ONLY place `dict[str, Any]` is allowed is the literal wire boundary (TOML/JSON parse functions); 2-3 functions per file. See `conductor/product-guidelines.md` "Core Value", `conductor/code_styleguides/data_oriented_design.md` §8.5 (The Python Type Promotion Mandate), `conductor/code_styleguides/python.md` §17 (LLM Default Anti-Patterns), and `conductor/code_styleguides/type_aliases.md` for the canonical mandates. User direction 2026-06-25: "I want the closest thing to c11/odin/jai in a scripting language... metadata should not be a dict[str, any]." diff --git a/conductor/tier2/agents/tier2-autonomous.md b/conductor/tier2/agents/tier2-autonomous.md index 769e05eb..741b701a 100644 --- a/conductor/tier2/agents/tier2-autonomous.md +++ b/conductor/tier2/agents/tier2-autonomous.md @@ -83,9 +83,35 @@ This gate catches the failure mode in the 2026-06-24 MCP regression where Tier 2 - `git checkout*` (any form) - use `git switch -c` for new branches, `git switch` to switch - `git restore*` (any form) - do not restore files (per AGENTS.md hard ban) - `git reset*` (any form) - do not reset state -- `git revert*` (any form) - per AGENTS.md hard ban; use FIX-IF-FAILS (amend or fixup commit) instead +- `git revert*` (any form) - per AGENTS.md hard ban. **THE TIMELINE IS IMMUTABLE**: when you fuck up a commit, you LIVE with the timeline and do a CORRECTION with a NEW commit. You can grab artifacts, code, or files from old commits via `git show : > ` or `git checkout -- ` (note: `git checkout ` for FILE extraction is allowed; `git checkout ` to switch is BANNED). But you CANNOT reset the branch HEAD to an old commit and pretend the wrong work never happened. The wrong work is part of history now; the fix is a follow-up commit that supersedes it. **NEVER use `git revert`, `git reset --hard`, or `git reset --soft`** to "undo" a bad commit — always go FORWARD with a corrective commit. +- `git stash*` (any form: `git stash`, `git stash pop`, `git stash apply`, `git stash drop`, `git stash clear`) - per AGENTS.md hard ban (added 2026-06-27); stashing throws away the user's in-progress edits silently. If you think you need a stash, you don't - use a NEW BRANCH or a WORKTREE instead. The 2026-06-27 `cruft_elimination_20260627` track was corrupted by Tier 2 using `git stash` and losing the user's in-progress files. - File access outside the Tier 2 clone - the OS blocks it. **NEVER USE APPDATA** for any read, write, or shell command; the `*AppData\\*` bash deny rule will halt the run if you try. +### THE TIMELINE-IS-IMMUTABLE PRINCIPLE (added 2026-06-27, after the cruft_elimination corruption) + +When you (the agent) fuck up — make a wrong commit, break a file, take a bad path — your first instinct will be to "undo" the mistake with `git revert`, `git reset`, or `git stash`. **THIS INSTINCT IS WRONG.** The user explicitly stated: "if an agent fucks up, their tendency to want to 'revert' is not correct and instead they must live with the timeline and just do corrections with a new commit." + +**The rule:** +- The git history is IMMUTABLE on this branch. Every commit you've made is part of the record. +- "Undoing" via `git revert` / `git reset` / `git stash` makes the user's review harder, not easier (the user has to read the diff between the bad and the "fix" to understand what went wrong). +- "Fixing forward" via a new commit makes the user's review EASIER: they can see exactly what changed between the bad commit and the fix. + +**Correct pattern when you fuck up:** +1. Pause. Read the actual file. Confirm the state. +2. Write a NEW commit that fixes the problem. The commit message should briefly say what was wrong and what you fixed. +3. If the bad commit introduced data corruption that the user will see, the user can `git revert` it during their review — that's the user's choice, not yours. +4. If you need to recover an old version of a file (because the bad commit destroyed it), use `git show : > ` to extract it. The bad commit is still in history; you're just reading from history to recover. + +**Wrong pattern (which you must NOT do):** +- `git revert ` to undo a commit +- `git reset --hard ` to throw away a bad commit +- `git stash` to "save" uncommitted work (it just disappears when you lose the branch) +- `git checkout -- .` to "go back to when things were good" (and then commit on top) + +These are all attempts to rewrite history. They are BANNED. The right answer is always a forward commit. + +**Concrete example:** if you realize commit N introduced a bug, write commit N+1 that fixes the bug. The user can see both commits in the diff and understand the full story. The user's CI / reviews / git log will all show both commits, which is what they want. + ## Conventions (MUST follow - added 2026-06-17; updated 2026-06-27) - **Test runner:** ALWAYS use `uv run python scripts/run_tests_batched.py` for test runs. NEVER call `uv run pytest` directly. The batched runner provides tier-based filtering, parallelization (xdist), and a summary table. Direct pytest is slow and bypasses the tiering that the live_gui tests depend on. diff --git a/conductor/tier2/opencode.json.fragment b/conductor/tier2/opencode.json.fragment index 8e0b7d6a..3594b3b6 100644 --- a/conductor/tier2/opencode.json.fragment +++ b/conductor/tier2/opencode.json.fragment @@ -51,7 +51,15 @@ "git push*": "deny", "git checkout*": "deny", "git restore*": "deny", - "git reset*": "deny" + "git reset*": "deny", + "git revert*": "deny", + "git stash*": "deny", + "git stash pop*": "deny", + "git stash apply*": "deny", + "git stash drop*": "deny", + "git stash clear*": "deny", + "git clean -fd*": "deny", + "git clean -fdx*": "deny" } }, "agent": { @@ -82,7 +90,15 @@ "git push*": "deny", "git checkout*": "deny", "git restore*": "deny", - "git reset*": "deny" + "git reset*": "deny", + "git revert*": "deny", + "git stash*": "deny", + "git stash pop*": "deny", + "git stash apply*": "deny", + "git stash drop*": "deny", + "git stash clear*": "deny", + "git clean -fd*": "deny", + "git clean -fdx*": "deny" } } }