Skip to content

Commit 43faa22

Browse files
refactor(metadata-protocol): spell the inferred return types of the eight protocol.ts doors the facade keeps (.d.ts byte-equal) (#30516)
<!-- claude-projects-attribution: {"github_login":"os-bill"} --> _Requested by **Bill** · [project thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgKd8GqhzWbGWABewb5SLGNm)_ domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb ## 维护者速读 - 改了什么:`protocol.ts` 门面上 8 个因返回类型靠推断而留在类上的公开方法(`getDiscovery`、`findData`、`getData`、`cloneData` 和四个 `*MetaItem`)把返回类型写明在签名上,类型逐字取自它今天被推断进的 `.d.ts`;方法体一行未动。 - 为什么改:返回类型靠推断时,方法体一挪走,`.d.ts` 就会经新位置重新推断(拆分时实测 `getDiscovery` 丢过一个 `@deprecated` 注释),所以它们只能留在门面上;写明之后类型不再取决于方法体放在哪。 - 风险与回滚:没有行为变化,公开 `index.d.ts` / `index.d.cts` 改前改后逐字节相同;只有 source map 随新增行变动。回滚即撤本 PR。 - 先看:`packages/metadata-protocol/src/protocol.ts` 里 `getDiscovery` 的新签名(最长的一段),再看 `scripts/facade-delegation-registry.json` 改了理由的 8 行。 - 两分钟验证:`pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.facade-door-return-types.pin.test.ts`,预期 9 条全绿;在 main 的 `protocol.ts` 上其中 8 条是红的。 - 需要你做的:无,席位落地。方法体搬进 facet 这一步本 PR 没做(codemod 已不能在拆好的文件上重跑,见 Acceptance notes),`engine.ts` 那一半排在 #30055 之后。 Part of #30054 (the `protocol.ts` half, step 1 only: the return types are spelled; the bodies stay, and the `engine.ts` half is owed. Both are listed under Acceptance notes.) Clause-②: no — the published `index.d.ts` and `index.d.cts` of `@objectstack/metadata-protocol` are byte-equal before and after, so no exported member changes. Metadata-protocol: none Skills-docs: none — an internal refactor of eight method signatures whose printed types do not change; no skill text names them. ## What changes - **`packages/metadata-protocol/src/protocol.ts`.** The eight doors the #30019 gate lists as `inferred-return-type` exceptions on card #30054 now declare their return type: `getDiscovery`, `findData`, `getData`, `cloneData`, `saveMetaItem`, `publishMetaItem`, `rollbackMetaItem`, `deleteMetaItem`. Each type is copied, text for text, from the line the base build printed for that method in `dist/index.d.ts`: the type literals, their docblocks (the `@deprecated` on `getDiscovery`'s `apiName`, the ones `publishMetaItem` carries), the double-quoted string unions and the `| undefined` the printer writes are all kept, so the declaration emit reprints them unchanged. No body, parameter or modifier changes. `tsc --noEmit` accepts every body against its spelled type. - **`scripts/facade-delegation-registry.json`.** The eight rows stay (their bodies are still on the class, and the gate refuses a row whose member is already a delegation). Their `reason` no longer says "stays until the return type is spelled", which is now false; it says the type is spelled and why the body still stays. - **Pin.** `protocol.facade-door-return-types.pin.test.ts` parses `protocol.ts` and requires each of the eight doors to carry a return type annotation, so an edit cannot quietly drop one before a later move would re-infer it. - **Changeset.** `@objectstack/metadata-protocol` patch: the published declarations are byte-equal, but the shipped source maps move with the new lines, so the package's published files do change. ## Tests - New pin: 9/9 pass at head. On `origin/main`'s `protocol.ts` (restored unstaged, then put back from `HEAD`, `git diff HEAD` empty) 8 of 9 fail, one per door. - Ablation (once, through `scripts/ablation-replace.mjs`): `rollbackMetaItem`'s annotation removed, anchor 1 → 0, blob `0a87e4f8` → `ec11148a`; the pin goes 1 failed / 8 passed, naming `rollbackMetaItem`; restored to the `HEAD` blob with `git diff HEAD` empty. - `@objectstack/metadata-protocol` full suite at head `1777fb2d2`: 317 files passed, 4 skipped; 22,434 tests passed, 26 skipped. `pnpm typecheck` exit 0. (The same suite ran at `63a626492`, before the second merge: 316 files, 22,419 tests, all passing.) - `pnpm lint` (`eslint . --no-inline-config`) exit 0 at `63a626492`; at head `1777fb2d2`, eslint `--no-inline-config` over the two changed source files exit 0. ## Acceptance notes - **The move (step 2) is not mechanical today, so it is not in this PR.** `scripts/codemod-split-protocol.mjs` cannot re-run on the landed facade: on `origin/main` it refuses with "protocol.ts already carries [#29985 codemod] stubs: run the script on an unsplit file". Its regenerate-from-base route no longer holds either: `--verify --base 48914fd^` (the #29985 split's base) now reports 79/85 moved bodies identical and 71/78 host-split checks passing, because later PRs edited moved bodies in the facet modules (#30293, #30353, #30380, #30414), and two facet modules gained top-level statements that are not facet methods (`PackagedArtifactBaseType` in `protocol-discovery-and-bases.ts`, `storedGrantObjectKeys` in `protocol-package-commits.ts`), which the facade layer's unlift refuses. Moving the eight bodies needs a pass over the landed facade, as the engine codemod has (`--scoped`, `--hand-docs`, and #30055's `--members`). That is an edit to `scripts/codemod-split-protocol.mjs`, outside this card's file surface; carrier: the seat. - **Rows still owed on #30054.** `protocol.ts` (body move): `getDiscovery`, `findData`, `getData`, `cloneData`, `saveMetaItem`, `publishMetaItem`, `rollbackMetaItem`, `deleteMetaItem`. `engine.ts` (types and move, serial behind #30055): `registerApp`, `registerHook`, `registerDriver`, `init`, `triggerHooks`, `destroy`, `setDatasourceMapping`, `getStatus`. - **A spelled type is now the published shape, so it must move with the body.** TypeScript does not refuse a body that returns a wider object than its signature (a non-literal return gets no excess-property check), and the `.d.ts` prints the signature, not the body. Measured on this branch: `origin/main` gained `seedApplied.landed` on the publish receipt (#30427, `a7b8876f5`) while this PR was open; the branch's first spelling (copied at `c5800818`) merged with no conflict, and would have dropped `landed` from the published `publishMetaItem` type. The type was re-copied from `a1d0b1ee9`'s build (commit `1777fb2d2`), and the proof below is against that base. A later change to what one of these doors returns edits the signature too. - No `packages/objectql` file changes, so its declaration files are not re-proved here. ## Verification Head `1777fb2d2` (branch merged with `origin/main` `a1d0b1ee9`), base `a1d0b1ee9`. <details><summary>Declaration-file proof</summary> - Base: `origin/main` `a1d0b1ee9`'s `protocol.ts` restored into the merged tree (the merged file differs from it only by the eight annotations), `turbo run build --filter=@objectstack/metadata-protocol...`, `dist/index.d.ts` and `dist/index.d.cts` copied aside. The eight types were copied from that `index.d.ts`. - Head `1777fb2d2`: `pnpm build` in `packages/metadata-protocol` (tsup with DTS, then `check-dts-emitted`: 2/2 declaration files present); `cmp` against the base copies: `index.d.ts` byte-equal, `index.d.cts` byte-equal (`index.d.ts` sha256 `f7c56a2155a2b77a…` on both sides). - The same proof ran first at base `c5800818` (byte-equal, sha256 `2f93f627839cccd7…`), before the merge that brought #30427. - The diff of the emitted declarations is empty. </details> <details><summary>Gates</summary> - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at head `1777fb2d2`: 69 derived commands (change set: 4 paths, +251 / -16, under the 3,000 threshold). Each was run with its exit code recorded before any pipe; all 69 exit 0. `--ran` reconciles 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN. `check-plugin-teardown-shape --self-test` needed `git fetch origin 621a487…` first (shallow clone). - The first pass at `63a626492` (same 69 commands) had 68 exit 0 and `check:dual-build-cjs-loads` exit 3 (no full workspace build then); at the final head it ran and passed. - `pnpm check:facade-delegation-only`: "5 facade class(es) in 3 file(s) hold delegations only", exit 0; the registry still carries the eight rows. - eslint over the two changed source files exit 0 at head; `pnpm lint` exit 0 at `63a626492`. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01Utp6CXZTh9qvT24wTN6dd6)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b17dbcf commit 43faa22

4 files changed

Lines changed: 251 additions & 16 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/metadata-protocol': patch
3+
---
4+
5+
refactor(metadata-protocol): the eight `ObjectStackProtocolImplementation` doors that kept an inferred return type spell it on the signature
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- `getDiscovery`, `findData`, `getData`, `cloneData`, `saveMetaItem`, `publishMetaItem`, `rollbackMetaItem` and `deleteMetaItem` now declare their return type, copied from the published declaration file it was inferred into. The built `index.d.ts` and `index.d.cts` are byte-equal before and after, and no behaviour changes; only the source maps move with the new lines. Nothing to do on upgrade.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* #30054 — the eight public doors that stayed whole on the
5+
* `ObjectStackProtocolImplementation` facade because their return type was
6+
* inferred now spell it.
7+
*
8+
* The protocol.ts codemod keeps a non-private method with an inferred return
9+
* type on the class (`inferred-return-type` in
10+
* `scripts/codemod-split-protocol.mjs`): the published `.d.ts` prints that
11+
* type, and once the body moved the compiler would infer it through the moved
12+
* function instead. Each door below now carries its type on the signature,
13+
* copied from the `.d.ts` it was inferred into (the PR proves the built
14+
* `.d.ts` byte-equal before and after), so the type no longer depends on where
15+
* the body lives. An edit that drops one of these annotations turns this red,
16+
* before a later move could re-infer it.
17+
*
18+
* The bodies are still on the class: each door keeps its row in
19+
* `scripts/facade-delegation-registry.json` until a facade pass moves it.
20+
*/
21+
import { readFileSync } from 'node:fs';
22+
import { fileURLToPath } from 'node:url';
23+
import ts from 'typescript';
24+
import { describe, expect, it } from 'vitest';
25+
26+
const FILE = fileURLToPath(new URL('./protocol.ts', import.meta.url));
27+
const CLASS_NAME = 'ObjectStackProtocolImplementation';
28+
29+
/** The doors, each with the head of the type it spells (the outer type of its `.d.ts` line). */
30+
const DOORS: Readonly<Record<string, string>> = {
31+
getDiscovery: 'Promise<{',
32+
findData: 'Promise<{',
33+
getData: 'Promise<{',
34+
cloneData: 'Promise<{',
35+
saveMetaItem: 'Promise<{',
36+
publishMetaItem: 'Promise<{',
37+
rollbackMetaItem: 'Promise<{',
38+
deleteMetaItem: 'Promise<{',
39+
};
40+
41+
function classMethods(): Map<string, ts.MethodDeclaration[]> {
42+
const text = readFileSync(FILE, 'utf8');
43+
const sf = ts.createSourceFile(FILE, text, ts.ScriptTarget.ES2022, true, ts.ScriptKind.TS);
44+
const cls = sf.statements.find((s): s is ts.ClassDeclaration => ts.isClassDeclaration(s) && s.name?.text === CLASS_NAME);
45+
const out = new Map<string, ts.MethodDeclaration[]>();
46+
for (const m of cls?.members ?? []) {
47+
if (!ts.isMethodDeclaration(m) || !m.body || !m.name || !ts.isIdentifier(m.name)) continue;
48+
out.set(m.name.text, [...(out.get(m.name.text) ?? []), m]);
49+
}
50+
return out;
51+
}
52+
53+
describe('protocol.ts facade doors spell their return type (#30054)', () => {
54+
const methods = classMethods();
55+
56+
it('finds the class and every door, once each', () => {
57+
expect(methods.size).toBeGreaterThan(0);
58+
for (const name of Object.keys(DOORS)) expect(methods.get(name)?.length, name).toBe(1);
59+
});
60+
61+
for (const [name, head] of Object.entries(DOORS)) {
62+
it(`${name} declares its return type on the signature`, () => {
63+
const m = methods.get(name)?.[0];
64+
expect(m, name).toBeDefined();
65+
const type = m!.type;
66+
expect(type, `${name} has an inferred return type`).toBeDefined();
67+
expect(type!.getText().startsWith(head), `${name}: ${type!.getText().slice(0, 40)}`).toBe(true);
68+
});
69+
}
70+
});

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

Lines changed: 163 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,7 +2486,60 @@ export class ObjectStackProtocolImplementation implements
24862486
return ProtocolDiscoveryAndBasesFacet.getProjectId(protocolHost(this));
24872487
}
24882488

