Skip to content

Commit 786c149

Browse files
dougborgclaude
andcommitted
docs(claude.md): document archive/deleted state conventions
Capture the conventions established by #526 so future work follows the same shape: - Query-param flags `include_archived` (items) and `include_deleted` (transactional entities) are siblings — both default to False, both surface soft-state on opt-in. - Response models that expose `archived_at` / `deleted_at` should also expose `is_archived` / `is_deleted` derived booleans for round-trip symmetry with `modify_<entity>` request bodies. - Items surface this end-to-end as of #526; transactional entities have the query-param half but not yet the derived-bool half (tracked in #540). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2b8f8ca commit 786c149

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,39 @@ Common mistakes to avoid:
152152
fields, use `to_unset(value)` from `katana_public_api_client.domain.converters`
153153
instead of `value if value is not None else UNSET`.
154154

155+
- **Archive / deleted state — opt-in flags + derived booleans** - Katana represents
156+
soft-state as nullable timestamps on the wire: `archived_at` (the user-toggleable
157+
archive lifecycle — exposed on catalog items, inventory rows, and a few other
158+
archivable entities) and `deleted_at` (soft-delete, exposed on most entities including
159+
catalog items *and* transactional entities like POs, SOs, MOs, stock transfers, stock
160+
adjustments). The two are independent — an entity can be both archived and
161+
soft-deleted. Two MCP-side conventions surface this; keep them symmetric:
162+
163+
- **Query-param flags** for opting into surfacing soft-state rows. **Default
164+
`False`.** Items use `include_archived` (`search_items`, catalog cache); the
165+
canonical wiring (landed in #526) is `cache.py`'s denormalized
166+
`entity_index.is_archived` column populated during sync, plus the
167+
`idx.is_archived = 0` predicate in `cache.search` / `search_fuzzy`. Transactional
168+
entities use `include_deleted` on `list_purchase_orders` / `list_sales_orders` /
169+
`list_manufacturing_orders` / `list_stock_adjustments`, filtering at the typed-cache
170+
query layer.
171+
- **Response-side derived booleans**: every response model that exposes `archived_at`
172+
/ `deleted_at` should also expose a convenience `is_archived` / `is_deleted` bool
173+
derived from `<timestamp> is not None`, saving callers from the timestamp/null
174+
inspection. **Note the asymmetry**: `is_archived` mirrors Katana's *write*
175+
convention (`update_<entity>` request bodies accept `is_archived: bool`, so
176+
round-tripping through `modify_<entity>` with
177+
`{"update_header": {"is_archived": false}}` works). `is_deleted`, by contrast, is
178+
*read-side only* — Katana exposes deletion through DELETE endpoints, not as a
179+
writable boolean on update bodies. Items expose `is_archived` on `ItemInfo` and
180+
`ItemDetailsResponse` as of #526.
181+
182+
Don't add a new opt-in flag without the matching derived bool, and vice versa. **Known
183+
gaps** (filed for follow-up): `list_stock_transfers` lacks `include_deleted` parity
184+
(#484); `check_inventory` and the inventory reporting tools lack `include_archived`
185+
and the `is_archived` row field (#539); transactional response models lack the
186+
`is_deleted` derived bool (#540).
187+
155188
- **Polluting the API spec/models with cache-only fields** - The OpenAPI spec at
156189
`docs/katana-openapi.yaml` and the generated pydantic models in
157190
`katana_public_api_client/models_pydantic/_generated/*.py` reflect Katana's actual

0 commit comments

Comments
 (0)