Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions docs/mutation-change-checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Mutation Change Checklist

Use this before changing any production mutation path in FocusRelay.

Scope:
- Future mutation logic in `Plugin/FocusRelayBridge.omnijs/Resources/BridgeLibrary.js`
- Future mutation logic in `Sources/OmniFocusAutomation/OmniFocusAutomation.swift`
- Future shared mutation models and services
- Future CLI and MCP mutation command wiring

## 1. Freeze The Contract First

Before coding, write down:
- the documented Omni Automation write APIs the change is allowed to use
- the exact public tool or CLI shape being introduced or modified
- whether the mutation is a patch, lifecycle transition, or move
- the validation and failure semantics
- whether cache invalidation is required after success

Reference:
- [`docs/omni-automation-write-contract.md`](./omni-automation-write-contract.md)

Minimum invariant list:
- v1 writes are homogeneous bulk only
- v1 writes target IDs only
- `update_*` is field patch only
- `set_*_completion` owns completion lifecycle
- `set_projects_status` owns project active/on-hold/dropped transitions
- `move_*` owns structural location changes
- successful writes invalidate cached `list_projects` and `list_tags`

## 2. Confirm The Official API Surface

Before implementation, verify that every production write API used by the change is documented on the official Omni Automation site.

Examples of approved v1 references:
- task fields such as `name`, `note`, `flagged`, `estimatedMinutes`, `dueDate`, `deferDate`
- task functions such as `appendStringToNote(...)`, `addTag(...)`, `addTags(...)`, `removeTag(...)`, `markComplete(...)`, `markIncomplete()`
- project fields such as `name`, `flagged`, `containsSingletonActions`, `sequential`, `status`, `reviewInterval`, `dueDate`, `deferDate`
- project functions such as `appendStringToNote(...)`, `addTag(...)`, `addTags(...)`, `removeTag(...)`, `markComplete(...)`, `markIncomplete()`
- database functions such as `moveTasks(...)` and `moveSections(...)`

If the docs are ambiguous:
- keep it out of scope
- document the ambiguity
- do not ship a speculative production path

## 3. Add Semantic Tripwire Tests

Add tests for the exact boundary or contract risk introduced by the mutation change.

Minimum categories:
- valid mutation success
- invalid ID handling
- preview-only behavior
- verify readback behavior
- CLI and MCP parity for request/response semantics

Add focused coverage when applicable:
- repeating task completion
- repeating project completion
- move destination validation
- task tag add/remove/set behavior
- project status transitions between `active`, `on_hold`, and `dropped`
- cache invalidation after a successful write

## 4. Validate Safety Boundaries

Before merge, verify:
- bulk writes remain homogeneous
- no name-based mutation targeting was introduced
- no hidden mixed-operation batch behavior was added
- preview paths do not mutate data
- verify paths do not silently hide mutation failures
- error responses remain structured and actionable

For bulk writes:
- require explicit user-facing confirmation behavior at the tool layer when the later implementation issue adds it
- do not add partial-success semantics casually

## 5. Keep CLI And MCP On One Shared Core

Before merge, verify:
- request models are shared
- validation rules are shared
- result semantics are shared
- cache invalidation is triggered from the shared mutation layer, not duplicated in frontends

Do not:
- implement one behavior for CLI and a different one for MCP
- duplicate mutation logic in separate transports unless a later issue explicitly isolates that experiment

## 6. Verify The Read-After-Write Contract

For every mutation tool, define the post-write readback rule up front:
- what fields are returned by default
- what fields are returned only when `returnFields` is set
- when `verify=true` is required or recommended
- which read path is used to confirm the mutation

Minimum readback invariants:
- the target ID remains stable after non-repeating updates and moves
- completion/status tools report the final lifecycle state accurately
- repeating completion tools document and verify the returned object identity behavior
- cache invalidation prevents stale `list_projects` and `list_tags` responses after success

## 7. Update Docs Before Shipping

Before merge, make sure:
- public docs reflect the exact tool names and schemas
- examples show both single-item and homogeneous-bulk usage
- docs explain the split between patch vs lifecycle vs move tools
- docs state what is intentionally out of scope for v1

If the change alters install, approval, or restart behavior:
- validate the full user-facing flow in plain language docs

## 8. Define The Acceptance Rule Up Front

A mutation change is not done because the code compiles.

Write down the acceptance rule before implementation:
- `swift test` passes
- mutation tripwire tests cover the new boundary
- preview and verify semantics are correct
- CLI and MCP parity holds
- cache invalidation behaves correctly after success
- docs and examples match the shipped schema

If any of those fail:
- revert the change
- narrow the scope
- or split the work into a smaller issue
169 changes: 169 additions & 0 deletions docs/omni-automation-write-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# Omni Automation Write Contract

This document defines the Omni Automation APIs and product rules that are allowed in FocusRelay v1 mutation paths.

Scope:
- Any future task or project mutation helper in `Plugin/FocusRelayBridge.omnijs/Resources/BridgeLibrary.js`
- Any future mutation helper in `Sources/OmniFocusAutomation/OmniFocusAutomation.swift`
- Any future shared mutation core used by CLI and MCP

Workflow companion:
- [`docs/mutation-change-checklist.md`](./mutation-change-checklist.md)

