You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4f8c2d1
Browse filesBrowse the repository at this point in the historyBrowse files
A provider factory can throw ConnectorUpstreamUnavailableError (spec) to mark an operational fault; the reconcile degrades that instance (visible husk with state/degradedReason, or old connector keeps serving on changed-config failures) and retries with exponential backoff plus on every metadata:reloaded. Configuration faults stay fatal at boot. The mcp provider classifies connect/tools-list failures as unavailable.
`credentialRef`, name conflict — authoring mistakes — stay fatal at boot. But a
140
+
provider whose factory must contact an upstream to materialize (the `mcp`
141
+
provider connects and calls `tools/list`) can fail because that upstream is
142
+
*temporarily unreachable*; aborting the whole app boot for one integration's
143
+
network blip turns a degraded connector into a total outage.
144
+
145
+
A factory signals the operational case by throwing an error carrying the
146
+
`CONNECTOR_UPSTREAM_UNAVAILABLE` code (`ConnectorUpstreamUnavailableError` in
147
+
`@objectstack/spec/integration`; the materializer's check is structural, not
148
+
`instanceof`). The reconcile then — in both boot and reload modes — **degrades**
149
+
that one instance instead of failing the run:
150
+
151
+
- With no live connector under the name, an action-less husk is registered
152
+
(`state: 'degraded'` + `degradedReason` on the descriptor, `status: 'error'`
153
+
on the def) so `GET /connectors` shows the instance honestly instead of it
154
+
silently missing, and a `connector_action` dispatch fails with the reason and
155
+
"the platform retries automatically" — never the generic wiring hint.
156
+
- On a changed-config re-materialization, the previous live connector keeps
157
+
serving untouched (the same guarantee every other reload failure gives).
158
+
- Degraded instances are retried on an exponential backoff (5s doubling to a
159
+
5-minute ceiling; a config edit resets it) and immediately by any reconcile
160
+
(`metadata:reloaded`). Recovery replaces the husk atomically via
161
+
`registerConnector`; an instance deleted while degraded is dropped, husk and
162
+
pending retry included.
163
+
164
+
The `mcp` provider classifies connect / `tools/list` failures as unavailable;
165
+
transport-shape validation stays a plain (fatal) throw. Lazy connect-on-first-
166
+
dispatch was rejected: MCP actions ARE the server's `tools/list`, so a
167
+
connector materialized without connecting would register a zero-action def —
168
+
exactly the plausible-but-dead shape this ADR exists to kill.
169
+
135
170
### Deliberate scope boundaries
136
171
137
172
-**`providerConfig.spec` (openapi)** accepts an inline document, an http(s) URL, **or a package-relative file path** (#3016 follow-up). The connector still owns no filesystem access: the automation service injects a `loadPackageFile` capability into `ConnectorProviderContext` that resolves the ref against the declaring stack/package root (`packageRoot`, CLI default: the `objectstack.config.ts` directory) and **confines reads to that root** — absolute and `..`-escaping paths are rejected. Read/parse failures follow the reconcile policy above: fatal at boot, skipped on reload.
138
173
-**MCP credentials** ride the transport (ADR-0024); for an http transport a resolved `auth` is folded into the request headers.
139
-
-**MCP at boot** connects during materialization, so an unreachable server fails boot; a fail-soft "optional" marker for boot-time materialization is a possible future refinement (runtime reloads are already soft).
174
+
-**A live `provider: 'mcp'` showcase demo** remains deferred: materialization needs a reachable MCP server, and the natural in-repo target (`@objectstack/mcp`, the platform's own MCP endpoint) is not listening until after the automation plugin's `start()` — the demo would deterministically boot degraded and heal seconds later, making the dogfood CI gate timing-sensitive. It should land together with an in-repo MCP fixture server (or an explicit boot-ordering story for self-connection).
175
+
-**The openapi provider's remote-URL spec fetch** still throws plain on network failure (fatal at boot). It can adopt the same `CONNECTOR_UPSTREAM_UNAVAILABLE` classification once operators ask for it — the mechanism is provider-agnostic.
0 commit comments