feat(0017): undo group transactions — begin/end/rollback, envelope rollback_available, HL 28 - #38
Conversation
Add uv dev toolchain (ruff, basedpyright, pytest), project CI with Node-24-ready Actions, gitignore for local agent/conductor governance, offline smoke tests, and docs/planner-handoff.md for cold-start planners. Includes small gimp_mcp_server typing/format fixes for the new gate.
Document 0001 bootstrap complete, 0002 quality stabilization as next, and the full path through 0028 final product polish.
Full product ruff/format green; scripts layout; setup-uv@v9.0.0; lint.yml retired; planner-handoff policy. Ledger: 83598dee-78b5-4c0a-8975-96a7b5cd15c4
…th jail Track 0003: Class A/B exec gates, AF_INET 127.0.0.1, session auth, path jail, audit. CI green. Codex final PASS WITH DEFERRED P3.
…mapping Visible composite snapshots (dup+merge), image_index, ToolResult structuredContent mapping, temp policy, fail-closed selection/PNG validation. Codex final PASS WITH DEFERRED P3.
* feat(export): add gimp_mcp_export host module + offline alpha tests * fix(export): alpha-preserving merge-on-dup + file-*-export + verify tool * docs: Issue 16 alpha export defaults, install gimp_mcp_export.py * fix(export): recursive alpha preflight + structured MCP errors IR1-01: walk layer groups recursively in preflight/verify_alpha IR1-02: return structured export error dicts from MCP export_image IR1-04: fail-closed when preserve_alpha and drawable unset IR1-05: greps, type-4 PNG fixture, structured-error source tests * fix(export): codex P1/P2 — no silent format fallback, fail-closed RGBA8, batch metadata * fix(export): format README; drop accidental conductor review from tree Keep conductor/ gitignored local-only. Ruff-format README code fences for CI. * docs(0005): mark AlphaExportCorrectness complete in planner handoff Issue 16 closed: merge-on-dup export, IHDR ALPHA_LOST, verify_alpha_channel. Next product track: 0006 StateManifestOrientation (placeholder plan). --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
Schema-versioned orient_workspace state-manifest v1; host finalize; recursive layers; provisional handles; image_index metadata hygiene. Codex engineering PASS WITH DEFERRED P3 (live matrix).
Ledger: f13ebc80-dc77-4722-831e-68b1858c6a0f
…select_* (#6) Stable handle registry: gimp_mcp_handles, process-unique session_epoch, generation tombstones, structural bumps, select_image/select_layers. Codex PASS WITH DEFERRED P3.
Next product track is 0008-CoordinateModelAndExif (placeholder). PR #6 / main@33df2b5 delivered generation registry, STALE_HANDLE, select_*. Ledger: 211b63de-c672-4bfe-9143-007559ba8877 Co-authored-by: Ryan <rbourgoin@gmail.com>
…#8) * feat(0008): CoordinateModelAndExif — coords, mapping, normalize, map_* Ship gimp_mcp_coords as 7th plug-in file (preview/layer math, ordered ORIENTATION_OPS, declaration validate, half-even rounding). Enrich mapping metadata on three paths (build_mapping_metadata + plugin bitmap flatten + server ToolResult pass-through). Add normalize_image_orientation (default assume_pixels_upright; trust_tag opt-in; direct rotate/flip; both EXIF tags; METADATA_WRITE_FAILED; self gen-bump). Session _orientation_normalized synced with gen prune. Host map_* x4. Capability coordinate_exif_normalized true. Ledger: a184eb50-f0d4-42c6-b069-1061eef57ad3 * fix(0008): undo pixel ops when normalize set_metadata fails Call image.undo() after the undo group ends if metadata write fails and trust_tag pixel ops ran, so the canvas is not left rotated with a stale tag. Ledger: a184eb50-f0d4-42c6-b069-1061eef57ad3 * fix(0008): undo on mid-op normalize exceptions (ops_started) Ensure trust_tag pixel ops that raise after partial transform call image.undo() after undo_group_end, not only the metadata-false path. Ledger: a184eb50-f0d4-42c6-b069-1061eef57ad3 * fix(0008): fail-closed gboolean ops, invalid EXIF honesty, plan tests - Check image.flip/rotate and undo_group_* for explicit False - Keep present-but-invalid orientation for honesty; clamp for manifest - plan_normalize_ops offline behavioral tests; README install count Ledger: a184eb50-f0d4-42c6-b069-1061eef57ad3 * fix(0008): fail-closed undo_group_end (no success on False) Do not swallow undo_group_end gboolean False; re-raise body errors after end so generation is never bumped on group-close failure. Ledger: a184eb50-f0d4-42c6-b069-1061eef57ad3 --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
PR #8 / main@8970ad2; Codex PASS WITH DEFERRED P3; next=0009. Co-authored-by: Ryan <rbourgoin@gmail.com>
…kpoints, confirm_destructive (#10) * feat(0009): gimp_mcp_policy + codes + tests + install Ship 8th plug-in file for labels/paths/sidecar/integrity hash; POLICY_DENIED/CONFIRM_REQUIRED/CHECKPOINT_* codes; offline tests; pyproject + README install lists. Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 * feat(0009): Source_Immutable, confirm_destructive, checkpoints - ensure_source_immutable with parasite group + central mutable resolve - confirm_destructive on live flatten/merge/rotate free-angle/resize fill - checkpoint_create/restore with jailed paths + integrity sidecar - orient tattoo/protected; capabilities source_immutable_policy + checkpoints - MCP tools + protocol/README agent intake order Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 * fix(0009): tighten confirm-scope wiring tests and orient-snapshot honesty Pin free-angle / will_flatten branch structure for confirm_destructive. Document include_orient_snapshot=true as note-only (no embedded dump). Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 * fix(0009): address Codex P1/P2 — bool coerce, idempotent ensure, XCF partial - Use export.coerce_bool for confirm_destructive / allow_source_mutation / overwrite - Skip working copies on re-ensure (session set + name suffix); no gen bump on no-op - Save checkpoint XCF via .partial then os.replace; check PDB status + non-empty - Document allow_source_mutation as raw-TCP recovery only (not MCP mutators) Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 * fix(0009): strict coerce_bool + safer working-name skip + restore bools - coerce_bool fail-closed for non-scalar JSON (list/dict → default) - Name-based working skip only when policy group already has children - checkpoint_restore close_prior/verify_hash use coerce_bool Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 * fix(0009): durable Source_Immutable deny via group ancestry + hydrate _assert_mutable also denies descendants of parasite-marked group. Hydrate protected set on ensure, open_image, orient, checkpoint_restore. Strict coerce_bool non-scalar fail-closed already in export. Ledger: 3a04bc4b-8616-4512-9529-40c0f0c9f4d4 --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
…stMCP (#12) * 0010: high-level MCP surface (~18 tools) on real FastMCP Migrate from mcp.server.fastmcp shim to real fastmcp.FastMCP with include_tags + ToolAnnotations. Default surface is 18 HL tools; GIMP_MCP_ADVANCED_TOOLS=1 exposes full advanced surface. Ledger: 5272272a-d519-4e72-9635-d27e3267c1fb * fix(0010): handle-first save/export/verify/close + by_color layer_id Wire plugin mutators through _resolve_image_from_params so HL handle params cannot silently target image 0. Fail closed on explicit layer_id for select_by_color. Strengthen offline handle tests; PROTOCOL design names. Ledger: 5272272a-d519-4e72-9635-d27e3267c1fb * fix(0010): fail-closed prior handle on restore; honest composite index checkpoint_restore close_prior with invalid handle returns STALE/FOREIGN instead of silent skip. Derive open-list image_index after handle resolve for composite mapping. Align create_selection layer_handle docs; tests. Ledger: 5272272a-d519-4e72-9635-d27e3267c1fb --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
Ledger: 5272272a-d519-4e72-9635-d27e3267c1fb Co-authored-by: Ryan <rbourgoin@gmail.com>
…st_id audit (#14) * feat(0011): structured error envelope v1 + request_id audit correlation Implement product error envelope, single-line ToolError wire, CODE matrix (PARTIAL_MUTATION, CONNECTION_FAILED), host/plugin split audit files, and request_id correlation (contextvars host, threading.local plugin). - export_image raises ToolError on ALPHA_LOST (H1; details preserved) - _jail_path_or_raise re-raises SecurityError (H5) - send_command params copy + _request_id; CONNECTION_FAILED on transport - @with_structured_error on all MCP tools; structured_errors capability - docs: PROTOCOL recovery table, SECURITY audit/traceback policy, README Ledger: 6dc55b22-8287-44cf-a6d3-1fbbfb37327a * fix(0011): call_api ToolError path + affected_handles on INTERNAL (M5) Ledger: 6dc55b22-8287-44cf-a6d3-1fbbfb37327a * fix(0011): parse_tool_error_text handles message containing ' | ' Codex P1: rfind alone selected the pipe inside JSON error.message when the human message also contained the delimiter. Try every ' | ' candidate from the right until a valid envelope parses. Regression test added. Ledger: 6dc55b22-8287-44cf-a6d3-1fbbfb37327a --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
…#15) Ledger: 6dc55b22-8287-44cf-a6d3-1fbbfb37327a Co-authored-by: Ryan <rbourgoin@gmail.com>
…t codes (#16) * feat(cli): 0012 gimp-agent doctor probe exit codes Ship host package gimp_agent/ with entrypoint gimp-agent: - argparse CLI: doctor [--strict], probe [--timeout], version, codes - CODE_* / CLI-local → exit 0-12 map + reverse table - path discovery (env/PATH/App Paths/install dirs + GIMP 3.* semver) - doctor ordered checks; probe auth JSON get_gimp_info - JSON envelope (--json / GIMP_AGENT_JSON); offline tests - docs: README CLI section; protocol full exit table * fix(cli): 0012 address review lows (docs, tests, timeout) Document non-strict doctor (exit 0 + ok:false) and probe TIMEOUT→9. Add offline tests for non-strict doctor and TimeoutError path. Remove dead stderr branch in jsonio.emit (human mode stays stdout). * fix(cli): 0012 codex P1/P2 — json flag, probe success, version rc * fix(cli): 0012 env JSON mode + strict JSON for invalid timeout --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
…17) Co-authored-by: Ryan <rbourgoin@gmail.com>
…export (#18) * feat(0013): atomic XCF save and export with collision policy Add gimp_mcp_atomic pure helpers, OUTPUT_COLLISION/VERIFY_FAILED codes, temp+os.replace writers for save_xcf/export_image, CLI save-xcf/export, atomic capabilities true, and 8-file plugin ship set. * docs(0013): fix honesty — atomic save/export and ALPHA_LOST final_intact Remove README non-atomic table claim; align protocol ALPHA_LOST and capabilities with verify-on-temp; fold planner-handoff 0013 notes. Ledger: df79fd18-00cb-4850-84ce-f9d9804d3b90 * fix(0013): flatten export success results (no nested status) Public export_image strips helper status so results match DoD-4 flat manifest. Tests and mocks updated. Ledger: df79fd18-00cb-4850-84ce-f9d9804d3b90 --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
PR #18 / main@5763a69; Codex PASS WITH DEFERRED P3; next=0014. Co-authored-by: Ryan <rbourgoin@gmail.com>
…nly CLI (#20) Host gimp_mcp_verify: PNG defilter 0-4 (Paeth), MAE/max_ae/changed, global SSIM, refine_should_stop, grayscale diff, optional ImageMagick; budgets 50M/500MiB. MCP HL compare_images + verify_artifact (catalog 20); pixel_verification true; alpha_snapshot stays false. CLI gimp-agent compare/verify host-only (no TCP); --spec workspace-jailed; VERIFY_FAILED exit 8. Doctor magick/compare info. Ledger: a5957e9d-3a46-46f2-93fe-4a857a3bcca2 Co-authored-by: Ryan <rbourgoin@gmail.com>
) * feat(0015): recipe registry load/validate + package-data JSON Add gimp_mcp_recipes.py (stdlib JSON registry, whole-value $name interpolation, semver latest, fail-closed load) and five recipes under gimp_agent/recipes/ as setuptools package-data. Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * feat(0015): MCP list_recipes apply_recipe HL 22 Expose list_recipes + apply_recipe as HL tools; catalog 20→22; capability recipe_library=true (batch_interpreter stays false). Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * feat(0015): CLI recipes run batch Add gimp-agent recipes/run/batch with --inputs append, --input-glob, continue-on-fail batch semantics, and exit 12 for unknown recipe ids. Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * test(0015): offline recipe matrix Cover load fail-closed, interpolation, compare-artifacts host, web-export scale with advanced unset, created_paths rollback, batch continue-on-fail, exiftool shell=False, HL 22, and package resources. Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * docs(0015): README protocol recipes Document HL 22, recipe library, CLI recipes/run/batch, and mark 0015 in progress in planner-handoff. Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * fix(0015): rebind output_path after version collision; batch exit 10 Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a * fix(0015): batch collision/params/XOR; load-time defaults; glob safety Ledger: 59d02950-cb04-4591-bac6-e820d18c0e6a --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
PR #22 / main@51adaeb; Codex PASS WITH DEFERRED P3; next focus 0016. Co-authored-by: Ryan <rbourgoin@gmail.com>
…ers[], HL 25 (#24) * feat(0016): NDE DrawableFilter tools — apply/edit/remove, orient filters[], HL 25 * fix(0016): address internal review mediums (error codes, edit order, probe mock, SECURITY) * fix(0016): Codex R1 — HL layer_handle required; UNSUPPORTED on filter new failures * docs(0016): mark NdeFilterTools complete in planner handoff Record HL 25, handle-first NDE tools, offline waiver, and next track 0017. --------- Co-authored-by: Ryan <rbourgoin@gmail.com>
…l rollback pop - Plugin send-path enriches error dicts with rollback_available + transaction_id when an open agent TX exists (DoD-3 / §2.13 honesty) - Dispatch reap resolves layer_handle and other handle-like params - Host contextvar image_id wires open-TX hint for mutator ToolErrors - Partial rollback pops stack after undo_group_end success if undo fails - Prune agent TX stacks in _sync_image_generations for closed images
…path Codex R1: image.undo() gboolean False was treated as success; host open-TX hint could stale-advertise rollback after plugin reap. Plugin SoT on TCP errors; clear host hint on close_image; docs 25→28 HL.
|
Opened against upstream by mistake; product tracks merge to Ryan-AI-Studios/gimp-mcp fork. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (64)
WalkthroughThe PR adds authenticated GIMP MCP transport, structured security and editing policies, visible-composite snapshots, stable handles, checkpoints, filters, transactions, PNG verification, a host CLI, recipes, packaging, CI, documentation, and extensive offline tests. ChangesGIMP MCP platform
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Track 0017-UndoGroupTransactions: agent multi-step undo transactions via GIMP
undo_group_*, honest error-enveloperollback_available/transaction_id, wall-clock timeout force-close, HL 28 tools, and shipgimp_mcp_tx.pyas the 10th plug-in file.Changes
gimp_mcp_tx.py: pure mint/validate/TxStack/reap/recent helpers (EXPECTED Add CodeRabbit configuration for automated code reviews #10 + packaging triad)undo_group_begin/end/rollback(28 total); advanced status/force_closeTX_*→ CLI exit 6; capundo_group_transactions: trueReview
Residual (deferred)
_last_cmd_paramsthread-local for multi-client concurrent enrichTest plan
uv run ruff check .uv run basedpyrightuv run pytest -m "not integration and not slow"Summary by CodeRabbit
New Features
gimp-agentcommand-line interface for diagnostics, authenticated plugin checks, recipes, verification, comparison, and batch processing.Documentation
Tests