Skip to content
Open
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
75 changes: 75 additions & 0 deletions tools/v2/individual/draft-improver/docs/CORE_CONTRACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Draft Improver Core Contract

This document describes the folder-local Draft Improver engine added for the
core feature issue. It is deterministic and does not call an LLM, live mailbox,
remote API, database, wallet, or production service.

## Inputs

`improveDraft(request, options)` accepts a plain object with:

- `id`: stable local request identifier.
- `subject`: optional draft subject.
- `body`: required draft body.
- `goal`: one of `clarity`, `concise`, `friendly`, `professional`, or
`call-to-action`.
- `audience`: optional recipient name used for a safe greeting.
- `senderName`: optional sender name used for a safe signoff.
- `deadline`: optional text used only when adding a call to action.
- `context`: optional reviewer context clipped to the local limit.
- `channel`: optional channel label, defaulting to `email`.

`options.now` fixes the generated timestamp for deterministic tests.
`options.limits` can override local subject, body, and context clipping limits.

## Outputs

Successful calls return:

- `status: "ready"`
- `isLoading: false`
- `error: null`
- `result.input`: normalized copy of the accepted request.
- `result.output`: improved `subject`, improved `body`, and a short `preview`.
- `result.issues`: issues detected before improvement.
- `result.remainingIssues`: issues still needing reviewer attention.
- `result.changes`: reviewable change records grouped by type.
- `result.warnings`: clipping warnings for oversized local input.
- `result.metrics`: word counts, reduction percentage, reading time, and issue
count.
- `result.reviewRequired`: true when a medium severity issue remains.

## Loading State

`createDraftImproverLoadingState(message)` returns the shape future UI work can
render before a local improvement run finishes:

- `status: "loading"`
- `isLoading: true`
- `error: null`
- `result: null`
- `message`: reviewer-facing progress text.

## Error State

Invalid requests do not throw. They return:

- `status: "error"`
- `isLoading: false`
- `error.code: "draft-improver-error"`
- `error.messages`: validation messages.
- `result: null`
- `requestId`: the local request id when available.

The validator rejects empty bodies and active markup such as script tags or
`javascript:` URLs. This keeps the core engine reviewable without overlapping
the future app shell, routing, mail rendering, wallet, Stellar, or database
integration work.

## Local Review Command

Run from the repository root:

```bash
node --test tools/v2/individual/draft-improver/tests/draft-improver-core.test.mjs
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"tool": "draft-improver",
"runContext": {
"now": "2026-07-01T00:00:00.000Z",
"source": "synthetic-folder-local-fixture"
},
"sourceRequests": [
{
"id": "draft-clarity-001",
"subject": "",
"goal": "clarity",
"audience": "Jordan",
"senderName": "Mira",
"deadline": "Friday",
"channel": "email",
"context": "Follow up on an internal project plan.",
"body": "just wanted to circle back on the migration plan. i think maybe we should approve the staging checklist and share owners for the launch items"
},
{
"id": "draft-concise-002",
"subject": "Requesting the updated launch copy",
"goal": "concise",
"audience": "Avery",
"senderName": "Noah",
"deadline": "2026-07-05",
"channel": "email",
"context": "Ask for a shorter launch copy update.",
"body": "Hi Avery,\n\nI am really writing in order to ask whether you can very quickly send the updated launch copy. It is very important for the review packet and we really need it by the requested date.\n\nThanks,\nNoah"
},
{
"id": "draft-friendly-003",
"subject": "Invoice attachment",
"goal": "friendly",
"audience": "Sam",
"senderName": "Riley",
"deadline": "",
"channel": "email",
"context": "Make a direct request warmer.",
"body": "Please send the invoice attachment again. The file did not come through on my side."
}
],
"expectedOutcomes": [
{
"id": "draft-clarity-001",
"status": "improved",
"requiredChangeTypes": ["subject", "wording", "structure", "action"],
"expectedSubjectPrefix": "Draft"
},
{
"id": "draft-concise-002",
"status": "improved",
"requiredChangeTypes": ["concise"],
"expectedSubjectPrefix": "Requesting"
},
{
"id": "draft-friendly-003",
"status": "improved",
"requiredChangeTypes": ["tone", "structure"],
"expectedSubjectPrefix": "Invoice"
}
]
}
8 changes: 8 additions & 0 deletions tools/v2/individual/draft-improver/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export {
createDraftImproverErrorState,
createDraftImproverLoadingState,
draftImproverCore,
improveDraft,
improveDraftBatch,
validateDraftImproverRequest,
} from "./services/draft-improver.service.mjs";
Loading