Skip to content

Issue #99 Phase 1: add exstruct.edit public edit API#102

Merged
harumiWeb merged 5 commits intomainfrom
feat/edit-core
Mar 15, 2026
Merged

Issue #99 Phase 1: add exstruct.edit public edit API#102
harumiWeb merged 5 commits intomainfrom
feat/edit-core

Conversation

@harumiWeb
Copy link
Owner

@harumiWeb harumiWeb commented Mar 15, 2026

Summary

Acceptance Criteria

  • AC-01: Invalid non-object / non-string patch ops fail with indexed ValueError instead of leaking AttributeError.
  • AC-02: Top-level sheet fallback applies to JSON-string ops as well as dict ops.
  • AC-03: PatchToolInput / MakeToolInput and an MCP server caller path are covered by regression tests for the JSON-string + top-level sheet flow.
  • AC-04: ADR-0006 status is synchronized across the ADR body and all ADR index artifacts.
  • AC-05: New exstruct.edit modules include the missing module docstrings added in this PR.
  • AC-06: Phase 1 scope remains the same: no CLI work and no patch/result contract change.

Validation

  • uv run pytest tests/mcp/patch/test_normalize.py tests/mcp/test_tool_models.py tests/mcp/test_server.py -q
  • uv run task precommit-run
  • Updated ADR metadata and task tracking for the review follow-up.

Refs #99

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced public Python API for workbook editing via exstruct.edit with patch_workbook() and make_workbook() functions
    • Added comprehensive schema discovery tools and normalization utilities for patch operations
    • Exposed chart type handling and alignment/formatting support in the public API surface
  • Documentation

    • Updated architecture documentation with new public editing API specification
    • Added editing API reference guide with usage examples and schema information
    • Enhanced MCP documentation to clarify relationship with public editing layer

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

Adds a first-class public workbook editing API under exstruct.edit (phase 1): new modules, public entry points patch_workbook and make_workbook, normalization and schema artifacts, re-exports in MCP modules for compatibility, ADR and docs updates, and tests validating the new public surface. Underlying patch execution pipeline unchanged.

Changes

Cohort / File(s) Summary
Architecture & ADRs
dev-docs/adr/ADR-0006-public-edit-api-and-host-boundary.md, dev-docs/adr/README.md, dev-docs/adr/decision-map.md, dev-docs/adr/index.yaml
Adds ADR-0006 and updates ADR index/decision map documenting the public edit API and host-owned safety boundary.
Docs & Specs
dev-docs/specs/editing-api.md, dev-docs/specs/data-model.md, dev-docs/architecture/overview.md, docs/api.md, docs/mcp.md, tasks/feature_spec.md, tasks/todo.md
New editing API spec and data-model adjustments, architecture overview updates to surface exstruct.edit, and documentation/task tracking for phase 1.
Public edit package
src/exstruct/edit/__init__.py, src/exstruct/edit/api.py, src/exstruct/edit/service.py, src/exstruct/edit/models.py, src/exstruct/edit/types.py, src/exstruct/edit/specs.py, src/exstruct/edit/normalize.py, src/exstruct/edit/op_schema.py, src/exstruct/edit/chart_types.py, src/exstruct/edit/errors.py
Creates exstruct.edit package exposing public API (patch_workbook, make_workbook), types, normalization, op schemas, specs, chart-type utilities, and re-exported models/errors.
MCP re-exports / refactor
src/exstruct/mcp/op_schema.py, src/exstruct/mcp/patch/chart_types.py, src/exstruct/mcp/patch/normalize.py, src/exstruct/mcp/patch/specs.py, src/exstruct/mcp/patch/types.py
Replaces local implementations with imports from exstruct.edit and re-exports them to preserve MCP public surface while sourcing implementations from the new edit layer.
Tests
tests/edit/test_api.py, tests/mcp/patch/test_normalize.py, tests/mcp/test_server.py, tests/mcp/test_tool_models.py
Adds tests for the public edit API (patch/make flows, schema exposure) and additional normalization/top-level-sheet JSON-string handling tests.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant EditAPI as exstruct.edit.service
  participant MCP as exstruct.mcp.patch_runner
  participant Backend as PatchEngine (com/openpyxl)

  Client->>EditAPI: call patch_workbook(PatchRequest)
  EditAPI->>MCP: delegate to run_patch(request, policy=None)
  MCP->>Backend: execute patch ops (apply ops, engine selection)
  Backend-->>MCP: PatchResult (diffs, errors)
  MCP-->>EditAPI: PatchResult
  EditAPI-->>Client: PatchResult
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related issues

