Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .changeset/33522-retire-describe-managed-api-method-conflicts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
'@objectstack/spec': patch
---

refactor(spec)!: retire `describeManagedApiMethodConflicts`, an export of `@objectstack/spec/data` that nothing calls

Clause-②: no (narrowing)
Metadata-protocol: none

<!-- adr-0087: not-required (no-migration-prescription) No metadata moves: no key of any schema, authorable spelling, object definition, stored row or stored shape is added, removed, renamed or re-shaped. The one change is a removed runtime function of the `@objectstack/spec/data` subpath, so there is nothing for `objectstack migrate meta` to rewrite and no tombstone. The other categories are closed on facts: `@objectstack/spec` publishes (not unpublished); no ADR-0087 id covers the function and this diff adds none (not registered or already-registered); it is a function, not an interface or a type narrowed off `any` (not runtime-interface-only or type-surface-only); and `runtime-export-retired` reads only a package's root entry at this revision, which never exported this name (it is reachable from the `./data` subpath alone), so that category cannot verify it. -->

**BREAKING** for a TypeScript caller that imports `describeManagedApiMethodConflicts` from `@objectstack/spec/data`. None is known: in this repository (`ui/` and `examples/` included), in hotcrm and in gallery the name occurs only in its own declaration, its own test and the generated surface snapshots. The lint rule `object/managed-api-method-unaffordable` and the registry's boot-time strip each word their own message from `checkManagedApiMethodAffordances`, so the helper's sentence reached no author or operator. That sentence also named `userActions` as the remedy on every `managedBy` bucket, which is wrong on a `synced` object, whose parse refuses a `userActions` override that opens a write.

**What stays.** `checkManagedApiMethodAffordances`, `ManagedApiMethodConflict` and `MANAGED_WRITE_VERB_AFFORDANCE` are unchanged, and so is every verdict the lint rule and the registry strip reach.

**For a caller.** The compiler names the import (`TS2305: Module '"@objectstack/spec/data"' has no exported member 'describeManagedApiMethodConflicts'`). Delete it, and word the message from the `verb` and `needs` of each conflict `checkManagedApiMethodAffordances` returns, for the object's own `managedBy` bucket. **No deprecation window** (startup-stage posture: a shipped capability with no consumer retires at once).
1 change: 0 additions & 1 deletion packages/spec/api-surface/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,6 @@
"deriveInlineRowFormFields (function)",
"deriveRecordFlowSurface (function)",
"deriveRecordSurface (function)",
"describeManagedApiMethodConflicts (function)",
"discriminateDefaultValueShape (function)",
"driverConfigJsonSchema (function)",
"driverHasLocalDefault (function)",
Expand Down
1 change: 0 additions & 1 deletion packages/spec/export-origins/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,6 @@
"deriveInlineRowFormFields": "src/data/inline-grid-columns.ts#deriveInlineRowFormFields (function)",
"deriveRecordFlowSurface": "src/data/record-surface.ts#deriveRecordFlowSurface (function)",
"deriveRecordSurface": "src/data/record-surface.ts#deriveRecordSurface (function)",
"describeManagedApiMethodConflicts": "src/data/managed-api-affordance.ts#describeManagedApiMethodConflicts (function)",
"discriminateDefaultValueShape": "src/data/default-value-shape.ts#discriminateDefaultValueShape (function)",
"driverConfigJsonSchema": "src/data/driver/common.zod.ts#driverConfigJsonSchema (function)",
"driverHasLocalDefault": "src/data/driver/config-registry.zod.ts#driverHasLocalDefault (function)",
Expand Down
31 changes: 0 additions & 31 deletions packages/spec/src/data/managed-api-affordance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { describe, expect, it } from 'vitest';
import {
MANAGED_WRITE_VERB_AFFORDANCE,
checkManagedApiMethodAffordances,
describeManagedApiMethodConflicts,
type ManagedApiMethodConflict,
} from './managed-api-affordance';

Expand Down Expand Up @@ -133,33 +132,3 @@ describe('the verb → affordance table', () => {
expect(Object.isFrozen(MANAGED_WRITE_VERB_AFFORDANCE)).toBe(true);
});
});

describe('describeManagedApiMethodConflicts', () => {
it('names the verbs and the affordance they would need', () => {
const msg = describeManagedApiMethodConflicts(checkManagedApiMethodAffordances(managed()));
expect(msg).toContain('create, update, delete');
expect(msg).toContain('userActions create/edit/delete');
expect(msg).toContain('enable.apiMethods');
expect(msg).toContain('ADR-0092');
});

it('states the contradiction only — the remedy belongs to each consumer', () => {
const msg = describeManagedApiMethodConflicts(checkManagedApiMethodAffordances(managed()));
expect(msg).not.toMatch(/\b(drop|remove|Either)\b/);
});

it('does not repeat an affordance flag shared by two verbs', () => {
const msg = describeManagedApiMethodConflicts(
checkManagedApiMethodAffordances(managed({ enable: { apiMethods: ['update', 'upsert'] } })),
);
expect(msg).toContain('needs userActions edit)');
});

it('reads correctly for a single conflict', () => {
const msg = describeManagedApiMethodConflicts(
checkManagedApiMethodAffordances(managed({ enable: { apiMethods: ['get', 'delete'] } })),
);
expect(msg).toContain('[delete]');
expect(msg).toContain('needs userActions delete)');
});
});
22 changes: 0 additions & 22 deletions packages/spec/src/data/managed-api-affordance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,25 +127,3 @@ export function checkManagedApiMethodAffordances(schema: unknown): ManagedApiMet
}
return out;
}

/**
* The one sentence both consumers say about a conflict, so an operator who
* greps a stripped verb out of a boot log and an author reading the lint
* finding are told the same thing in the same words.
*
* States the CONTRADICTION only. Each consumer appends its own remedy, because
* the honest remedy differs by where you are standing: at registration the verb
* has already been taken away and the operator's next move is to find the
* author, while at authoring time both doors — open the affordance, or drop the
* verb — are still open.
*/
export function describeManagedApiMethodConflicts(
conflicts: readonly ManagedApiMethodConflict[],
): string {
const verbs = conflicts.map((c) => c.verb).join(', ');
const flags = [...new Set(conflicts.map((c) => c.needs))].join('/');
return (
`advertises generic write verb(s) [${verbs}] in enable.apiMethods that its resolved ` +
`affordances do not permit (needs userActions ${flags}) — see ADR-0092 / ADR-0103.`
);
}
Loading