Skip to content

Commit 57ac54b

Browse files
committed
feat(spec): register FLOW_CONVERSION_CONFLICT in the ADR-0112 ledger (#9567 half 1)
`saveMetaItem`'s flow-conversion rename guard (protocol.ts:12674-12682) has thrown a live 409 FLOW_CONVERSION_CONFLICT since ADR-0078 landed -- already SCREAMING_SNAKE, so this is an ordinary ADR-0112 D3 ledger admission under @objectstack/metadata-protocol. It was invisible to check:dispatcher-error-vocabulary's scan because the site stamps the code through a cast rather than the bare-identifier `assign` shape the scan matched. Regenerated the two docs that mirror the ledger (content/docs/references/api/ contract.mdx, error-code-ledger.mdx) via gen:schema + gen:docs; check:generated and check:docs both confirm no other artifact moved. Half 2 of #9567 (`owd_widening_forbidden`) is measurement-only in this PR -- see the PR description -- so this PR does not close the issue. Part of #9567
1 parent e6ee690 commit 57ac54b

4 files changed

Lines changed: 29 additions & 1 deletion

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
Register `FLOW_CONVERSION_CONFLICT` (409) in the ADR-0112 error-code ledger under
6+
`@objectstack/metadata-protocol` (#9567). The code was already live on the wire —
7+
`saveMetaItem`'s flow-conversion rename guard (`protocol.ts`) has thrown it since
8+
ADR-0078 landed, already SCREAMING_SNAKE — but was invisible to
9+
`check:dispatcher-error-vocabulary`'s scan because the site stamps it through a
10+
cast (`(err as any).code = 'FLOW_CONVERSION_CONFLICT'`) rather than the bare-
11+
identifier `assign` shape the scan matched at the time. This is an ordinary,
12+
additive admission: no accept/reject behavior, no producer, and no wire shape
13+
changes.

‎content/docs/references/api/contract.mdx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const result = ApiErrorSchema.parse(data);
2727

2828
| Property | Type | Required | Description |
2929
| :--- | :--- | :--- | :--- |
30-
| **code** | `Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| 'INVALID_FORMAT' \| 'VALUE_TOO_LONG' \| 'VALUE_TOO_SHORT' \| 'VALUE_OUT_OF_RANGE' \| … +285 more>` | ✅ | Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages) |
30+
| **code** | `Enum<'VALIDATION_ERROR' \| 'INVALID_FIELD' \| 'MISSING_REQUIRED_FIELD' \| 'INVALID_FORMAT' \| 'VALUE_TOO_LONG' \| 'VALUE_TOO_SHORT' \| 'VALUE_OUT_OF_RANGE' \| … +286 more>` | ✅ | Error code (e.g. VALIDATION_ERROR; StandardErrorCode ∪ the ledger the serving side registers — ERROR_CODE_LEDGER for framework packages) |
3131
| **declaredCode** | `string` | optional | The producer-declared code, verbatim, when it is not a member of the closed `code` vocabulary — the open, author-authored channel (app-specific spellings; ADR-0112, #9106) |
3232
| **message** | `string` | ✅ | Readable error message |
3333
| **category** | `string` | optional | Error category (e.g. validation, authorization) |
@@ -179,6 +179,7 @@ const result = ApiErrorSchema.parse(data);
179179
* `FILE_NOT_FOUND`
180180
* `FILTER_TOKEN_UNKNOWN`
181181
* `FILTER_TOKEN_UNRESOLVED`
182+
* `FLOW_CONVERSION_CONFLICT`
182183
* `FLOW_DISABLED`
183184
* `FLOW_FAILED`
184185
* `FLOW_NO_START_NODE`

‎content/docs/references/api/error-code-ledger.mdx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ const result = ErrorCode.parse(data);
284284
* `FILE_NOT_FOUND`
285285
* `FILTER_TOKEN_UNKNOWN`
286286
* `FILTER_TOKEN_UNRESOLVED`
287+
* `FLOW_CONVERSION_CONFLICT`
287288
* `FLOW_DISABLED`
288289
* `FLOW_FAILED`
289290
* `FLOW_NO_START_NODE`

‎packages/spec/src/api/error-code-ledger.zod.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,19 @@ export const ERROR_CODE_LEDGER = {
377377
'COMMIT_NOT_FOUND',
378378
'CONCURRENT_UPDATE',
379379
'DESTRUCTIVE_CHANGE', // change would drop data; needs an explicit opt-in
380+
// [#9567] ADR-0078's rename guard refuses a metadata write whose `type`/
381+
// `name` token is already a LIVE name owned by something else in the
382+
// environment — persisting the un-renamed body would mint exactly the row
383+
// that guard exists to prevent (`saveMetaItem`, `protocol.ts`, same posture
384+
// as `duplicatePackage` / #4454). 409, not 422: the body may be perfectly
385+
// valid — the refusal comes from environment state, so resubmitting the
386+
// same body cannot help. Surfaced by the widened
387+
// `check:dispatcher-error-vocabulary` scan (#9460, half 1); NOTE the
388+
// producer's message prefix spells the code lowercase
389+
// (`[flow_conversion_conflict]`) while the wire stamp is SCREAMING_SNAKE —
390+
// a human-log inconsistency worth a glance, left as-is because the
391+
// producer is outside this ledger's surface.
392+
'FLOW_CONVERSION_CONFLICT',
380393
'INVALID_METADATA',
381394
'INVALID_REQUEST',
382395
'ITEM_LOCKED', // _lock refuses the write/delete (ADR-0010 §3.3)

0 commit comments

Comments
 (0)