Skip to content

Commit e5ac5cf

Browse files
committed
fix(metadata-protocol): every container collision refusal names its owner and its prescription inside the 500-character wire bound, the explanation after
Claude-Session: https://claude.ai/code/session_017ErfyP2Rx7XWHJA27QjyUi Co-authored-by: Claude <noreply@anthropic.com>
1 parent f30588c commit e5ac5cf

2 files changed

Lines changed: 31 additions & 20 deletions

File tree

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

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18030,25 +18030,29 @@ export class ObjectStackProtocolImplementation implements
1803018030
`Add the view as a member of the container '${container}' (its list, listViews, form or formViews)`;
1803118031
const ofItsOwn = 'the container under a name of its own that no package ships and no stored container expands';
1803218032

18033+
// ⛔ Every message names the owner, then gives the prescription, and
18034+
// only then explains: a 4xx message crosses the REST boundary bounded
18035+
// at 500 characters by truncating its TAIL (`CLIENT_MESSAGE_MAX`), so
18036+
// the explanation is the half an author can lose and still act.
18037+
//
1803318038
// The save name: the row this container would be.
1803418039
const rowHides = 'this container would be that row, so';
1803518040
const sibling = siblingServing(saveName);
1803618041
if (sibling) {
1803718042
return refusal(
1803818043
`it is saved under '${saveName}', which is a name the stored container '${sibling.container.name}' `
18039-
+ `expands (its ${kindOn(sibling.item)}). An expanded view fills only a name that has no stored row of `
18040-
+ `its own, and ${rowHides} that view would no longer be served and no read would answer a view under `
18041-
+ `'${saveName}'. ${asMemberOf(sibling.container.name)}, or save ${viewItem(saveName)}.`,
18044+
+ `expands (its ${kindOn(sibling.item)}). ${asMemberOf(sibling.container.name)}, or save `
18045+
+ `${viewItem(saveName)}. An expanded view fills only a name that has no stored row of its own, and `
18046+
+ `${rowHides} that view would no longer be served and no read would answer a view under '${saveName}'.`,
1804218047
);
1804318048
}
1804418049
const shipped = shippedServing(saveName);
1804518050
if (shipped) {
1804618051
return refusal(
1804718052
`it is saved under '${saveName}', which is the name of the ${kindOn(shipped)} the package `
18048-
+ `'${String(shipped._packageId)}' ships. A stored row under a packaged view's name takes that view's `
18049-
+ `place, and ${rowHides} the packaged view would no longer be served and no read would answer a view `
18050-
+ `under '${saveName}'. Save ${viewItem(saveName)} to override the packaged view, or save `
18051-
+ `${ofItsOwn}.`,
18053+
+ `'${String(shipped._packageId)}' ships. Save ${viewItem(saveName)} to override the packaged view, or `
18054+
+ `save ${ofItsOwn}. A stored row under a packaged view's name takes that view's place, and ${rowHides} `
18055+
+ `the packaged view would no longer be served and no read would answer a view under '${saveName}'.`,
1805218056
);
1805318057
}
1805418058
const own = served.find((expanded) => expanded.name === saveName);
@@ -18061,33 +18065,33 @@ export class ObjectStackProtocolImplementation implements
1806118065
? asMemberOf(object)
1806218066
: `Save ${ofItsOwn}`;
1806318067
return refusal(
18064-
`it is saved under '${saveName}', which is a name its own expansion produces (its ${kindOn(own)}). An `
18065-
+ `expanded view fills only a name that has no stored row of its own, and ${rowHides} no read would `
18066-
+ `answer a view under '${saveName}'. ${firstArm}, or save ${viewItem(saveName)}.`,
18068+
`it is saved under '${saveName}', which is a name its own expansion produces (its ${kindOn(own)}). `
18069+
+ `${firstArm}, or save ${viewItem(saveName)}. An expanded view fills only a name that has no stored `
18070+
+ `row of its own, and ${rowHides} no read would answer a view under '${saveName}'.`,
1806718071
);
1806818072
}
1806918073

1807018074
// Every name its expansion produces: the views this container would serve.
1807118075
for (const view of served) {
1807218076
const name = String(view.name);
18073-
const taken = `it is saved under '${saveName}', and its ${kindOn(view)} would be served as '${name}'`;
18077+
const taken = `its ${kindOn(view)} would be served as '${name}'`;
1807418078
const other = siblingServing(name);
1807518079
if (other) {
1807618080
return refusal(
18077-
`${taken}, which is a name the stored container '${other.container.name}' already expands (its `
18078-
+ `${kindOn(other.item)}). Two containers cannot serve one name: the one read last would replace `
18079-
+ `the other's view on both doors, and nothing would say why. ${asMemberOf(other.container.name)}, `
18080-
+ `or save ${viewItem(name)}.`,
18081+
`${taken}, a name the stored container '${other.container.name}' already expands. `
18082+
+ `${asMemberOf(other.container.name)}, or save ${viewItem(name)}. Saved under '${saveName}', this `
18083+
+ `container and that one would both serve '${name}': the one read last would replace the other's `
18084+
+ `view on both doors, and nothing would say why.`,
1808118085
);
1808218086
}
1808318087
const packaged = shippedServing(name);
1808418088
if (packaged) {
1808518089
return refusal(
18086-
`${taken}, which is the name of the ${kindOn(packaged)} the package `
18087-
+ `'${String(packaged._packageId)}' ships. A container's view under a packaged view's name `
18088-
+ `replaces that view on both doors, and nothing would say why. Save ${viewItem(name)} to override `
18089-
+ `the packaged view, or give the member a key of its own that no package ships and no stored `
18090-
+ `container expands.`,
18090+
`${taken}, the name of the ${String(packaged.viewKind)} view the package `
18091+
+ `'${String(packaged._packageId)}' ships. Save ${viewItem(name)} to override the packaged view, or `
18092+
+ `give the member a key of its own that no package ships and no stored container expands. Saved `
18093+
+ `under '${saveName}', this container's view would replace the packaged view on both doors, and `
18094+
+ `nothing would say why.`,
1809118095
);
1809218096
}
1809318097
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,13 @@ describe('#21334 a container on another package\'s object never takes that packa
18911891
expect(error.message, 'the refusal names the save name').toContain(`'${row.save.name}'`);
18921892
expect(error.message, 'the refusal names the colliding name').toContain(`'${refused.collides}'`);
18931893
expect(error.message, 'the refusal names the other owner').toContain(OWNER_NAMED[refused.owner](refused.ownerName));
1894+
// … the owner and the prescription both inside the first 500 characters,
1895+
// the bound a 4xx message crosses the REST boundary under, tail cut
1896+
// (`CLIENT_MESSAGE_MAX`): the explanation is the half that may be lost …
1897+
const delivered = String(error.message).slice(0, 500);
1898+
expect(delivered, 'the owner survives the wire bound').toContain(OWNER_NAMED[refused.owner](refused.ownerName));
1899+
expect(delivered, 'the prescription survives the wire bound')
1900+
.toContain(`a view item (name, object, viewKind and config) under '${refused.collides}'`);
18941901
// … and never prescribes a save under a name another stored row
18951902
// holds: wherever a stored row's name appears, it is named as THE
18961903
// CONTAINER (or as the object a view binds to), never as a name.

0 commit comments

Comments
 (0)