Primary source:
- [OmniFocus Omni Automation index](https://omni-automation.com/omnifocus/index.html)

Relevant reference pages:
- [Database](https://omni-automation.com/omnifocus/database.html)
- [Project](https://omni-automation.com/omnifocus/project.html)
- [Task](https://omni-automation.com/omnifocus/task.html)

## Rules
- Use only documented Omni Automation APIs in production mutation paths.
- If an API or mutation pattern is not documented on the official site, do not make it part of the default write path.
- Keep CLI and MCP mutation semantics aligned to one shared contract.
- v1 mutations are homogeneous bulk only: one call, one operation kind, one patch or destination or state applied to all passed IDs.
- v1 mutations are ID-only. Name lookup remains a read-side concern.
- `update_*` is for field patches only.
- `set_*_completion` owns completion lifecycle transitions.
- `set_projects_status` owns project status transitions.
- `move_*` owns structural location changes.
- Successful mutations must invalidate cached `list_projects` and `list_tags` results before later reads.

## Locked V1 Public Surface

### Task tools
- `update_tasks`
- `set_tasks_completion`
- `move_tasks`

### Project tools
- `update_projects`
- `set_projects_status`
- `set_projects_completion`
- `move_projects`

## Shared Request Semantics

### Targeting
- Inputs target existing objects by ID only.
- A request fails validation if any referenced ID cannot be resolved.
- v1 does not support name-based mutation targeting or fuzzy matching.

### Bulk behavior
- All targets in one request receive the same operation.
- v1 does not support mixed-operation batches such as “complete these, move those, patch those others.”
- Single-item CLI and MCP commands should reuse the same bulk-capable internal models.

### Preview and verification
- `previewOnly=true` validates and resolves targets without mutating OmniFocus.
- `verify=true` performs a post-write readback using the documented read path and returns the resolved post-state.
- `returnFields` is opt-in and limits post-write payload shape.
- Mutation tools should default to compact result summaries rather than full object payloads.

### Failure semantics
- Validation failures should be reported before any mutation is attempted.
- Errors must be structured and actionable.
- v1 should prefer all-or-nothing behavior for one homogeneous request unless a later issue explicitly introduces partial success semantics.

## Allowed Documented Mutation Surfaces

### Task field patches
- `task.name`
- `task.note`
- `task.appendStringToNote(...)`
- `task.flagged`
- `task.estimatedMinutes`
- `task.dueDate`
- `task.deferDate`
- `task.addTag(...)`
- `task.addTags(...)`
- `task.removeTag(...)`

### Task lifecycle
- `task.markComplete(date)`
- `task.markIncomplete()`
- `task.active`

### Task moves
- `moveTasks(tasks, position)`
- Allowed destination shapes for v1:
- inbox insertion locations
- project destinations
- parent task destinations
- documented task child insertion locations

### Project field patches
- `project.name`
- `project.flagged`
- `project.completedByChildren`
- `project.containsSingletonActions`
- `project.sequential`
- `project.reviewInterval`
- `project.dueDate`
- `project.deferDate`
- `project.appendStringToNote(...)`
- `project.addTag(...)`
- `project.addTags(...)`
- `project.removeTag(...)`
- `project.task.<task-like property>` only when needed to implement a documented project property while keeping the public API project-shaped

### Project lifecycle
- `project.status`
- `project.markComplete(date)`
- `project.markIncomplete()`

### Project moves
- `moveSections(sections, position)`
- Allowed destination shapes for v1:
- folder destinations
- documented folder child insertion locations

### General deletion support
- `deleteObject(...)` is documented, but deletion is out of scope for the current v1 mutation roadmap and should not be exposed by the tools above.

## Allowed Derived Patterns
- Resolve task IDs to task objects and apply one homogeneous patch across all targets.
- Resolve project IDs to project objects and apply one homogeneous patch across all targets.
- Use `task.markComplete(...)` and `task.markIncomplete()` rather than synthesizing completion by direct date assignment.
- Use `project.markComplete(...)` and `project.markIncomplete()` rather than synthesizing completion by direct date assignment.
- Use `project.status` for project active/on-hold/dropped transitions.
- Use `moveTasks(...)` and `moveSections(...)` for structural moves instead of delete/recreate flows.
- Hide project root-task implementation details behind project-oriented public inputs and outputs.

## Out Of Scope For V1
- Mixed-operation `batch_mutate_tasks`
- Name-based target resolution for writes
- Creating new tasks, projects, folders, or tags as part of these tools
- Deleting tasks or projects
- Attachment or file-link mutation
- Notification mutation
- Repetition-rule mutation
- Project review date direct mutation using undocumented surfaces
- Tag reordering as part of update tools
- Placement controls beyond documented move destinations unless a later issue validates a concrete use case
- `plannedDate` writes

## Special Notes And Caveats

### Repeating completion semantics
- `markComplete(...)` on repeating tasks and projects can clone the repeated item and mark that clone complete.
- `set_*_completion` must treat repeating items as lifecycle operations that require post-write verification rather than assuming a simple boolean flip.

### Project root-task details
- Omni Automation documents that many “task-like” project properties are ultimately held on the project’s root task.
- FocusRelay may use that documented implementation detail internally, but the public tool surface should remain project-shaped.

### Planned date writes
- The task docs currently describe `plannedDate` with mixed signals about setter support and migration requirements.
- Because the documentation is ambiguous and the current roadmap does not need it, planned-date writes stay out of scope for v1.

## Review Checklist
Before merging mutation-path changes, verify:
- The change started from [`docs/mutation-change-checklist.md`](./mutation-change-checklist.md), not from ad hoc schema choices.
- Every OmniFocus property, function, and move API used by the mutation path appears on the official docs pages above.
- The public tool shape still matches the locked v1 surface in this document.
- Bulk semantics remain homogeneous.
- Preview, verify, and `returnFields` behavior remain consistent across CLI and MCP.
- Successful writes invalidate cached `list_projects` and `list_tags` results.
- Repeating-item completion behavior is covered by tests before merge.
Loading