Skip to content

Commit cbce5d3

Browse files
committed
fix(spec): mark withheldMaps as declared ahead of its producer, and name the exception in the module header
No export writes withheldMaps yet and no install door reads it, so its describe now opens [PLANNED — not yet served] (ADR-0049), says what absence means from an exporter that predates the key, and a test pins the marker. The module header names the two members declared ahead of their producer. Claude-Session: https://claude.ai/code/session_01ADHkmPi3pqv7Vkx4kymD87 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 27e2a7a commit cbce5d3

4 files changed

Lines changed: 39 additions & 10 deletions

File tree

‎.changeset/29373-export-withheld-maps.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Metadata-protocol: added
99

1010
`GET /packages/:id/export` writes each item as a served read returns it, so a connector's header and environment-variable maps are already withheld whole by the connector redactor and the exported item simply lacks them. An import elsewhere could not tell such a map from one the package never had. The export contract now has a place to say so:
1111

12-
- **`PackageExportManifestSchema` gains an optional fixed key `withheldMaps`**, a list of `{ type, name, path }`: `type` is `connector`, `name` is the connector item's name, and `path` is one of the four positions the redactor withholds whole, spelled as it reports them: `providerConfig.headers`, `providerConfig.defaultHeaders`, `providerConfig.transport.headers`, `providerConfig.transport.env`. Positions only: no header or variable name is listed, and an entry carrying any other key is refused. Absent when the export withheld nothing. The export does not write it yet; the runtime half follows.
13-
- **`UNMANAGED_INSTALL_KEY_DISPOSITIONS` classifies `withheldMaps` as `door`**, so an unmanaged import accepts an export that carries it instead of refusing the whole package for an unrecognised key. The door reads it; the new base never carries it.
12+
- **`PackageExportManifestSchema` gains an optional fixed key `withheldMaps`**, a list of `{ type, name, path }`: `type` is `connector`, `name` is the connector item's name, and `path` is one of the four positions the redactor withholds whole, spelled as it reports them: `providerConfig.headers`, `providerConfig.defaultHeaders`, `providerConfig.transport.headers`, `providerConfig.transport.env`. Positions only: no header or variable name is listed, and an entry carrying any other key is refused. It is declared ahead of its producer: no export writes it and no install door reads it yet, and its describe opens `[PLANNED — not yet served]` until the runtime half serves it. Until then, an export's lack of the key says nothing about what was withheld.
13+
- **`UNMANAGED_INSTALL_KEY_DISPOSITIONS` classifies `withheldMaps` as `door`**, so an unmanaged import accepts an export that carries it instead of refusing the whole package for an unrecognised key. The runtime half has the door read it to name each incomplete map; the new base never carries it.
1414
- **The export's `label` is classified `door` too.** The export contract has always declared it, but the table never classified it, so an unmanaged import refused any export that carried one. The base's install manifest declares no `label`, so the base is named by the request's `targetName` or the source `name`, as before.
1515

1616
The table's totality test now reads the export's fixed keys as a third schema a package body is read with, beside `ManifestSchema` and the stack definition, so a fixed key the export gains reddens a spec test on the PR that adds it.

‎packages/spec/src/api/package-lifecycle.test.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ describe('PackageExportManifestSchema.withheldMaps names each map the export wit
239239
if (result.success) expect(result.data).toEqual(manifest);
240240
});
241241