Possibly related PRs

  • Feat/mcp chart #68 — Overlaps on chart-type utilities and their tests; changes here centralize chart types under exstruct.edit.
  • Feat/design edit mcp #65 — Related refactor/relocation of op/schema/normalize/specs/types; strong code‑level overlap.
  • Feat/edit mcp #57 — Prior MCP patch/schema/normalize infrastructure that this PR promotes and re-exports from the edit layer.

Suggested labels

enhancement

Poem

🐰 I hopped and found a tidy door,

exstruct.edit now leads the floor.
patch_workbook, make_workbook—a pair,
MCP watches from the stair.
A carrot cheer for code made clear.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: promoting exstruct.edit as the Phase 1 public editing API for issue #99, which aligns with the primary objective described in the PR.
Description check ✅ Passed The PR description includes a clear summary, comprehensive acceptance criteria (6 items all checked), specific validation steps performed, and issue reference, covering the core requirements despite using a different structure than the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/edit-core
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

This comment was marked as resolved.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/mcp/test_server.py (1)

1033-1073: Consider extracting common fake functions into pytest fixtures.

The fake function setup (fake_run_extract_tool, fake_run_read_json_chunk_tool, etc.) is repeated across many tests in this file. A shared fixture could reduce duplication and improve maintainability.

💡 Example fixture approach
`@pytest.fixture`
def mocked_server_tools(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
    """Fixture providing mocked server tools with call tracking."""
    calls: dict[str, tuple[object, ...]] = {}
    
    def fake_run_patch_tool(
        payload: PatchToolInput,
        *,
        policy: PathPolicy,
        on_conflict: OnConflictPolicy,
    ) -> PatchToolOutput:
        calls["patch"] = (payload, policy, on_conflict)
        return PatchToolOutput(out_path="out.xlsx", patch_diff=[], engine="openpyxl")
    
    # ... additional fake functions ...
    
    monkeypatch.setattr(server, "run_patch_tool", fake_run_patch_tool)
    # ... additional monkeypatches ...
    
    return calls
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/mcp/test_server.py` around lines 1033 - 1073, The repeated fake tool
functions (fake_run_extract_tool, fake_run_read_json_chunk_tool,
fake_run_validate_input_tool, fake_run_patch_tool) and monkeypatch.setattr calls
should be consolidated into a pytest fixture (e.g., mocked_server_tools) that
registers those fakes and monkeypatches server.run_* and
anyio.to_thread.run_sync once, returns a calls dict for assertions, and is used
by tests instead of duplicating the setup; update tests to accept the fixture
and remove the inline fake_* functions and monkeypatch.setattr calls so all
mocks (including fake_run_patch_tool and run_sync replacement) are centralized
and reusable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/mcp/test_server.py`:
- Around line 1033-1073: The repeated fake tool functions
(fake_run_extract_tool, fake_run_read_json_chunk_tool,
fake_run_validate_input_tool, fake_run_patch_tool) and monkeypatch.setattr calls
should be consolidated into a pytest fixture (e.g., mocked_server_tools) that
registers those fakes and monkeypatches server.run_* and
anyio.to_thread.run_sync once, returns a calls dict for assertions, and is used
by tests instead of duplicating the setup; update tests to accept the fixture
and remove the inline fake_* functions and monkeypatch.setattr calls so all
mocks (including fake_run_patch_tool and run_sync replacement) are centralized
and reusable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea8d930b-7a3d-4ac3-82c2-b2018849e8cb

📥 Commits

Reviewing files that changed from the base of the PR and between 7560433 and a576f73.

📒 Files selected for processing (15)
  • dev-docs/adr/README.md
  • dev-docs/adr/decision-map.md
  • dev-docs/adr/index.yaml
  • dev-docs/architecture/overview.md
  • dev-docs/specs/data-model.md
  • src/exstruct/edit/chart_types.py
  • src/exstruct/edit/normalize.py
  • src/exstruct/edit/op_schema.py
  • src/exstruct/edit/specs.py
  • src/exstruct/edit/types.py
  • tasks/feature_spec.md
  • tasks/todo.md
  • tests/mcp/patch/test_normalize.py
  • tests/mcp/test_server.py
  • tests/mcp/test_tool_models.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • dev-docs/adr/README.md
  • src/exstruct/edit/types.py

@harumiWeb harumiWeb merged commit 68521f5 into main Mar 15, 2026
12 checks passed
@harumiWeb harumiWeb deleted the feat/edit-core branch March 15, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants