diff --git a/graph.fabro b/graph.fabro new file mode 100644 index 000000000..4ab945c04 --- /dev/null +++ b/graph.fabro @@ -0,0 +1,34 @@ +digraph ImplementAndSimplify { + graph [ + goal="Implement and simplify", + model_stylesheet=" + * { backend: api; model: claude-opus-4-6;} + " + ] + rankdir=LR + + start [shape=Mdiamond, label="Start"] + exit [shape=Msquare, label="Exit"] + + toolchain [label="Toolchain", shape=parallelogram, script="command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1", max_retries=0] + preflight_compile [label="Preflight Compile", shape=parallelogram, script="cargo check 2>&1", max_retries=0] + preflight_lint [label="Preflight Lint", shape=parallelogram, script="cargo clippy -- -D warnings 2>&1", max_retries=0] + fix_lints [label="Fix Lints", prompt="The preflight lint step failed. Read the build output from context and fix all clippy lint warnings.", max_visits=3] + implement [label="Implement", prompt="Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan."] + simplify [label="Simplify", prompt="@prompts/simplify.md"] + verify [label="Verify", shape=parallelogram, script="cargo clippy -- -D warnings 2>&1 && cargo test 2>&1", goal_gate=true, retry_target="fixup"] + fixup [label="Fixup", prompt="The verify step failed. Read the build output from context and fix all clippy lint warnings and test failures.", max_visits=3] + + start -> toolchain + toolchain -> preflight_compile [condition="outcome=success"] + toolchain -> exit + preflight_compile -> preflight_lint [condition="outcome=success"] + preflight_compile -> exit + preflight_lint -> implement [condition="outcome=success"] + preflight_lint -> fix_lints + fix_lints -> preflight_lint + implement -> simplify -> verify + verify -> exit [condition="outcome=success"] + verify -> fixup + fixup -> verify +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 000000000..3d27ed4d2 --- /dev/null +++ b/manifest.json @@ -0,0 +1,13 @@ +{ + "run_id": "01KKSVA835XYTBYE18QJ9TWGKX", + "workflow_name": "ImplementAndSimplify", + "goal": "# Plan: Add safeguards to asset collection and checkpoint commits\n\n## Context\n\nComparing our snapshot safeguards to Codex's ghost commits revealed gaps:\n- Asset collection has no file count limit — a run matching thousands of small files will collect them all\n- Asset collection excludes fewer directories than Codex (missing Python venvs, build dirs, caches)\n- Checkpoint commits have no built-in exclude defaults — a fresh run with no config runs `git add -A` on everything that isn't gitignored\n\n## Changes\n\n### 1. Add MAX_FILE_COUNT to asset collection\n\n**File:** `lib/crates/fabro-workflows/src/asset_snapshot.rs`\n\nAdd constant:\n```rust\nconst MAX_FILE_COUNT: usize = 100;\n```\n\nIn `select_files_to_collect()` (line 195), add count check alongside existing size budget check:\n```rust\nif selected.len() >= MAX_FILE_COUNT {\n break;\n}\n```\n\nUpdate existing test `select_files_enforces_total_budget` to verify the count limit doesn't interfere, and add a new test `select_files_enforces_count_limit`.\n\n### 2. Expand EXCLUDE_DIRS for asset collection\n\n**File:** `lib/crates/fabro-workflows/src/asset_snapshot.rs`\n\nAdd missing directories from Codex's list. Current:\n```rust\nconst EXCLUDE_DIRS: &[&str] = &[\n \".git\", \"node_modules\", \".pnpm-store\", \".npm\",\n \"target\", \".next\", \"__pycache__\",\n];\n```\n\nNew (adding 7 entries):\n```rust\nconst EXCLUDE_DIRS: &[&str] = &[\n \".git\", \"node_modules\", \".pnpm-store\", \".npm\",\n \"target\", \".next\", \"__pycache__\",\n \".venv\", \"venv\", \".cache\", \".tox\",\n \".pytest_cache\", \".mypy_cache\", \"dist\",\n];\n```\n\nRationale for each addition:\n- `.venv`, `venv` — Python virtual environments (thousands of files)\n- `.cache` — generic cache dir (pip, pre-commit, etc.)\n- `.tox` — Python tox testing tool virtualenvs\n- `.pytest_cache`, `.mypy_cache` — Python tool caches\n- `dist` — JS/TS build output\n\nNot adding `build` or `env`/`.env` from Codex — `build` is too generic (many projects have legitimate `build/` dirs with test outputs), and `env`/`.env` could be dotenv config files.\n\n### 3. Apply built-in excludes to checkpoint commits\n\n**File:** `lib/crates/fabro-workflows/src/asset_snapshot.rs`\n\nExtract `EXCLUDE_DIRS` into a public constant so it can be shared:\n```rust\npub const EXCLUDE_DIRS: &[&str] = &[ ... ];\n```\n\n**File:** `lib/crates/fabro-workflows/src/engine.rs`\n\nIn `git_checkpoint()`, always include `EXCLUDE_DIRS` as pathspec excludes, merged with user-configured `exclude_globs`. Convert each `EXCLUDE_DIRS` entry to `**/dirname/**` glob format for git pathspec compatibility.\n\nChange at line ~550:\n```rust\nlet mut all_excludes: Vec = asset_snapshot::EXCLUDE_DIRS\n .iter()\n .map(|d| format!(\"**/{d}/**\"))\n .collect();\nall_excludes.extend(exclude_globs.iter().cloned());\nall_excludes.sort();\nall_excludes.dedup();\n\nlet add_cmd = if all_excludes.is_empty() {\n format!(\"{GIT_REMOTE} add -A\")\n} else {\n let pathspecs: Vec = all_excludes\n .iter()\n .map(|g| format!(\"':(glob,exclude){g}'\"))\n .collect();\n format!(\"{GIT_REMOTE} add -A -- . {}\", pathspecs.join(\" \"))\n};\n```\n\nThis means checkpoint commits will always exclude the same directories as asset collection, plus any user-configured globs. The `add_cmd` branch for empty excludes becomes unreachable but can stay for clarity.\n\n## Files to modify\n\n1. `lib/crates/fabro-workflows/src/asset_snapshot.rs` — add MAX_FILE_COUNT, expand EXCLUDE_DIRS, make EXCLUDE_DIRS pub\n2. `lib/crates/fabro-workflows/src/engine.rs` — merge built-in excludes into checkpoint git add\n\n## Approach: Red/Green TDD\n\nFor each change, write the failing test first, then make it pass.\n\n### Step 1: MAX_FILE_COUNT (asset collection)\n\n**Red:** Add test `select_files_enforces_count_limit` in `asset_snapshot.rs` — create 150 small, recent files and assert `select_files_to_collect` returns at most 100. Run tests, verify it fails.\n\n**Green:** Add `const MAX_FILE_COUNT: usize = 100;` and the count check in `select_files_to_collect()`. Run tests, verify it passes.\n\n### Step 2: Expanded EXCLUDE_DIRS (asset collection)\n\n**Red:** Add test `build_find_command_excludes_venv` that asserts the find command contains `.venv` in the prune clause. Run tests, verify it fails.\n\n**Green:** Add the 7 new entries to `EXCLUDE_DIRS`. Run tests, verify it passes.\n\n### Step 3: Built-in excludes for checkpoint commits\n\n**Red:** Add test in `engine.rs` (or appropriate test module) that calls `git_checkpoint` with empty `exclude_globs` and asserts the `git add` command includes pathspec excludes for `EXCLUDE_DIRS` entries (e.g. `node_modules`). Run tests, verify it fails.\n\n**Green:** Make `EXCLUDE_DIRS` pub, merge built-in excludes into the git add command in `git_checkpoint()`. Run tests, verify it passes.\n\n### Final verification\n\n1. `cargo test -p fabro-workflows`\n2. `cargo clippy --workspace -- -D warnings`\n3. `cargo fmt --check --all`\n", + "start_time": "2026-03-15T22:54:25.806108Z", + "node_count": 10, + "edge_count": 13, + "run_branch": "fabro/run/01KKSVA835XYTBYE18QJ9TWGKX", + "base_sha": "742f02bb26937cf6df250c5500c78e1f36a44f96", + "base_branch": "main", + "workflow_slug": "implement", + "host_repo_path": "/Users/bhelmkamp/p/fabro-sh/fabro" +} \ No newline at end of file diff --git a/sandbox.json b/sandbox.json new file mode 100644 index 000000000..b198de59f --- /dev/null +++ b/sandbox.json @@ -0,0 +1,5 @@ +{ + "provider": "daytona", + "working_directory": "/home/daytona/workspace", + "identifier": "fabro-01KKSVA835XYTBYE18QJ9TWGKX" +} \ No newline at end of file