Skip to content

Commit d257dfa

Browse files
committed
fix(metadata-protocol): the sibling-expansion refusal prescribes the sibling container, never a save under its name
The refusal told the author to save the container under its object's name. In the card's own pair that name holds the sibling container, so following the arm literally replaced the sibling's row and dropped the view the refusal keeps serving. It now names the stored container that expands the name and prescribes adding the view as a member of it, or saving a view item under the expanded name. One pin per kernel; the changeset's fix carries the same two arms. Claude-Session: https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7196447 commit d257dfa

3 files changed

Lines changed: 27 additions & 7 deletions

File tree

‎.changeset/21620-container-sibling-expansion-name.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ Clause-②: no (narrowing)
1616

1717
**What still saves.** A container under its object's name, which expands as before, and its own re-save. A container under any other name of its own that no other stored container of its object expands to: this door keeps a container saved under a name other than its object, and this change leaves that alone. A view item (a body carrying `viewKind`) under an expanded name, the sanctioned override for that name. The read doors are unchanged. A row stored in this shape before this change keeps its bytes and is served as before; `migrate meta --stored` and package duplication, which re-save stored rows through this door, report such a row as failed with this refusal instead of re-saving it.
1818

19-
**The fix.** Save the container under its object's name (`crm_lead`), or save a view item (`name`, `object`, `viewKind`, `config`) under the expanded name (`crm_lead.pipeline`).
19+
**The fix.** Add the view as a member of the stored container that already expands the name (in the example, the container `crm_lead`, whose `listViews.pipeline` is that view), or save a view item (`name`, `object`, `viewKind`, `config`) under the expanded name (`crm_lead.pipeline`).

‎packages/metadata-protocol/src/protocol.ts‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18018,9 +18018,14 @@ export class ObjectStackProtocolImplementation implements
1801818018
* as the row's failure instead of re-saving it.
1801918019
*
1802018020
* `VALIDATION_ERROR` / 400, the envelope of the two name checks it sits
18021-
* beside. The prescription is the ruling's: save the container under its
18022-
* object's name, or save a view item under the expanded name. Runtime
18023-
* words carry no tracker number.
18021+
* beside. The prescription names the stored container that expands the
18022+
* name, and gives two arms: add the view as a member of THAT container, or
18023+
* save a view item under the expanded name. ⛔ It never prescribes a save
18024+
* under a name another stored container holds — not even the object's own
18025+
* name, which in the card's pair IS the sibling: an author (or an AI)
18026+
* following such an arm literally would replace the sibling's row and drop
18027+
* the very view this refusal keeps serving. Runtime words carry no tracker
18028+
* number.
1802418029
*/
1802518030
private async containerSiblingExpansionNameRefusal(
1802618031
type: string,
@@ -18052,9 +18057,9 @@ export class ObjectStackProtocolImplementation implements
1805218057
`Invalid view container: it is saved under '${saveName}', which is a name the stored container `
1805318058
+ `'${hit.container.name}' expands (its ${String(hit.item.viewKind)} view on '${object}'). An expanded `
1805418059
+ `view fills only a name that has no stored row of its own, and this container would be that row, so `
18055-
+ `that view would no longer be served and no read would answer a view under '${saveName}'. Save the `
18056-
+ `container under its object's name, '${object}', or save a view item (name, object, viewKind and `
18057-
+ `config) under '${saveName}'.`,
18060+
+ `that view would no longer be served and no read would answer a view under '${saveName}'. Add the `
18061+
+ `view as a member of the container '${hit.container.name}' (its list, listViews, form or formViews), `
18062+
+ `or save a view item (name, object, viewKind and config) under '${saveName}'.`,
1805818063
) as Error & { code: 'VALIDATION_ERROR'; status: 400 };
1805918064
err.code = 'VALIDATION_ERROR';
1806018065
err.status = 400;

‎packages/metadata-protocol/src/view-container-runtime-expansion.test.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,21 @@ describe('#21334 a container on another package\'s object never takes that packa
14741474
});
14751475
}
14761476

1477+
it('the prescription names the sibling container that expands the name and never prescribes a save under it — in the card\'s pair the object\'s own name IS that sibling', async () => {
1478+
const { protocol, rows, registry } = showcaseHarness(environmentId);
1479+
await saved(saveIn(protocol, LEAD, { name: LEAD, object: LEAD, listViews: { pipeline: leadList('Lead Pipeline') } }));
1480+
const PIPELINE = `${LEAD}.pipeline`;
1481+
const error = await refusalOf(saveIn(protocol, PIPELINE, second(PIPELINE)));
1482+
// The envelope, and the sibling named as the container that expands the name.
1483+
expectRefused(error, PIPELINE, LEAD);
1484+
// A save under the sibling's name would replace its row and drop `pipeline`,
1485+
// the view this refusal keeps serving: no arm may name that save.
1486+
expect(error.message, 'no save is prescribed under the sibling\'s (here the object\'s) name')
1487+
.not.toContain(`under '${LEAD}'`);
1488+
expectNothingWritten(rows, registry, [LEAD], PIPELINE);
1489+
await expectServed(protocol, PIPELINE, undefined, 'Lead Pipeline');
1490+
});
1491+
14771492
it('an environment-wide sibling is in an organization caller\'s selection: that caller\'s save under its expanded name is refused', async () => {
14781493
const { protocol, rows, registry } = showcaseHarness(environmentId);
14791494
await saved(saveIn(protocol, LEAD, { name: LEAD, object: LEAD, listViews: { pipeline: leadList('Lead Pipeline') } }));

0 commit comments

Comments
 (0)