feat(concelier): blocked-readiness state for credential-gated sources (SRC-CREDS-005)

Closes the last open task in SPRINT_20260422_003. Persisted operator
enablement is now separated from runtime readiness so credential-gated
sources can show an explicit blocked state instead of collapsing into a
generic failed/disabled shape.

Readiness model:
- new SourceReadiness constants class: Disabled | Unsupported | Blocked | Ready
- ConfiguredAdvisorySourceStatus gains Readiness + BlockedReason alongside
  existing SyncState (kept as backward-compatible alias)
- enabled = persisted operator intent (untouched)
- readiness = blocked when persisted-enabled and credentials/URIs missing
- blockedReason = free-form list of missing fields
- blockingReason.errorCode = SOURCE_CONFIG_REQUIRED for structured drill-down

Endpoint propagation:
- /status: persisted enabled=true kept; readiness=blocked; readyForSync=false
- /{id}/enable: 200 with readiness=blocked; sourceRegistry left disabled
  until credentials land (pre-existing behaviour retained)
- /{id}/sync: 422 readiness=blocked + SOURCE_CONFIG_REQUIRED;
  **connector never invoked**, no job run created
- /sync (batch): per-result outcome=blocked with readiness/errorCode/
  blockedReason; excluded from totalTriggered; other sources proceed
- Transition: PUT /{id}/configuration with missing credential →
  runtimeOptionsInvalidator.Invalidate → next /status flips to ready.
  No disable/re-enable cycle needed.

Tests: 8 targeted xUnit methods via scripts/test-targeted-xunit.ps1,
8/8 pass. Includes: blocked status exposure, blocked-to-ready transition
on persisted credential, connector-not-invoked-when-blocked, plus 4
pre-existing SRC-CREDS-002 regression tests.

Docs:
- docs/modules/concelier/connectors.md — new "Blocked / sleeping
  readiness state" section with field contract, per-endpoint behaviour
  table, UI/CLI rendering guidance, resolution flow
- docs/modules/cli/guides/commands/db.md — short note under
  `db connectors configure` cross-linking the connectors.md contract

Sprint SPRINT_20260422_003 archived — all 5 tasks DONE.

New fields are additive; existing UI types in
source-management.api.ts ignore unknown fields so no UI breakage. A
future FE pass can wire explicit readiness/blockedReason rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-22 16:28:33 +03:00
parent 06a8558b0f
commit 838257245a
6 changed files with 441 additions and 50 deletions

View File

@@ -55,6 +55,12 @@ Notes:
- Multi-value URI fields accept comma-, semicolon-, or newline-separated absolute URIs.
- The current CLI path sends literal values on the command line. Use the Web UI path if command-history exposure is unacceptable for a secret.
Blocked state for credential-gated sources:
- Persisted enablement (`enabled=true`) is kept separate from runtime readiness. When an enabled source is missing required credentials or URIs, its `readiness` (alias `syncState`) is `blocked`, `blockedReason` describes what is missing, and both `/sync` and the batch `/sync` paths skip it with an explicit `blocked` outcome instead of invoking the connector and emitting a misleading scheduler failure.
- Supplying the missing field through `stella db connectors configure <source> --set <field>=<value>` flips the source to `readiness=ready` on the next status call without any disable/re-enable step.
- See [connectors.md -> Blocked / sleeping readiness state](/C:/dev/New%20folder/git.stella-ops.org/docs/modules/concelier/connectors.md) for the full endpoint contract.
### db fetch
Trigger a connector stage (`fetch`, `parse`, or `map`) for a given source.