I1202 — One typed provider model reads the objects, and no code names a provider
Add apps/majordomus-cli/src/identity with the typed model of a provider object: discovery of every object under .ai/repo/identity/providers/, validation against the schema, resolution of the credential environment variables at use rather than at load, and a deterministic ordering of the sign-in offer. Expose the read as a capability so the provider list reaches the CLI, the API, OpenAPI, MCP and the Cockpit through the registry rather than through five readers.
BLOCKED wave 1 · p0 · implementation profile · runs alone
Part of web-sign-in — The deployed surfaces know who is asking, and the identity providers are data.
Blocked. This issue cannot start until I1201 is done. The status is derived from that, not declared.
Objective
Add apps/majordomus-cli/src/identity with the typed model of a provider object: discovery of every object under .ai/repo/identity/providers/, validation against the schema, resolution of the credential environment variables at use rather than at load, and a deterministic ordering of the sign-in offer. Expose the read as a capability so the provider list reaches the CLI, the API, OpenAPI, MCP and the Cockpit through the registry rather than through five readers.
Why
The objects are only canonical if exactly one thing parses them. A second reader in the Cockpit or in the HTTP layer would be a second definition of what a provider is, and would drift the first time the schema gains a field.
Current state
I1201 has the objects; nothing reads them.
Desired state
identity::providers() returns the validated, ordered set; a provider whose credentials are absent is reported as unavailable with a reason rather than omitted silently; and grep for the strings google and facebook in apps/ returns nothing outside tests and fixtures.
Scope
- apps/majordomus-cli/src/identity
- apps/majordomus-cli/src/capability/builtin
- apps/majordomus-cli/src/lib.rs
- apps/majordomus-cli/tests
Out of scope
- The HTTP flow, which is I1203
- Reading a credential value into any type that is serialised, cached, logged or rendered
Dependencies
What waits on this
- I1203BLOCKED One flow serves every provider, and it refuses everything it did not start
- I1208BLOCKED Adding a provider is one file, removing one is one deletion, and both are executed rather than described
Acceptance criteria
- The provider set is discovered from the directory, validated, and ordered deterministically
- A provider with absent credentials is unavailable with a stated reason, and the reason reaches the surfaces
- No provider identifier appears in the executable's source outside test fixtures
- The read is declared once as a capability and appears in CLI, HTTP, OpenAPI, MCP and docs with no second registration
Validation
- cargo test --workspace --all-features
- cargo clippy --workspace --all-targets --all-features -- -D warnings
- majordomus generate --check
Evidence required
- typed_model
- capability_projected
- no_provider_names_in_code
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Risk
Resolving credentials at load makes the model unusable in any context that serialises it. They are resolved at the moment of the flow and never held.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I1202.yaml. Read it back with majordomus plan show I1202.