Skip to content

feat(usai-provider): self-register provider facts + own normalizer + vendored fallback (ADR 0004 Layer 1) #424

Open

Description

@wz-gsa

Summary

Layer 1 of ADR 0004 (integrations/isolation/docs/decisions/0004-neutral-model-provider-discovery.md, PR #423). This is the first buildable slice — independently useful and testable even before Layer 2 (the models orchestrator kit) exists.

Scope

  1. Self-registration facts file. usai-provider's startup phase writes a small, static JSON facts file to /var/lib/acq/models/providers/usai.json:

    {
      "schemaVersion": "acq-provider-facts/v1",
      "providerId": "usai",
      "host": "api.gsa.usai.gov",
      "baseUrl": "https://api.gsa.usai.gov/api/v1",
      "modelsUrl": "https://api.gsa.usai.gov/api/v1/models",
      "keyEnv": "USAI_API_KEY"
    }

    /var/lib/acq/ is root-owned (mirrors the existing kit-env marker convention, acq.backends/msb.sh:1571 in quickstart) — not agent-writable, so a compromised agent process cannot plant a bogus provider entry.

  2. Env-var-ownership invariant (security-load-bearing, from the ADR's incorporated dissent). keyEnv MUST name a variable this SAME kit's own spec.yaml environment:/secret-binding declares. Add a scripts/verify assertion (or a validate-kits.py check) that fails if the facts file's keyEnv doesn't match the kit's own declared name — this is the mechanical check that prevents a provider kit from ever naming a credential it doesn't own.

  3. Provider's own normalizer. A small script (raw USAi /models response → the neutral catalog schema defined in ADR 0004) ships inside usai-provider's own kit directory. This can reuse/extract logic from the existing scripts/sync-usai-models.mjs rather than starting from scratch.

  4. Provider's own vendored fallback snapshot. A small, committed, last-known-good model list, used when live refresh fails (this issue doesn't build the refresh mechanism yet — Layer 2 does — but the snapshot file and its shape should exist so Layer 2 has something to fall back to on day one).

Explicitly out of scope for this issue

  • The models orchestrator kit itself (separate issue, Layer 2).
  • Any change to usai-provider's existing opencode.jsonc rendering — unaffected until Layer 3 wires the harness kit to read the new neutral aggregate.
  • goose-server migration (separate issue once this lands, to fix the confirmed usai/goose-usai secret-duplication bug via the SAME provider identity).

Verification

  • sh -n / shellcheck --severity=warning on any new script.
  • scripts/scan_unsafe_shell.py on any new script.
  • validate-kits.py --strict (kit still valid).
  • Live RUN_ACQ=1 scripts/verify: assert the facts file exists at the expected path post-boot, has the expected shape, and keyEnv matches the kit's own declared env var name.

References

  • ADR 0004: docs(isolation): add ADR 0004 for neutral model-provider discovery #423
  • Confirmed secret-duplication bug this eventually fixes (Layer 1 lays the groundwork; full fix lands when goose-server migrates): usai-provider registers service usai; in-flight goose-server independently registers the same USAi credential as goose-usai — traced via acq.backends/secret-store.sh's _acq_secret_key (dedupes by service-name string only, never by host).

Activity

  1. changed the title [-]feat(usai-provider): self-register provider facts + own normalizer + vendored fallback (ADR 0003 Layer 1)[/-] [+]feat(usai-provider): self-register provider facts + own normalizer + vendored fallback (ADR 0004 Layer 1)[/+] on Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions