-
Notifications
You must be signed in to change notification settings - Fork 21
Issue #99 Phase 1: add exstruct.edit public edit API #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
dev-docs/adr/ADR-0006-public-edit-api-and-host-boundary.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # ADR-0006: Public Edit API and Host-Owned Safety Boundary | ||
|
|
||
| ## Status | ||
|
|
||
| `accepted` | ||
|
|
||
| ## Background | ||
|
|
||
| ExStruct already had a capable workbook editing pipeline, but it was reachable | ||
| primarily through MCP-facing modules such as `exstruct.mcp.patch_runner` and the | ||
| `exstruct_patch` / `exstruct_make` tool handlers. That made normal Python usage | ||
| awkward and blurred the boundary between editing behavior and host-owned safety | ||
| policy. | ||
|
|
||
| The issue is not only discoverability. The MCP layer also owns path sandboxing, | ||
| artifact mirroring, and server execution concerns that should not be mandatory | ||
| for ordinary library callers. At the same time, existing patch models, backend | ||
| selection rules, and warning/error payloads are already tested and should remain | ||
| stable while the public surface is promoted. | ||
|
|
||
| ## Decision | ||
|
|
||
| - `exstruct.edit` is adopted as the first-class public Python API for workbook | ||
| editing. | ||
| - Phase 1 public entry points are `patch_workbook(PatchRequest)` and | ||
| `make_workbook(MakeRequest)`. | ||
| - The existing patch contract is preserved for Phase 1: | ||
| - `PatchOp`, `PatchRequest`, `MakeRequest`, `PatchResult` | ||
| - op names | ||
| - normalization behavior | ||
| - schema-discovery metadata | ||
| - backend warning/error payload shape | ||
| - MCP remains a host/integration layer. It continues to own: | ||
| - `PathPolicy` | ||
| - MCP tool input/output mapping | ||
| - artifact mirroring | ||
| - server defaults, thread offloading, and runtime controls | ||
| - Phase 1 may reuse the proven `exstruct.mcp.patch.*` execution pipeline under | ||
| the hood while `exstruct.edit` becomes the canonical public import path. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Python callers now have a direct, library-oriented entry point that does not | ||
| require MCP-specific path restrictions. | ||
| - MCP compatibility remains intact because the old import paths stay available. | ||
| - Operation schemas and alias normalization can now be treated as part of the | ||
| public editing surface, not only MCP documentation. | ||
| - The transition keeps two module trees in play during Phase 1, which is less | ||
| clean than a full implementation relocation but materially reduces risk while | ||
| the new public surface is established. | ||
| - Future phases can move more execution internals under `exstruct.edit` without | ||
| reopening the public contract question. | ||
|
|
||
| ## Rationale | ||
|
|
||
| - Tests: | ||
| - `tests/edit/test_api.py` | ||
| - `tests/mcp/patch/test_normalize.py` | ||
| - `tests/mcp/test_patch_runner.py` | ||
| - `tests/mcp/test_make_runner.py` | ||
| - `tests/mcp/patch/test_service.py` | ||
| - `tests/mcp/test_tools_handlers.py` | ||
| - Code: | ||
| - `src/exstruct/edit/__init__.py` | ||
| - `src/exstruct/edit/api.py` | ||
| - `src/exstruct/edit/service.py` | ||
| - `src/exstruct/mcp/patch_runner.py` | ||
| - `src/exstruct/mcp/tools.py` | ||
| - Related specs: | ||
| - `dev-docs/specs/editing-api.md` | ||
| - `dev-docs/specs/data-model.md` | ||
| - `docs/api.md` | ||
| - `docs/mcp.md` | ||
|
|
||
| ## Supersedes | ||
|
|
||
| - None | ||
|
|
||
| ## Superseded by | ||
|
|
||
| - None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Editing API Specification | ||
|
|
||
| This document defines the Phase 1 public editing contract exposed from | ||
| `exstruct.edit`. | ||
|
|
||
| ## Public import path | ||
|
|
||
| - Primary public package: `exstruct.edit` | ||
| - Primary functions: | ||
| - `patch_workbook(request: PatchRequest) -> PatchResult` | ||
| - `make_workbook(request: MakeRequest) -> PatchResult` | ||
| - Primary public models: | ||
| - `PatchOp` | ||
| - `PatchRequest` | ||
| - `MakeRequest` | ||
| - `PatchResult` | ||
| - `PatchDiffItem` | ||
| - `PatchErrorDetail` | ||
| - `FormulaIssue` | ||
|
|
||
| ## Phase 1 guarantees | ||
|
|
||
| - Python callers can edit workbooks through `exstruct.edit` without providing | ||
| MCP-specific `PathPolicy` restrictions. | ||
| - The patch operation vocabulary, field names, defaults, warnings, and error | ||
| payload shapes remain aligned with the existing MCP patch contract. | ||
| - `exstruct.edit` exposes the same operation normalization and schema metadata | ||
| used by MCP: | ||
| - `coerce_patch_ops` | ||
| - `resolve_top_level_sheet_for_payload` | ||
| - `list_patch_op_schemas` | ||
| - `get_patch_op_schema` | ||
| - Existing MCP compatibility imports remain valid: | ||
| - `exstruct.mcp.patch_runner` | ||
| - `exstruct.mcp.patch.normalize` | ||
| - `exstruct.mcp.patch.specs` | ||
| - `exstruct.mcp.op_schema` | ||
|
|
||
| ## Host-only responsibilities | ||
|
|
||
| The following behaviors are not part of the Python editing API contract and | ||
| remain owned by MCP / agent hosts: | ||
|
|
||
| - `PathPolicy` root restrictions and deny-glob enforcement | ||
| - MCP tool input/output models and transport mapping | ||
| - artifact mirroring for MCP hosts | ||
| - server-level defaults such as `--on-conflict` | ||
| - thread offloading, timeouts, and confirmation flows | ||
|
|
||
| ## Current implementation boundary | ||
|
|
||
| - Phase 1 promotes `exstruct.edit` as the canonical public import path. | ||
| - The implementation intentionally reuses the existing patch execution pipeline | ||
| under `exstruct.mcp.patch.*` to avoid destabilizing the tested backend logic | ||
| during the API promotion. | ||
| - Contract metadata moved to `exstruct.edit` in Phase 1: | ||
| - patch op types | ||
| - chart type metadata | ||
| - patch op alias/spec metadata | ||
| - public op schema discovery | ||
|
|
||
| ## Explicit non-goals for Phase 1 | ||
|
|
||
| - No top-level `from exstruct import patch_workbook` export | ||
| - No new CLI subcommands | ||
| - No op renaming (`set_value` remains the public op name) | ||
| - No change to backend selection or fallback policy | ||
| - No change to `PatchResult` shape |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.