242+
it('is declared ahead of its producer: the describe opens with the planned marker and names the ADR, never a tracker id', () => {
243+
const description = PackageExportManifestSchema.shape.withheldMaps.description ?? '';
244+
expect(description).toMatch(/^\[PLANNED — not yet served\] /);
245+
expect(description).toContain('ADR-0049');
246+
expect(description).not.toMatch(/#\d{3,}/);
247+
});
248+
242249
it('is optional — an export that withheld nothing, or one from before the key, still parses', () => {
243250
expect(PackageExportManifestSchema.safeParse(identity).success).toBe(true);
244251
});

‎packages/spec/src/api/package-lifecycle.zod.ts‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@
3737
* declared a VERSION rollback against the live COMMIT-rollback path;
3838
* `RollbackToPackageCommitResponseSchema` below is the true contract,
3939
* authored after that retirement per the ruling's sequencing (3A).
40+
*
41+
* Two members are not transcriptions but DECLARED AHEAD OF THEIR PRODUCER
42+
* (ADR-0049), each describe opening `[PLANNED — not yet served]` until the
43+
* change that serves it drops the marker: the `nav` arm of
44+
* `GetPackageCustomizationsResponseSchema.contributions` (#27928) and
45+
* `PackageExportManifestSchema.withheldMaps` (#28640 ruling ③A, served by
46+
* #29342). Their own docblocks say what is not served yet.
4047
*/
4148

4249
import { z } from 'zod';
@@ -190,12 +197,23 @@ export const RollbackToPackageCommitResponseSchema = lazySchema(() => z.object({
190197
* redactor's, not a contract of the export. The path vocabulary is the
191198
* redactor's own `redactedKeys` spelling of those four positions, and
192199
* `package-lifecycle.test.ts` holds the two equal.
200+
*
201+
* DECLARED AHEAD OF ITS PRODUCER (ADR-0049): `withheldMaps` is declared
202+
* before any export writes it and before any install door reads it. Until the
203+
* server half (#29342) makes `assemblePackageManifest` write the list and both
204+
* install doors name each incomplete map, no export carries it; its describe
205+
* opens `[PLANNED — not yet served]`, and #29342 drops the marker in the change
206+
* that serves it (the pin is in `package-lifecycle.test.ts`). Its `door` row in
207+
* `UNMANAGED_INSTALL_KEY_DISPOSITIONS` is live today: it keeps the unmanaged
208+
* import from refusing an export that carries the key.
193209
*/
194210
export const PackageExportManifestSchema = lazySchema(() => z.object({
195211
id: z.string().describe('The exported package\'s id.'),
196212
name: z.string().describe('The exported package\'s machine name.'),
197213
version: z.string().describe('The exported package\'s version.'),
198214
label: z.string().optional().describe('Display label, when the package declares one.'),
215+
// Declared ahead of its producer: #29342 writes and reads it, and drops the
216+
// `[PLANNED — not yet served]` marker in that change.
199217
withheldMaps: z.array(z.object({
200218
type: z.literal('connector').describe('Metadata type of the item whose map was withheld.'),
201219
name: z.string().describe('Name of the item whose map was withheld.'),
@@ -206,11 +224,13 @@ export const PackageExportManifestSchema = lazySchema(() => z.object({
206224
'providerConfig.transport.env',
207225
]).describe('Dot path of the withheld map inside the item.'),
208226
}).strict()).optional().describe(
209-
'Every map the export withheld WHOLE because a served read never carries it: a connector\'s '
210-
+ 'header and environment-variable maps. The item is written with that map absent, so an import '
211-
+ 'reads this list to tell an incomplete map from one the package never had, and names each one '
212-
+ 'for an operator to re-enter. Positions only: no header or variable name is listed. Absent '
213-
+ 'when the export withheld nothing.',
227+
'[PLANNED — not yet served] Declared ahead of its producer (ADR-0049): no export writes this list '
228+
+ 'yet and no install door reads it yet. Every map the export withheld WHOLE because a served read '
229+
+ 'never carries it: a connector\'s header and environment-variable maps. The item is written with '
230+
+ 'that map absent, so once served an import reads this list to tell an incomplete map from one the '
231+
+ 'package never had, and names each one for an operator to re-enter. Positions only: no header or '
232+
+ 'variable name is listed. Absence says nothing about what was withheld when the exporter predates '
233+
+ 'this key; from an exporter that writes it, absence means nothing was withheld.',
214234
),
215235
}).catchall(z.unknown().describe(
216236
'One key per metadata type present in the package (plural spelling, e.g. '

‎packages/spec/src/kernel/unmanaged-install.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,11 @@ export const UNMANAGED_INSTALL_KEY_DISPOSITIONS: Readonly<Record<string, Unmanag
115115
// Read by the door to judge the requested mode; the base is the
116116
// environment's own package and makes no promise about how it installs.
117117
installModes: 'door',
118-
// [#28640 ruling ③A] The export's list of the maps it withheld whole: the
119-
// door reads it to name each incomplete map in its answer. It describes the
120-
// exchange, not the package, so the base never carries it.
118+
// [#28640 ruling ③A] The export's list of the maps it withheld whole,
119+
// declared ahead of its producer: the server half (#29342) has the door read
120+
// it to name each incomplete map in its answer. This row is live today — it
121+
// keeps the import from refusing an export that carries the key. It
122+
// describes the exchange, not the package, so the base never carries it.
121123
withheldMaps: 'door',
122124
// The export's display label. No manifest the base is installed with
123125
// declares one (`PackageInstallManifestSchema` is closed and has no

0 commit comments

Comments
 (0)