@@ -1673,14 +1673,25 @@ export class ObjectStackClient {
16731673 /**
16741674 * Get a specific installed package by its ID (reverse domain identifier).
16751675 *
1676- * ⛔ [#11925] NOT bound, and the `{ package }` envelope is left exactly as
1677- * it was — the two mounted surfaces answer this route with DIFFERENT
1678- * envelopes, so no single declaration is true (#12034). `runtime`'s
1679- * `/packages` domain sends `success(pkg)` — the bare row — while `rest`'s
1680- * `GET {base}/packages/:id` sends `sendOk(res, { package: { ...pkg,
1681- * source } })`, and the REST routes "shadow live dispatcher twins" only
1682- * where a `package` service is registered. Binding the member here would
1683- * harden a claim that is already false on one of the two.
1676+ * ⛔ [#11925 / #12034] STILL NOT bound, and the `{ package }` envelope is
1677+ * left exactly as it was. #12034 shipped its `install` / `enable` /
1678+ * `disable` neighbours (one producer each) and deliberately did NOT ship
1679+ * this one, because this route is a REAL fork with no single true type.
1680+ * Both bodies below were MEASURED by driving each registrar, not read off
1681+ * the source:
1682+ *
1683+ * dispatcher handlePackages('/<id>', 'GET')
1684+ * -> { success: true, data: { id, manifest, enabled, status } }
1685+ * rest GET /api/v1/packages/:id
1686+ * -> { success: true, data: { package: { …row, source } } }
1687+ *
1688+ * `unwrapResponse` strips one envelope, so the post-unwrap value is the
1689+ * BARE row on the dispatcher and `{ package }` on REST. Binding either
1690+ * member here hardens a claim that is false on the other surface. Making
1691+ * it bindable means converging the two PRODUCERS — a wire-behaviour change
1692+ * to two mounted surfaces, above this card's authority, with a clause-②
1693+ * narrowing analysis of its own. The measured convergence cost is recorded
1694+ * on #12034 for that ruling.
16841695 *
16851696 * Its SCOPED twin `ScopedEnvironmentClient.packages.get` IS bound, because
16861697 * only the REST registrar serves the scoped mount — one surface, one
@@ -1695,14 +1706,25 @@ export class ObjectStackClient {
16951706 /**
16961707 * Install a new package from its manifest.
16971708 *
1698- * ⛔ [#11925] NOT bound. This method and its `enable` / `disable`
1699- * neighbours declare `{ package; message? }`, and the ONLY surface that
1700- * serves them — `runtime`'s `/packages` domain; `rest` mounts no twin for
1701- * any of the three — answers `success(pkg)`, the bare row (#12034). The
1702- * declared envelope is not merely erased, it is false, and the `any`
1703- * member is what keeps that invisible. Correcting it is a response-shape
1704- * decision with its own clause-② analysis, not the `any`-binding this card
1705- * carries, so the shape is left untouched here.
1709+ * [#12034] Bound to `InstalledPackage` — the BARE row, no envelope.
1710+ *
1711+ * What this REPLACED was not an erasure but a FALSEHOOD: the declaration
1712+ * read `{ package: any; message?: string }`, a shape no surface has ever
1713+ * sent, and the `any` member is what kept that invisible —
1714+ * `(await client.packages.install(m)).package` compiled and was
1715+ * `undefined` at runtime. There is exactly ONE serving surface, so there
1716+ * was never a "which surface do we match" question: `rest`'s registrar
1717+ * mounts only `POST /packages/publish`, `GET /packages`,
1718+ * `GET /packages/:id` and `DELETE /packages/:id` (measured by driving
1719+ * `registerPackageRoutes` and enumerating what it mounted — this route is
1720+ * `NO_HANDLER` there), leaving `runtime`'s `/packages` domain alone to
1721+ * answer, and it answers `success(pkg)`: `{ success: true, data: <row> }`,
1722+ * status 201. `message` is gone with the wrapper — no surface sends one.
1723+ *
1724+ * The wire fact is pinned end-to-end in
1725+ * `packages-write-envelope.test.ts` (the real dispatcher answering a real
1726+ * client call), and the DECLARATION in `return-type-precision.test.ts` —
1727+ * a runtime test cannot observe a return-type narrowing at all.
17061728 *
17071729 * By default the server rejects a manifest whose `id` is already
17081730 * installed with **409 Conflict** (duplicate-id guard) instead of
@@ -1712,7 +1734,7 @@ export class ObjectStackClient {
17121734 install : async (
17131735 manifest : any ,
17141736 options ?: { settings ?: Record < string , any > ; enableOnInstall ?: boolean ; overwrite ?: boolean } ,
1715- ) => {
1737+ ) : Promise < InstalledPackage > => {
17161738 const route = this . getRoute ( 'packages' ) ;
17171739 const res = await this . fetch ( `${ this . baseUrl } ${ route } ` , {
17181740 method : 'POST' ,
@@ -1723,7 +1745,7 @@ export class ObjectStackClient {
17231745 ...( options ?. overwrite !== undefined ? { overwrite : options . overwrite } : { } ) ,
17241746 } ) ,
17251747 } ) ;
1726- return this . unwrapResponse < { package : any ; message ?: string } > ( res ) ;
1748+ return this . unwrapResponse < InstalledPackage > ( res ) ;
17271749 } ,
17281750
17291751 /**
@@ -1739,24 +1761,38 @@ export class ObjectStackClient {
17391761
17401762 /**
17411763 * Enable a disabled package.
1742- */
1743- enable : async ( id : string ) => {
1764+ *
1765+ * [#12034] Bound to `InstalledPackage` — the BARE row, no envelope, for
1766+ * the reason spelled out on `install` above: one serving surface
1767+ * (`PATCH /packages/:id/enable` is `NO_HANDLER` on the REST registrar),
1768+ * and it answers `success(registry.enablePackage(id))`. The
1769+ * `{ package: any; message?: string }` this replaces was never emitted by
1770+ * anything.
1771+ */
1772+ enable : async ( id : string ) : Promise < InstalledPackage > => {
17441773 const route = this . getRoute ( 'packages' ) ;
17451774 const res = await this . fetch ( `${ this . baseUrl } ${ route } /${ encodeURIComponent ( id ) } /enable` , {
17461775 method : 'PATCH' ,
17471776 } ) ;
1748- return this . unwrapResponse < { package : any ; message ?: string } > ( res ) ;
1777+ return this . unwrapResponse < InstalledPackage > ( res ) ;
17491778 } ,
17501779
17511780 /**
17521781 * Disable an installed package.
1753- */
1754- disable : async ( id : string ) => {
1782+ *
1783+ * [#12034] Bound to `InstalledPackage` — the BARE row, no envelope, same
1784+ * single-producer argument as `install` / `enable` above
1785+ * (`PATCH /packages/:id/disable` is `NO_HANDLER` on the REST registrar).
1786+ * The dispatcher answers `success(registry.disablePackage(id))`, so the
1787+ * row comes back with `enabled: false` — the caller reads the row itself,
1788+ * never a `.package` member.
1789+ */
1790+ disable : async ( id : string ) : Promise < InstalledPackage > => {
17551791 const route = this . getRoute ( 'packages' ) ;
17561792 const res = await this . fetch ( `${ this . baseUrl } ${ route } /${ encodeURIComponent ( id ) } /disable` , {
17571793 method : 'PATCH' ,
17581794 } ) ;
1759- return this . unwrapResponse < { package : any ; message ?: string } > ( res ) ;
1795+ return this . unwrapResponse < InstalledPackage > ( res ) ;
17601796 } ,
17611797
17621798 /* [#3563 PR-4] Lifecycle beyond install/enable — these eleven routes
0 commit comments