2489-
async getDiscovery() {
2489+
async getDiscovery(): Promise<{
2490+
authFamilies?: {
2491+
admin: boolean;
2492+
} | undefined;
2493+
version: string;
2494+
name: string;
2495+
/** @deprecated Use `name`. Removed in protocol 18 (#4828). */
2496+
apiName: string;
2497+
environment: "sandbox" | "production" | "development";
2498+
routes: {
2499+
data: string;
2500+
metadata: string;
2501+
discovery?: string | undefined;
2502+
ui?: string | undefined;
2503+
auth?: string | undefined;
2504+
automation?: string | undefined;
2505+
storage?: string | undefined;
2506+
analytics?: string | undefined;
2507+
packages?: string | undefined;
2508+
datasources?: string | undefined;
2509+
email?: string | undefined;
2510+
approvals?: string | undefined;
2511+
realtime?: string | undefined;
2512+
notifications?: string | undefined;
2513+
ai?: string | undefined;
2514+
i18n?: string | undefined;
2515+
mcp?: string | undefined;
2516+
};
2517+
locale: {
2518+
default: string;
2519+
supported: string[];
2520+
timezone: string;
2521+
};
2522+
services: Record<string, {
2523+
enabled: boolean;
2524+
status: "registered" | "degraded" | "available" | "unavailable" | "stub";
2525+
handlerReady?: boolean | undefined;
2526+
route?: string | undefined;
2527+
provider?: string | undefined;
2528+
version?: string | undefined;
2529+
message?: string | undefined;
2530+
rateLimit?: {
2531+
requestsPerMinute?: number | undefined;
2532+
requestsPerHour?: number | undefined;
2533+
burstLimit?: number | undefined;
2534+
retryAfterMs?: number | undefined;
2535+
} | undefined;
2536+
}>;
2537+
capabilities: Record<"ai" | "automation" | "cron" | "analytics" | "files" | "search" | "export" | "i18n" | "notifications" | "comments" | "chunkedUpload" | "transactionalBatch" | "websockets", {
2538+
enabled: boolean;
2539+
features?: Record<string, boolean> | undefined;
2540+
description?: string | undefined;
2541+
}>;
2542+
}> {
24902543
// Get registered services from kernel if available
24912544
const registeredServices = this.getServicesRegistry ? this.getServicesRegistry() : new Map();
24922545

@@ -5407,7 +5460,12 @@ export class ObjectStackProtocolImplementation implements
54075460
return servesExpansionTarget.call(host, target);
54085461
}
54095462

5410-
async findData(request: { object: string, query?: any, context?: any }) {
5463+
async findData(request: { object: string, query?: any, context?: any }): Promise<{
5464+
hasMore: boolean;
5465+
total?: number | undefined;
5466+
object: string;
5467+
records: any[];
5468+
}> {
54115469
// [#3770] Existence first: an unregistered object is a 404 before any
54125470
// query parameter is even parsed, so an unknown name can never be
54135471
// probed for query-shape validity (nor reach the driver as a table).
@@ -6159,7 +6217,11 @@ export class ObjectStackProtocolImplementation implements
61596217
};
61606218
}
61616219

6162-
async getData(request: { object: string, id: string, expand?: string | string[], select?: string | string[], context?: any }) {
6220+
async getData(request: { object: string, id: string, expand?: string | string[], select?: string | string[], context?: any }): Promise<{
6221+
object: string;
6222+
id: string;
6223+
record: Record<string, any>;
6224+
}> {
61636225
this.assertObjectRegistered(request.object); // [#3770]
61646226
const queryOptions: any = {
61656227
where: { id: request.id }
@@ -6281,7 +6343,24 @@ export class ObjectStackProtocolImplementation implements
62816343
* win over the copied values — the natural place to set a new `name`,
62826344
* clear a unique field, or reset status before insert.
62836345
*/
6284-
async cloneData(request: { object: string, id: string, overrides?: Record<string, any>, context?: any }) {
6346+
async cloneData(request: { object: string, id: string, overrides?: Record<string, any>, context?: any }): Promise<{
6347+
warnings?: {
6348+
rule: string;
6349+
severity: "info" | "warning";
6350+
field: string;
6351+
code: string;
6352+
message: string;
6353+
}[] | undefined;
6354+
droppedFields?: {
6355+
object: string;
6356+
fields: string[];
6357+
reason: "readonly" | "computed" | "readonly_when" | "primary_key" | "stored_expression";
6358+
}[] | undefined;
6359+
object: string;
6360+
id: any;
6361+
sourceId: string;
6362+
record: any;
6363+
}> {
62856364
// [#3770] This object-existence check used to be open-coded here and
62866365
// was the ONLY one on the whole data plane; it is now the shared gate
62876366
// every data entry point runs. Same error envelope as before.
@@ -10814,7 +10893,22 @@ export class ObjectStackProtocolImplementation implements
1081410893
// STORED content hash itself (`migrateStoredMetadata`): it reaches the
1081510894
// repository as given. ⛔ No transport sets it — every door builds its
1081610895
// request field by field from named inputs, never by spreading a body.
10817-
async saveMetaItem(request: SaveMetaItemRequest) {
10896+
async saveMetaItem(request: SaveMetaItemRequest): Promise<{
10897+
state: "draft" | "active";
10898+
message: string;
10899+
advisories?: {
10900+
rule: string;
10901+
path: string;
10902+
where: string;
10903+
message: string;
10904+
hint: string;
10905+
severity: "error" | "info" | "warning";
10906+
}[] | undefined;
10907+
projectionApplied?: MutationProjectionOutcome | undefined;
10908+
success: boolean;
10909+
version: string;
10910+
seq: number;
10911+
}> {
1081810912
// [#28355] A refusal that carries no row of its own leaves its `denied` row here.
1081910913
return withRefusalAudit((entry) => this.recordMetadataAudit(entry), {
1082010914
operation: 'save', type: request.type, name: request.name, actor: request.actor,
@@ -11051,7 +11145,55 @@ export class ObjectStackProtocolImplementation implements
1105111145
* Records a history event with `op='publish'`. 404 (`NO_DRAFT`)
1105211146
* when there is nothing to publish.
1105311147
*/
11054-
async publishMetaItem(request: PublishMetaItemRequest) {
11148+
async publishMetaItem(request: PublishMetaItemRequest): Promise<{
11149+
success: boolean;
11150+
version: string;
11151+
seq: number;
11152+
message?: string;
11153+
/**
11154+
* Present when a `seed` draft was published: the result of materializing
11155+
* its rows. Publishing the metadata ALWAYS succeeds independently — a
11156+
* seed-load problem is surfaced here, never thrown, so callers (and UIs)
11157+
* must check `seedApplied.success` instead of assuming data went live.
11158+
*/
11159+
seedApplied?: {
11160+
success: boolean;
11161+
inserted: number;
11162+
updated: number;
11163+
error?: string;
11164+
errors?: unknown[];
11165+
/** [#30348] Per object, the rows created vs matched — `SeedAppliedLandedSchema`. */
11166+
landed?: SeedAppliedLandedParsed[];
11167+
};
11168+
/**
11169+
* Present when a publish-time materializer is registered for this type
11170+
* (ADR-0086 P2 — e.g. `flow`): the result of projecting the published
11171+
* body into its data-plane representation. Best-effort,
11172+
* same contract as `seedApplied` — surfaced, never thrown.
11173+
*/
11174+
materializeApplied?: PublishMaterializeResult;
11175+
/**
11176+
* Present when an ADR-0094 mutation projector is registered for this
11177+
* type: the outcome of the awaited post-persist projection. The
11178+
* draft→active promotion runs the projector exactly as a direct active
11179+
* save does, so this is the same receipt `saveMetaItem` returns.
11180+
*
11181+
* [#7294] It was ASSIGNED below and missing from this annotation, so
11182+
* the method's declared type denied a key the wire body carried — the
11183+
* same declared-≠-returned gap one layer down from the one #7294
11184+
* closed on the spec side.
11185+
*/
11186+
projectionApplied?: MutationProjectionOutcome;
11187+
/**
11188+
* [#9176] Present ONLY when the #4463 runtime authoring gate raised at
11189+
* least one non-blocking finding against the draft body this promotion
11190+
* carried to `active` — an empty array is never emitted, so a clean
11191+
* publish's response bytes are unchanged (the #4717 discipline, one
11192+
* door over). Every entry is `warning`/`info` by construction: an
11193+
* `error` finding refuses the promotion as the 422 instead.
11194+
*/
11195+
advisories?: RuntimeAuthoringIssue[];
11196+
}> {
1105511197
// [#28355] A refusal that carries no row of its own leaves its `denied` row here.
1105611198
return withRefusalAudit((entry) => this.recordMetadataAudit(entry), {
1105711199
operation: 'publish', type: request.type, name: request.name, actor: request.actor,
@@ -13211,7 +13353,13 @@ export class ObjectStackProtocolImplementation implements
1321113353
* into the row the by-name read naming no package serves, a `.custom`
1321213354
* pair's declared override over a row bound to its read-only base.
1321313355
*/
13214-
async rollbackMetaItem(request: RollbackMetaItemRequest) {
13356+
async rollbackMetaItem(request: RollbackMetaItemRequest): Promise<{
13357+
success: boolean;
13358+
version: string;
13359+
seq: number;
13360+
restoredFromVersion: number;
13361+
message?: string;
13362+
}> {
1321513363
// [#28355] A refusal that carries no row of its own leaves its `denied` row here.
1321613364
return withRefusalAudit((entry) => this.recordMetadataAudit(entry), {
1321713365
operation: 'rollback', type: request.type, name: request.name, actor: request.actor,
@@ -13301,7 +13449,14 @@ export class ObjectStackProtocolImplementation implements
1330113449
* "Reset to factory default" semantic from ADR-0005. Whitelist is shared
1330213450
* with {@link saveMetaItem}.
1330313451
*/
13304-
async deleteMetaItem(request: DeleteMetaItemRequest) {
13452+
async deleteMetaItem(request: DeleteMetaItemRequest): Promise<{
13453+
success: boolean;
13454+
message?: string;
13455+
reset?: boolean;
13456+
seq?: number;
13457+
/** [ADR-0094] Outcome of the awaited mutation projector, when one is registered. */
13458+
projectionApplied?: MutationProjectionOutcome;
13459+
}> {
1330513460
// [#28355] A refusal that carries no row of its own leaves its `denied` row here.
1330613461
return withRefusalAudit((entry) => this.recordMetadataAudit(entry), {
1330713462
operation: 'delete', type: request.type, name: request.name, actor: request.actor,

‎scripts/facade-delegation-registry.json‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,49 +31,49 @@
3131
"file": "packages/metadata-protocol/src/protocol.ts",
3232
"member": "getDiscovery",
3333
"card": "#30054",
34-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
34+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
3535
},
3636
{
3737
"file": "packages/metadata-protocol/src/protocol.ts",
3838
"member": "findData",
3939
"card": "#30054",
40-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
40+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
4141
},
4242
{
4343
"file": "packages/metadata-protocol/src/protocol.ts",
4444
"member": "getData",
4545
"card": "#30054",
46-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
46+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
4747
},
4848
{
4949
"file": "packages/metadata-protocol/src/protocol.ts",
5050
"member": "cloneData",
5151
"card": "#30054",
52-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
52+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
5353
},
5454
{
5555
"file": "packages/metadata-protocol/src/protocol.ts",
5656
"member": "saveMetaItem",
5757
"card": "#30054",
58-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
58+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
5959
},
6060
{
6161
"file": "packages/metadata-protocol/src/protocol.ts",
6262
"member": "publishMetaItem",
6363
"card": "#30054",
64-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
64+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
6565
},
6666
{
6767
"file": "packages/metadata-protocol/src/protocol.ts",
6868
"member": "rollbackMetaItem",
6969
"card": "#30054",
70-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
70+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
7171
},
7272
{
7373
"file": "packages/metadata-protocol/src/protocol.ts",
7474
"member": "deleteMetaItem",
7575
"card": "#30054",
76-
"reason": "inferred-return-type (#29985 report: stays on the class until the return type is spelled)"
76+
"reason": "return type spelled on the signature (#30054 step 1, public .d.ts byte-equal); the body stays until the protocol.ts codemod can move a member of the landed facade (it refuses its own output, and the split no longer re-proves from its #29985 base)"
7777
},
7878
{
7979
"file": "packages/metadata-protocol/src/protocol.ts",

0 commit comments

Comments
 (0)