Skip to content

Commit ce12e11

Browse files
committed
fix(spec): list the five service-ai-studio tools the AI registry was omitting
`PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio']` omitted five tools the cloud AI runtime actually registers — `get_authoring_rules`, `load_tools`, `open_record`, `test_flow` and `toggle_flow` — so under ADR-0109, where the default authoring path declares no tool records at all, a skill naming any of them resolved against nothing and was reported by `validate`/`lint` as a FICTIONAL tool reference. That is the exact failure the registry exists to end. Added in the list's existing alphabetical order (verified: both groups were in fact sorted before this change, and the package's own shape test pins it). Nothing else in the registry moves. The pin lives in `packages/lint`, where "refused" and "accepted" are the verdicts: the five now resolve, and a sixth name shaped like them and registered by nobody is still reported — the control, without which the widening pin cannot fail. Fixes #16512 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
1 parent f89812e commit ce12e11

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
`PLATFORM_TOOLS_BY_PACKAGE['service-ai-studio']` lists the five tools the cloud AI runtime registers that it had been omitting: `get_authoring_rules`, `load_tools`, `open_record`, `test_flow` and `toggle_flow`. Added in the list's existing alphabetical order; nothing else in the registry moves.
6+
7+
The omission was not cosmetic. `PLATFORM_PROVIDED_TOOL_NAMES` is the load-bearing half of `skill.tools[]` reference integrity under ADR-0109 — the default third-party authoring path declares no tool records at all, so a `skill.tools[]` entry resolves against this registry or against the materialised `action_<name>` family and against nothing else. While these five were absent, a skill naming any of them was reported by `validate` / `lint` as a **fictional** tool reference (`ai-skill-tool-unresolved`), which is precisely the failure the registry was created to end. Five previously-refused references are now accepted; a name registered by nobody is still refused.
8+
9+
The module's own maintenance contract already said why an omission is worse than no registry at all — "an out-of-date registry is worse than no registry, because consumers now trust it" — and a second consumer had already paid for it: `@objectstack/mcp` gives a listed name `openWorldHint: false`, and the Studio's tool-step labels read the same set.
10+
11+
This is the data half only. Making the owning package's conformance test **derive** the union from what `plugin.ts` actually registers, instead of restating it, is tracked separately in the cloud repository; re-copying the list correctly resets the clock rather than stopping it.

packages/lint/src/validate-ai-tool-references.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,33 @@ describe('validate-ai-tool-references', () => {
159159
expect(validateAiToolReferences(stack)).toEqual([]);
160160
});
161161

162+
/**
163+
* [#16512] The five `service-ai-studio` tools the cloud runtime registers
164+
* that the registry did not list.
165+
*
166+
* `PLATFORM_PROVIDED_TOOL_NAMES` is the load-bearing half of
167+
* `skill.tools[]` reference integrity under ADR-0109, so while these five
168+
* were absent a skill naming any of them was reported as a FICTIONAL tool —
169+
* the precise failure the registry exists to end. The pin lives here, not
170+
* beside the constant: "refused" and "accepted" are this rule's verdicts,
171+
* and the list's own file can only pin its shape.
172+
*/
173+
it('resolves the five service-ai-studio tools the registry was missing (#16512)', () => {
174+
const five = ['test_flow', 'toggle_flow', 'get_authoring_rules', 'load_tools', 'open_record'];
175+
expect(validateAiToolReferences({ skills: [{ name: 's', tools: five }] })).toEqual([]);
176+
177+
// The control, without which this pin cannot fail: a sixth name shaped
178+
// exactly like the five and registered by nobody is STILL reported. A
179+
// universe widened until everything resolves would pass the assertion
180+
// above and fail this one.
181+
const control = validateAiToolReferences({
182+
skills: [{ name: 's', tools: [...five, 'archive_flow'] }],
183+
});
184+
expect(control).toHaveLength(1);
185+
expect(control[0].path).toBe('skills[0].tools[5]');
186+
expect(control[0].message).toContain('archive_flow');
187+
});
188+
162189
it('reports stable paths and tolerates junk shapes', () => {
163190
const stack = {
164191
skills: [{ name: 's', tools: ['query_records', 'nope_tool'] }],

packages/spec/src/system/constants/platform-tool-names.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,21 @@ export const PLATFORM_TOOLS_BY_PACKAGE: Readonly<Record<string, readonly string[
6565
'describe_metadata',
6666
'describe_object',
6767
'get_active_package',
68+
'get_authoring_rules',
6869
'get_metadata_schema',
6970
'get_package',
7071
'list_metadata',
7172
'list_objects',
7273
'list_packages',
74+
'load_tools',
7375
'modify_field',
76+
'open_record',
7477
'propose_blueprint',
7578
'set_active_package',
7679
'suggest_builder',
80+
'test_flow',
7781
'todo_write',
82+
'toggle_flow',
7883
'update_metadata',
7984
'validate_expression',
8085
'verify_build',

0 commit comments

Comments
 (0)