T01 connector_base + docs/discovery-connectors.md (read-only/stateless, candidate->PR->promote; `candidate` added to schema status enum; candidates/ gitignored, excluded from gate). T02 connector_reposcoping (repo-scoping facts -> candidates; graceful degrade). T03 connector_gitconfig (deterministic scan; real .env -> secret-ref, no values; verified 4 real candidates from ~/state-hub). T04 connector_featurecontrol (feature-flag surfaces linking to feature-control keys, no eval logic; FR-12). T05 registry_health (unowned + stale detection). Make targets: connect-gitconfig/reposcoping/featurecontrol, registry-health. WP-0003 finished (5/5). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3.2 KiB
Discovery Connectors
Status: draft
Updated: 2026-06-27
Repo: config-atlas
Workplan: ATLAS-WP-0003 (Phase 2)
Related: ../specs/ArchitectureBlueprint.md §4/§6,
ecosystem-boundaries.md §2.4,
configuration-surface-schema.md
Connectors grow the surface registry from automated discovery instead of only
hand authoring — reusing repo-scoping's scanner → candidate → approval model
rather than building bespoke approval machinery.
Contract
A connector MUST:
- be read-only and stateless — never write a source system, never auto-merge;
- never read or store configuration values or secret values — record file locations and key/flag identities only;
- emit candidate surface entries (
status: candidate) with provenance inevidence.discovery_method = connector:<name>; - produce schema-valid entries (validated by
connector_base.emit_candidate); - never overwrite a promoted entry — if an id already exists under
registry/surfaces/*.md, the candidate is skipped (the registry is truth).
Connectors propose; humans/agents dispose.
Candidate lifecycle
connector -> registry/surfaces/candidates/<id>.md (status: candidate)
-> PR review (human or trusted agent)
-> promote: move to registry/surfaces/<id>.md (status: draft|active),
add row to registry/indexes/surfaces.yaml, set a real owner
-> or reject: delete the candidate
Candidates live in registry/surfaces/candidates/ and are excluded from the
promoted-entry validation/index gate (tools/validate_registry.py globs
registry/surfaces/*.md non-recursively), so unreviewed candidates never become
registry truth or break the index. The candidates directory is gitignored —
candidates are ephemeral connector output; promotion moves an entry into the
tracked registry/surfaces/ and surfaces.yaml.
Connectors
| Connector | Source | Emits | Command |
|---|---|---|---|
git-config |
repo config files (*.env.example, values*.yaml, config*.yaml); real .env → secret-ref |
app/deploy/secret-ref candidates | make connect-gitconfig REPO=<slug> |
repo-scoping |
repo-scoping observed facts (--facts file or REPO_SCOPING_URL) |
app-config candidates | make connect-reposcoping REPO=<slug> |
feature-control |
feature-control key registry (--keys or its index) |
feature-flag candidates (link only) | make connect-featurecontrol |
All degrade gracefully (emit nothing) when their source is unavailable.
Health
make registry-health (tools/registry_health.py) reports unowned surfaces
(missing owner, or owner not resolvable to a known identity) and stale surfaces
(evidence.last_seen older than the threshold). Ownership resolution currently
uses the reuse-surface roster as a stand-in until domain-tree binding is wired.
Boundaries
Connectors reuse repo-scoping's discovery model and never duplicate it; the
feature-control connector links to feature-control keys and never re-derives
evaluation logic (PRD FR-12). See ecosystem-boundaries.md.