Skip to content

Commit 40b315b

Browse files
feat(spec)!: retire the connector resilience family — health (probe + breaker), status and nested webhooks, sixteen keys nothing read (#20273) (#20350)
Fixes #20273 Clause-②: no (narrowing) Retires the connector resilience family under ADR-0049 enforce-or-remove, one batch, by the triage verdict RETIRE (comment 5858520070) under the maintainer's criterion on #18900: `connector.health` (the `healthCheck` probe, eight keys, and the `circuitBreaker`, six keys), `connector.status` and the connector-nested `webhooks` — sixteen authorable keys that nothing read. Authoring any of them is now a tsc error and a parse error that carries the prescription; no alias window. ## Census first (origin/main 3f86dc5, each zero beside a lit control) | family | readers outside `packages/spec` | lit control, same scan | |:--|:--|:--| | the fourteen `health.healthCheck.*` / `health.circuitBreaker.*` leaves | 0 (`circuitBreaker`, `fallbackStrategy`, `halfOpenMaxRequests`, `unhealthyThreshold`, `healthyThreshold`, `monitoringWindowMs`, `resetTimeoutMs` outside generated docs; `healthCheck` only as the kernel plugin-health contract; no `.health.` read in `packages/connectors` or `service-automation`) | `retryConfig` read 17 times in `packages/connectors` + `service-automation` | | `status` | 0 connector reads: one member-read pattern over connectors, service-automation, rest, runtime, metadata and objectql finds 38 `.status` reads, every one on an HTTP answer, an error case or a flow-run entry | the same pattern finds `requestTimeoutMs` read off a connector entry / provider context 5 times | | nested `webhooks` | 0 reads of a connector's own array (the one test that authors one pins that it is NOT hoisted) | `stack.webhooks` read 5 times | objectui: nothing imports a removed name at the pinned `.objectui-sha` f8a9d0fb (one comment mentions `WebhookEventSchema`), and no connector `status` / `health` / `webhooks` reader at objectui main 610819c40. No key had a live reader, so no `premise_still_valid` fork. ## What changed - **Tombstones.** `health`, `status`, `webhooks` are `retiredKey()` tombstones on the private `ConnectorBaseSchema` that both published carriers wrap (`ConnectorSchema`, `DeclarativeConnectorEntrySchema`), so `defineConnector`, `registerConnector`, `stack.connectors[]` and `PUT /api/v1/meta/connector/:name` all refuse them. Six `RETIRED_KEYS_BY_MAJOR[18]` rows. - **Residue.** `status` was `.default('inactive')`, emitted by every 17.x parse into every connector; `status: 'inactive'` joins `connectionTimeoutMs: 30000` in `CONNECTOR_RETIRED_KEY_RESIDUE` (accepted and stripped). Every other value is refused. - **Seven defs leave whole** (`RETIRED_DEFS_BY_MAJOR[18]`): `ConnectorHealth`, `HealthCheckConfig`, `CircuitBreakerConfig`, `ConnectorStatus`, `WebhookConfig`, `WebhookEvent`, `WebhookSignatureAlgorithm`. The manifest keys and baseline rows were deleted deliberately after the build named them. - **D2 conversion `connector-resilience-keys-removed`** (step 18, retired from the load path): strips the three keys from `connectors[]` and from stored rows, one notice per key; nested webhooks are stripped, never moved. - **D3 entry `connector-resilience-keys-retired`** (one per family, ruling B on #17152), naming the D2 and the chain below. - **Writers deleted.** `status: 'active'` in the four shipped connector packages and `status: 'error'` on the automation service's degraded husk were writes nothing read back; tsc found the husk's test fixture too. - `packages/spec/docs/SYNC_ARCHITECTURE.md`: the "Monitoring: Health checks" tick is gone, and so are the ticks and example lines this retirement made false (connector webhooks, circuit breaker, `status: 'active'`); the doc's compile gate (`connector-author-shape.test.ts`) holds the example. - `automation/webhook.zod.ts`: its connector-webhook note is corrected, and the `extraKeys: ['signatureAlgorithm']` suggestion is dropped (the only surface accepting that key is gone, so a typo on the delivered webhook would have been pointed at a refused key). - Ledger: `status` and `webhooks` stay one `dead` row each, now tombstones; `connector/webhooks` left the undrilled baseline (the gate called it stale); `state-counts.md` and the README notes cell regenerated / corrected (dead 44 to 30). - Projections regenerated by their generators only: `migrations/registry.ts`, `api-surface/`, `declaration-map/`, `export-origins/`, `authorable-surface/`, `authorable-defaults/`, `json-schema.manifest/`, `content/docs/references/**`, strictness counts, `test-typecheck-debt.json` (shrink only). `spec-changes.json` and `docs/protocol-upgrade-guide.md` do not move: they fold majors up to `PROTOCOL_MAJOR` 17, and this is step 18 (`check:spec-changes` / `check:upgrade-guide` green). - `docs/adr/0122-...md` is NOT edited: no gate forced it. `type-alias-convention.pin.test.ts` loses the three isomorphic pins of the removed enums (783 to 780 on the merged tree; #19920 landed first with its own 786 to 783), the way the error-mapping precedent did. ## Deviations from the dispatch's mechanism assumptions (measured) 1. **Per-key tombstones vs. defs leaving.** The dispatch asked for one tombstone per key AND for `ConnectorHealth` / `ConnectorStatus` to leave via `RETIRED_DEFS_BY_MAJOR`. Both cannot hold for the fourteen `health.*` leaves: once `ConnectorHealth` leaves, its leaves have no shape to carry a tombstone. I followed the error-mapping precedent (13c48c2): one carrier tombstone per key the walk still reaches (`health`, `status`, `webhooks`), defs whole. 2. **"The liveness rows stay dead."** The fourteen drilled `health.*` rows cannot stay: with `health` a leaf, `check:liveness` refuses them (measured: `connector/health (declared children but property is not a container)`). `health` is one `dead` tombstone row whose note carries the fourteen verdicts and their census. 3. **"Rename, then removal."** Keeping the breaker half of `connector-health-and-trigger-durations-unit-in-key` is impossible under the conversion table's disjoint-fixture contract: the rename's own fixture carries a `health` block that the removal strips. Per `spec-property-retirement` §0 (same unreleased step) the breaker half is ABSORBED: the rename now carries only `triggers[].interval`, and the removal serves an author holding either spelling (a pin replays `monitoringWindow` plus a trigger `interval` and gets exactly one rename notice and one removal notice). 4. **`plugin.ts:1792` was not comment-only.** The line under that comment WROTE `status: 'error'` into the husk def, which the tombstone makes a tsc error and a registration-time parse refusal; the write is deleted and the comment corrected. 5. **File surface grew beyond the claim**, each forced by the retirement: the four connector packages and one service-automation test (writers), `automation/webhook.zod.ts` (orphaned `extraKeys`), plugin-webhooks' docblock and its pin test's docblock (they quoted the retired spec prose), `rest-server.test.ts` (a stale comment), `connector-author-shape.test.ts`, `type-alias-convention.pin.test.ts`. ## Acceptance notes - **PR #20255 merged before this PR was finished**, so `main` was merged here and its D3 entry `connector-resilience-durations-unit-in-key` is reconciled in this PR: it now prescribes only `triggers[].interval` to `intervalSeconds` and tells an author holding `monitoringWindow` / `monitoringWindowMs` that the renamed key is itself retired (delete the `health` block). `triggers[].interval` is untouched otherwise. - The out-of-repo consumer population of `@objectstack/spec` is not measured. ## Evidence (head 153f652) - `pnpm --filter @objectstack/spec build` green (manifest and baseline gates fired on the seven defs first, as they must on a whole-def removal, then passed once the rows were deleted deliberately). - `check:generated`: all 15 artifacts current. `check:liveness`, `check:migration-registry`, `check:spec-changes`, `check:upgrade-guide` green. - Gate union from `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` at 153f652, reconciled with `--ran`: 118 derived, 113 run with exit 0, 5 NOT MEASURED — `check:skill-examples`, `check:dual-build-cjs-loads`, `check:i18n`, `check:type-check-debt` refused with exit 3 (PREREQUISITE NOT MET: builds outside this diff's closure — client-react, the CLI plugin set, the whole monorepo), `check:query-options-erasure` (repo-wide ESLint scan; self-test passed, the ratchet outran a 300s per-gate bound — exit 124). CI runs all five. - Tests at 153f652: spec `--project local` over `src/migrations`, `src/conversions`, `src/integration`, the ADR-0122 pin, `rest-server`, `webhook`, `stack` — 18 files, 777 passed; spec `--project repo` (this PR's pin, the connectionTimeoutMs pin, the migrate-sentence pin, two sibling tree-scoped pins, three reference-tree scripts) — 8 files, 221 passed. - Earlier on this branch (pre-second-merge heads): full spec `--project local` 552 files / 16265 passed; `service-automation` 146 files / 1757 passed; connector-mcp / -openapi / -rest / -slack and plugin-webhooks 27 files / 255 passed; typecheck of those six packages green; dogfood `expression-conformance` 7 passed. - ESLint over the 32 changed lintable files (`--no-inline-config --format json`): 32 files, 0 errors, 0 warnings. Population: `eslint.config.mjs` flat config over `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`; the config enables no type-aware linting (no `parserOptions.project`), so this diff cannot move a verdict in an untouched file. The repo-wide `pnpm lint` is CI's. ## Ablation (one per closed door) Via `node scripts/ablation-replace.mjs` (anchor must hit, restore proven by blob hash equal to HEAD and an empty `git diff HEAD`), on committed head 849fb62, running `connector-resilience-keys-retirement.test.ts`: | tombstone deleted (bare strip) | result | |:--|:--| | `health` | 4 failed / 17 passed — REJECTS `health`, the three-door refusal, the either-spelling breaker refusal, the walked-shape pin | | `status` | 4 failed / 17 passed — REJECTS `status`, the three-door refusal, the non-default-value refusal, the walked-shape pin | | `webhooks` | 3 failed / 18 passed — REJECTS `webhooks`, the three-door refusal, the walked-shape pin | Each leg restored to blob 704684d (HEAD's). No permanent ablation test is left. --- _Generated by [Claude Code](https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 789b2ae commit 40b315b

50 files changed

Lines changed: 1769 additions & 1072 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/connector-mcp': patch
4+
'@objectstack/connector-openapi': patch
5+
'@objectstack/connector-rest': patch
6+
'@objectstack/connector-slack': patch
7+
'@objectstack/service-automation': patch
8+
---
9+
10+
feat(spec)!: retire the connector resilience family — `health` (health probe + circuit breaker), `status` and the nested `webhooks`, sixteen keys nothing read (#20273)
11+
12+
**BREAKING** — `connector.health` (the `healthCheck` probe, eight keys, and the
13+
`circuitBreaker`, six keys), `connector.status` and the connector-nested
14+
`webhooks` are removed from `ConnectorSchema` and `DeclarativeConnectorEntrySchema`
15+
— so from `defineConnector`, `stack.connectors[]`, the `PUT /api/v1/meta/connector/:name`
16+
door and `AutomationEngine.registerConnector`. ADR-0049 enforce-or-remove, one
17+
batch for the family, by the maintainer's criterion: does the mainstream platform
18+
offer this capability? Author-configured health probes and circuit breakers are
19+
not connector metadata in the mainstream (breakers live in API-gateway
20+
infrastructure), and an authored status and a nested webhook list duplicate what
21+
is already delivered here by other keys.
22+
23+
Measured before removal, each against a lit control: zero reads of any of the
24+
sixteen keys outside `packages/spec`. No loop ever polled a connector endpoint,
25+
counted consecutive failures or tripped a breaker, and none of the four
26+
`fallbackStrategy` behaviours existed. Nothing read an authored `status`: the
27+
runtime's dispatchability answer is the COMPUTED `state` (`ready` / `degraded`)
28+
on `GET /api/v1/automation/connectors`, which no authored value sets. A webhook
29+
nested in a connector was never registered as a `webhook` item, so it was never
30+
materialized into `sys_webhook` and never delivered.
31+
32+
### FROM → TO
33+
34+
| removed | what to write instead |
35+
| --- | --- |
36+
| `connector.health` (`healthCheck.*`, `circuitBreaker.*`, including `monitoringWindowMs` and the pre-rename `monitoringWindow`) | delete the block. Put health probes and circuit breaking in the connector provider or an upstream gateway. |
37+
| `connector.status` | delete the key. `enabled: false` on a declarative entry is what withdraws a materialized instance or marks a catalog-only descriptor; whether a registered connector can be dispatched is the computed `state`. |
38+
| `connector.webhooks` | delete the array. A webhook that is actually delivered is declared in the stack's top-level `webhooks:` collection — moving one there STARTS deliveries this connector never made, so decide per webhook. `events` and `signatureAlgorithm` have no counterpart there. |
39+
| `ConnectorHealth`, `HealthCheckConfig`, `CircuitBreakerConfig`, `ConnectorStatus`, `WebhookConfig`, `WebhookEvent`, `WebhookSignatureAlgorithm` (schemas, types, `…Parsed` types) | no replacement — nothing parsed or constructed them. |
40+
41+
**The one-line fix: delete `health:`, `status:` and `webhooks:` from every connector.**
42+
`os migrate meta --from 17` lists the mechanical edits for existing sources.
43+
44+
⚠️ Runtime behaviour is deliberately **unchanged**: none of the sixteen keys ever
45+
changed what a connector did. What changes is the answer an author gets — each
46+
key is refused at parse with a prescription, and in `tsc` (its input type is
47+
`never`), instead of being saved with no effect.
48+
49+
### The retirement kit
50+
51+
- **Tombstones.** `health`, `status` and `webhooks` are `retiredKey()` tombstones
52+
on the private `ConnectorBaseSchema` both published carriers wrap (the schema
53+
is not `.strict()`, so a bare deletion would be a silent strip, ADR-0104).
54+
`RETIRED_KEYS_BY_MAJOR[18]`: `integration/Connector:{health,status,webhooks}`
55+
and `integration/DeclarativeConnectorEntry:{health,status,webhooks}`.
56+
- **Retired-default residue.** `status` was `.default('inactive')`, so every 17.x
57+
parse emitted `status: 'inactive'` into every connector; that exact value joins
58+
`connectionTimeoutMs: 30000` in the residue stage (accepted and stripped, so a
59+
def a 17.x toolchain built still registers). Every other value is refused.
60+
- **Seven defs leave whole** (`RETIRED_DEFS_BY_MAJOR[18]`): the four
61+
`integration/` schemas and three enums listed above.
62+
- **D2 conversion `connector-resilience-keys-removed`** (step 18, retired from
63+
the load path): strips the three keys from `connectors[]` and from stored
64+
`sys_metadata` connector rows (the rehydration seam replays it), one notice per
65+
key, as a lossless delete. Nested webhooks are stripped, never moved.
66+
- **The chain.** In the same step, `connector-health-and-trigger-durations-unit-in-key`
67+
renamed `health.circuitBreaker.monitoringWindow` to `monitoringWindowMs`. That
68+
breaker half is absorbed by this removal: the renamed key is itself removed, so
69+
an author holding either spelling ends with no `health` block. The
70+
conversion's `triggers[].interval` → `intervalSeconds` rename is unaffected.
71+
- **D3 entry `connector-resilience-keys-retired`** carries the family's
72+
judgement: which probe, breaker or nested webhook the author actually relied
73+
on, and where it goes now.
74+
- **Writers deleted.** The four shipped connector packages wrote
75+
`status: 'active'` and the automation service's degraded husk wrote
76+
`status: 'error'`; nothing read either back, and both writes are gone.
77+
- **No deprecation window**, per the project's startup-stage posture.
78+
79+
⚠️ **The out-of-repo consumer population is NOT MEASURED.** `@objectstack/spec`
80+
is published, so this is breaking for consumers no telemetry was consulted for.
81+
82+
Clause-②: no (narrowing)
83+
84+
<!-- adr-0087: registered connector-resilience-keys-removed, connector-resilience-keys-retired -->

‎content/docs/references/index.mdx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Protocol Reference
3-
description: Every schema published by @objectstack/spec — 1523 schemas across 14 protocol modules
3+
description: Every schema published by @objectstack/spec — 1516 schemas across 14 protocol modules
44
---
55

66
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -24,7 +24,7 @@ counts are sums of the rows they head. Regenerate with
2424
| [Automation Protocol](/docs/references/automation) | 14 | 75 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. |
2525
| [Data Protocol](/docs/references/data) | 29 | 175 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. |
2626
| [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. |
27-
| [Integration Protocol](/docs/references/integration) | 1 | 24 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. |
27+
| [Integration Protocol](/docs/references/integration) | 1 | 17 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. |
2828
| [Kernel Protocol](/docs/references/kernel) | 30 | 157 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. |
2929
| [Marketplace Protocol](/docs/references/marketplace) | 4 | 30 | The package & marketplace format — package identity and versions, listing, publish, review, search, install, template manifests. |
3030
| [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. |
@@ -33,7 +33,7 @@ counts are sums of the rows they head. Regenerate with
3333
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
3434
| [System Protocol](/docs/references/system) | 34 | 275 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
3535
| [UI Protocol](/docs/references/ui) | 16 | 159 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
36-
| **Total** | **196** | **1523** | 14 protocol modules |
36+
| **Total** | **196** | **1516** | 14 protocol modules |
3737

3838
---
3939

@@ -186,13 +186,13 @@ Users and accounts, organizations, positions, SCIM provisioning.
186186

187187
## Integration Protocol
188188

189-
**Source:** `packages/spec/src/integration/` · **Import:** `@objectstack/spec/integration` · **1 page, 24 schemas**
189+
**Source:** `packages/spec/src/integration/` · **Import:** `@objectstack/spec/integration` · **1 page, 17 schemas**
190190

191191
The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances.
192192

193193
| File | Schemas |
194194
| :--- | :--- |
195-
| [`connector.zod.ts`](/docs/references/integration/connector) | `CircuitBreakerConfig`, `Connector`, `ConnectorAction`, `ConnectorActionEffect`, `ConnectorConflictResolution`, `ConnectorFieldMapping`, `ConnectorHealth`, `ConnectorInstanceAPIKeyAuth`, `ConnectorInstanceAuth`, `ConnectorInstanceBasicAuth`, `ConnectorInstanceBearerAuth`, `ConnectorInstanceNoAuth`, `ConnectorRetryStrategy`, `ConnectorStatus`, `ConnectorTrigger`, `ConnectorType`, `DataSyncConfig`, `DeclarativeConnectorEntry`, `HealthCheckConfig`, `RetryConfig`, `SyncStrategy`, `WebhookConfig`, `WebhookEvent`, `WebhookSignatureAlgorithm` |
195+
| [`connector.zod.ts`](/docs/references/integration/connector) | `Connector`, `ConnectorAction`, `ConnectorActionEffect`, `ConnectorConflictResolution`, `ConnectorFieldMapping`, `ConnectorInstanceAPIKeyAuth`, `ConnectorInstanceAuth`, `ConnectorInstanceBasicAuth`, `ConnectorInstanceBearerAuth`, `ConnectorInstanceNoAuth`, `ConnectorRetryStrategy`, `ConnectorTrigger`, `ConnectorType`, `DataSyncConfig`, `DeclarativeConnectorEntry`, `RetryConfig`, `SyncStrategy` |
196196

197197
---
198198

0 commit comments

Comments
 (0)