Skip to content

Commit 9fced18

Browse files
committed
feat(automation): expose connector origin on ConnectorDescriptor (ADR-0096 #2977)
`getConnectorDescriptors()` (served by GET /api/v1/automation/connectors) now includes `origin: 'plugin' | 'declarative'` per connector, so a designer can tell a materialized declarative instance (ADR-0096) apart from a plugin-registered connector. Additive: the field is always present; existing consumers ignore it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
1 parent 468b068 commit 9fced18

3 files changed

Lines changed: 18 additions & 2 deletions

File tree

.changeset/adr-0096-runtime-rematerialization.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@ is now a **reconcile** run both at boot and on `metadata:reloaded`:
1919
the same problems are logged and the offending entry skipped, so a bad publish
2020
never crashes a running server; a changed instance's old connector keeps
2121
serving until its replacement materializes successfully.
22+
23+
Also: `ConnectorDescriptor` (served by `GET /api/v1/automation/connectors`) now
24+
carries an `origin` field (`'plugin' | 'declarative'`), so a designer can
25+
distinguish a materialized declarative instance from a plugin-registered
26+
connector.

packages/services/service-automation/src/connector-materialization.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ describe('ADR-0096 — declarative connector materialization', () => {
203203
const desc = engine.getConnectorDescriptors().find((d) => d.name === 'billing');
204204
expect(desc).toBeDefined();
205205
expect(desc?.actions.map((a) => a.key)).toEqual(['ping']);
206-
// Origin is 'declarative', not 'plugin'.
206+
// Origin is 'declarative', not 'plugin' — surfaced on the descriptor so a
207+
// designer can distinguish a materialized instance from a plugin connector.
208+
expect(desc?.origin).toBe('declarative');
207209
expect(engine.getConnectorOrigin('billing')).toBe('declarative');
208210
// The factory saw the declared identity.
209211
expect(calls[0]?.name).toBe('billing');

packages/services/service-automation/src/engine.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,14 @@ export interface ConnectorDescriptor {
246246
readonly description?: string;
247247
readonly icon?: string;
248248
readonly actions: ConnectorActionDescriptor[];
249+
/**
250+
* How the connector reached the registry (ADR-0096 §4): `plugin` — registered
251+
* by a connector plugin via `registerConnector`; `declarative` — materialized
252+
* from a provider-bound `connectors:` stack entry at boot. Lets a designer
253+
* distinguish a live declarative instance from a plugin connector (and both
254+
* from an inert catalog descriptor, which never reaches this list).
255+
*/
256+
readonly origin: ConnectorOrigin;
249257
}
250258

251259
// ─── Core Automation Engine ─────────────────────────────────────────
@@ -926,12 +934,13 @@ export class AutomationEngine implements IAutomationService {
926934
* Handlers are omitted — they are runtime code, not metadata.
927935
*/
928936
getConnectorDescriptors(): ConnectorDescriptor[] {
929-
return [...this.connectors.values()].map(({ def }) => ({
937+
return [...this.connectors.values()].map(({ def, origin }) => ({
930938
name: def.name,
931939
label: def.label,
932940
type: def.type,
933941
description: def.description,
934942
icon: def.icon,
943+
origin,
935944
actions: (def.actions ?? []).map((a) => ({
936945
key: a.key,
937946
label: a.label,

0 commit comments

Comments
 (0)