docs(mcp): correct the stock adjust justification and document create's actor
The system prompt justified avoiding the stock_items.list + stock_items.adjust loop by claiming that path "writes a ledger row with no actor". That stopped being true when the branch routed adjust through the audited write service: adjust now requires actor.id and its ledger rows carry created_by. The instruction itself is unchanged and not weakened — the signed delta and the missing batch call are still the reasons to avoid the loop, and the new tool's own advantages are now named. stock_items.create now also requires actor.id, so an external MCP client that omits it gets a 500 JSON-RPC error. The generated catalogue row is truncated at 240 chars before that sentence, so both authoritative docs get a hand-written row and an input-shape block instead. The generator is not re-run; the catalogue is still 148 tools.
This commit is contained in:
parent
0fd3d2f34e
commit
2a0f0a97f7
3 changed files with 33 additions and 1 deletions
|
|
@ -134,6 +134,7 @@ specific** tool that fits the task.
|
|||
| `stock_purchase_items.bulk_update` | Batch patch stock_purchase_items (≤100 rows). Same whitelist + hand-edit guard as `.update`. Per-row independence — one row's failure never affects another. `dry_run: true` returns the same shape with `status: "dry_run"` per row. |
|
||||
| `stock_purchase_items.assign_driver` | Bind a stock_purchase_item to a driver. Transitions line status `null → assigned_to_driver` or `collection_pool → assigned_to_driver`. Wrong_status (409) when the line is already past the assignment step. |
|
||||
| `stock_purchase_items.mark_collected` | Mark a line as physically delivered. Status → `collected`, bumps `quantity_received`. Does NOT book into stock — that's `stock_purchases.receive`. Header auto-flips to `received` when every line on the PO has `quantity_received >= quantity`. |
|
||||
| `stock_items.create` | Create a new POS/till stock_item. `name` is required. **Requires `actor.id`** — a 15-char WFDASH user id — so the opening-balance `stock_ledger` row is attributed to a user; a call without one is refused with a JSON-RPC error before anything is written. When `current_qty > 0` the opening balance is booked through the audited write path: the ledger row is written first and the quantity second, and the row is reversed if the quantity write fails. `supplier` is a PocketBase record id (resolve it with `suppliers.list`), not free text. |
|
||||
| `stock_items.update` | Patch catalogue fields on a master stock_item: `sku`, `description`, `notes`, `unit`, `selling_price`, `markup`. For inventory qty use `stock_items.set_quantities`. Returns `{ok: true, item, previous}` on success or `{ok: false, reason, message, field?}` on rejection. |
|
||||
| `stock_items.set_pricing` | Set `cost_price` / `selling_price` / `markup` on existing stock_items in one batch (max 100 per call). The POS till reads `selling_price` (not `markup`), so set both consistently: selling = cost × (1 + markup/100). Cost changes are audited in `stock_ledger` with the `actor`; quantities are NOT changed (use `stock_items.set_quantities`). Requires `actor.id`. Returns per-row `{ok, item, previous}` / `{ok: false, reason, message}`. |
|
||||
| `stock_items.set_quantities` | Set or change the stock quantity on up to 100 pasted lines. `mode: "set"` (the number is the new quantity on hand) or `mode: "add"` (the number is added to the current quantity). `lines`: 1–100 entries of `{ sku?, description?, qty }` — `qty` is required, and each line needs a `sku` or a `description` to match on. `dry_run: true` plans the change and writes nothing at all. Quantities may be negative — the till oversells on purpose. A line that cannot be resolved is reported, never guessed. Every `stock_ledger` row is stamped with the acting user. Requires `actor.id`. **This is the tool for quantities.** |
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ JSON-RPC over HTTP. Same `Authorization` bearer as `/api/v1/*`.
|
|||
|
||||
| Tool | Purpose |
|
||||
| --- | --- |
|
||||
| `stock_items.create` | Create a new POS/till `stock_item`. `name` is required, and `actor.id` is required so the opening balance is attributed (a 15-char WFDASH user id). When `current_qty > 0` an opening-balance `stock_ledger` row is written first and the quantity second; the row is reversed if the quantity write fails. |
|
||||
| `stock_items.update` | Patch catalogue fields on a master `stock_item` (`sku`, `description`, `notes`, `unit`, `selling_price`, `markup`). For inventory qty use `stock_items.set_quantities`. |
|
||||
| `stock_items.set_pricing` | Set `cost_price` / `selling_price` / `markup` on existing `stock_items` in one batch (max 100). The POS till reads `selling_price`, not `markup` — set both. Cost changes are audited in `stock_ledger` with the `actor`; quantities are not changed (use `stock_items.set_quantities`). |
|
||||
| `stock_items.set_quantities` | Set or change the stock quantity on up to 100 lines, matched by SKU and description. `mode: "set"` (the number is the new quantity on hand) or `mode: "add"` (the number is added to the current quantity). `lines`: 1–100 entries of `{ sku?, description?, qty }` — `qty` is required. `dry_run: true` plans the change and writes nothing at all. Quantities may be negative (the till oversells on purpose). Every `stock_ledger` row is stamped with the acting user. Requires `actor.id`. |
|
||||
|
|
@ -308,6 +309,36 @@ Returns `{ item, previous_quantity_received, new_quantity_received, header_statu
|
|||
`header_flipped: true` when this call completed the parent PO (auto-flip
|
||||
from `sent` → `received`).
|
||||
|
||||
`stock_items.create` (required: `name`; `actor.id` is required at runtime and must be a 15-char user id — it is written to `stock_ledger.created_by`, a relation to `users`; `actor.name` defaults to the id):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "M6 x 40mm hex bolt",
|
||||
"sku": "M6-40",
|
||||
"unit": "ea",
|
||||
"current_qty": 120,
|
||||
"min_qty": 20,
|
||||
"cost_price": 3.50,
|
||||
"selling_price": 6.30,
|
||||
"markup": 80,
|
||||
"actor": { "id": "user-id", "name": "Dave" }
|
||||
}
|
||||
```
|
||||
|
||||
`actor.id` is required: a call without one is refused with a JSON-RPC error
|
||||
(HTTP 500) before anything is written, so the opening balance is never
|
||||
booked without an actor. It must be the 15-char id of a WFDASH user (see
|
||||
`users.lookup`); `actor.name` is optional and defaults to the id. The
|
||||
in-app Giellie agent injects the signed-in operator's own actor after the
|
||||
model's arguments, so it wins over anything the model passed and Giellie
|
||||
never has to supply one. A direct MCP client passes its own `actor.id`.
|
||||
|
||||
When `current_qty > 0` the opening balance is booked through the audited
|
||||
write path: the `stock_ledger` row is written first and the quantity
|
||||
second, and the row is reversed if the quantity write fails, so
|
||||
`SUM(change_qty)` still rebuilds `current_qty`. `supplier` is a
|
||||
PocketBase record id (resolve it with `suppliers.list`), not free text.
|
||||
|
||||
`stock_items.update` (required: `id`, `patch`):
|
||||
|
||||
```json
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Stock items and pricing (POS):
|
|||
Stock quantity updates (POS):
|
||||
When the user pastes stock lines (a SKU or description with a quantity):
|
||||
1. Always ask first whether the numbers are the new quantity on hand or a change to add to the current stock. Do not infer it from the wording, and do not write anything until they answer. Send mode "set" for the new quantity on hand and mode "add" for a change to add to the current stock.
|
||||
2. Resolve the lines with stock_items.set_quantities. Never loop stock_items.list and stock_items.adjust by hand — that path takes a signed delta, has no batch call, and writes a ledger row with no actor.
|
||||
2. Resolve the lines with stock_items.set_quantities. Never loop stock_items.list and stock_items.adjust by hand — that path takes a signed delta and has no batch call. stock_items.set_quantities takes the new quantity on hand (or an addition), resolves each SKU or description itself, and previews the whole batch before anything is written.
|
||||
3. Call it with dry_run: true first and show the user the plan as a table: SKU, item, before, after, status. A dry run writes nothing, so a row whose status is "applied" only means "would be applied" — render it as "would be applied", label the table a plan, and say plainly that nothing has changed yet. Point out the lines that did not match and the ones that were ambiguous.
|
||||
4. Only when they say to apply, call it again with dry_run: false.
|
||||
5. Report the outcome: applied, unchanged, unmatched, ambiguous, failed.
|
||||
|
|
|
|||
Loading…
Reference in a new issue