Skip to content

feat(isolation): define provider-neutral input contract - #518

Merged
basiliskus merged 6 commits into
mainfrom
feat/517-provider-input-contract
Oct 21, 2026
Merged

basiliskus merged 6 commits into
mainfrom
feat/517-provider-input-contract

Conversation

@mogul

@mogul mogul commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Define the validated, provider-neutral files that provider kits give to agent kits. USAi and a fictitious second provider use the same protocol contract, proving consumers do not need USAi-specific branches.

Issue resolved

#517

  • Separates provider connection facts from neutral model catalogs.
  • Defines stable packaged and projected paths.
  • Declares the bounded API protocol used by harness-owned static mappings.
  • Allows optional advisory model recommendations without harness-specific keys.
  • Validates identifiers, URLs, credentials, files, catalogs, and cross-file references.

Before and after

Before this PR: Provider metadata existed in overlapping USAi-specific shapes, and agent kits had no single validated contract or stable location from which to consume it.

After merge: Every provider kit can publish the same validated facts-and-catalog bundle, including a precise API protocol, while each agent kit retains ownership of its native configuration.

Verification

  • Provider contract tests: 143 passed
  • make validate-provider-input-contract: passed
  • make validate-kits: passed
  • make test-kits: passed
  • Scoped Ruff and git diff --check: passed
  • Independent adversarial review: speculative platform adapters removed; no remaining blockers

Security impact

The validator fails closed on unsafe paths, symlink escapes, credential ownership mismatches, malformed URLs, unsupported protocols, duplicate IDs, dangling recommendations, and invalid normalizer output. Protocol values are mapped by consumers through static allowlists, not dynamic imports or execution. No credential values are stored.

Relationships

Fixes: #517
Parent epic: #357
Blocks: #516 and GSA-TTS/agentic-coding-quickstart#600

Rollback

Revert this PR. It is additive and does not cut over existing OpenCode configuration generation.

@mogul
mogul requested a review from a team as a code owner October 21, 2026 07:25
@mogul mogul linked an issue Oct 21, 2026 that may be closed by this pull request
@mogul mogul changed the title feat/517 provider input contract feat(isolation): define provider-neutral input contract Oct 21, 2026
@mogul

mogul commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 First Mate review note: the #516 adversarial review found one contract gap that belongs in this lower layer before merge. #517 requires provider facts to identify the provider API adapter/type, but acq-provider-facts/v1 currently contains only host, baseUrl, modelsUrl, and keyEnv. Without a bounded adapter identifier, a provider-neutral OpenCode renderer cannot choose an implementation without provider-name branching. Please add a strict, non-executable adapter/type field with fictitious-provider coverage and validator tests. This is an acceptance-criteria correction within #517, not follow-up work.

The same review confirmed that projected-input absence must fail as “not ready” rather than be interpreted as an authoritative empty provider set; Quickstart projection remains tracked by GSA-TTS/agentic-coding-quickstart#600.

@basiliskus basiliskus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: request changes — 9716b7a800faf0730ad11323165ce47955c574dc

  1. major — scripts/validate_provider_input_contract.py:132: enforce the manifest credential declaration. credentialEnvNames is required but ignored. A bundle declaring only UNRELATED_CREDENTIAL passes while facts.keyEnv remains ACME_AI_API_KEY, so the validated contract can give consumers conflicting credential ownership. Cross-check facts.keyEnv against the bundle declaration (and add a regression test).

  2. major — scripts/validate_provider_input_contract.py:121: require a runnable normalizer entrypoint. Validation accepts any regular file. The shipped USAi normalizer is mode 0644, and direct invocation as ADR 0004 specifies exits 126 with “Permission denied”; both fictitious fixtures even point normalizerPath at non-executable JSON snapshots. Validate the executable contract and use executable fixture normalizers so tests exercise it.

Assisted-by: OpenCode [usai/gpt-5.6-sol-latest-guardrails-defaultv2] skill:change-review

@mogul
mogul force-pushed the feat/517-provider-input-contract branch from 9716b7a to ca34988 Compare October 21, 2026 16:51
mogul added 5 commits October 21, 2026 17:31
Define host-time provider facts, neutral catalogs, and package-to-projection manifests with runtime validation and CI coverage.\n\nCo-authored-by: OpenCode Agent <[email protected]>
Bind provider credentials to host-owned metadata and reject alternate IP-literal forms.\n\nCo-authored-by: OpenCode Agent <[email protected]>
Refresh the pinned transitive markdown-it release so Markdown Lint's npm audit passes.\n\nCo-authored-by: OpenCode Agent <[email protected]>
Add the bounded API protocol needed by provider-neutral harness renderers without speculating about unsupported hosting platforms.

Co-authored-by: OpenCode Agent <[email protected]>
Require declared credentials and directly runnable normalizers, with deterministic source-to-output fixture transforms.

Co-authored-by: OpenCode Agent <[email protected]>
@mogul
mogul force-pushed the feat/517-provider-input-contract branch from ca34988 to 91c3973 Compare October 21, 2026 17:31
@mogul

mogul commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Addressed both requested changes at 91c3973:

  • facts.keyEnv must now appear in the bundle's credentialEnvNames, with positive, missing-membership, and multi-credential regressions.
  • normalizerPath must be a non-symlink regular file with execute mode and effective execute access. The shipped USAi normalizer is executable and directly invoked in tests. Fixture bundles now ship executable deterministic --source/--out normalizers with vendor-shaped source inputs and byte-exact expected snapshots.
  • Added symlink-component rejection and strict USAi normalizer CLI option handling.

Verification after rebasing onto current main (03421e0): 149 provider-contract tests, strict kit validation, full kit/provider tests, direct normalizer execution, Ruff, and diff checks all pass. Fresh CI is running. Please re-review when checks complete.

@mogul
mogul requested a review from basiliskus October 21, 2026 17:32

@basiliskus basiliskus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: request changes — 91c3973142ccee164519f36ad2ee49b3ed08dd9b

The two findings from my prior review are resolved at this head: the validator now cross-checks facts.keyEnv against credentialEnvNames, and it requires directly executable normalizers with runnable fixture coverage.

  1. major — scripts/validate_provider_input_contract.py:23: reject non-standard JSON constants. Python’s json.loads accepts NaN and Infinity, and the schema accepts NaN as a non-negative cost. I changed a fixture snapshot cost to NaN; validate_bundle accepted it, while strict JSON parsing rejected it. Such a snapshot passes the host-time gate but is unusable by strict downstream JSON consumers, defeating the fallback. Reject non-finite constants in load_json and add a regression test.

Assisted-by: OpenCode [usai/gpt-5.6-sol-latest-guardrails-defaultv2] skill:change-review

Fail host-time validation for NaN and Infinity values that strict downstream JSON consumers cannot parse.

Co-authored-by: OpenCode Agent <[email protected]>
@mogul

mogul commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Addressed the strict-JSON finding at c9d4cc7. load_json now rejects NaN, Infinity, and -Infinity at the parser boundary, covering schemas, bundle manifests, facts, snapshots, and generated normalizer output uniformly. Added real copied-bundle snapshot regressions for all three constants.

Verification: 152 provider-contract tests, strict kit validation, full kit/provider tests, Ruff, and diff checks pass. Fresh CI is running; please re-review when complete.

@mogul
mogul requested a review from basiliskus October 21, 2026 17:46

@basiliskus basiliskus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: approve — c9d4cc74acbb4d37e5ffe9170e83329a8c5be9d6

The previously reported non-standard JSON issue is resolved. The loader now rejects NaN, Infinity, and -Infinity; the regression test covers all three constants, and the 152 provider-contract tests pass at this head.

Nit: the PR verification section says 143 provider-contract tests, while the current suite has 152.

Assisted-by: OpenCode [usai/gpt-5.6-sol-latest-guardrails-defaultv2] skill:change-review

@basiliskus
basiliskus self-requested a review October 21, 2026 17:51
@basiliskus
basiliskus merged commit 28a8ebd into main Oct 21, 2026
8 checks passed
@basiliskus
basiliskus deleted the feat/517-provider-input-contract branch October 21, 2026 17:52
mogul pushed a commit that referenced this pull request Oct 21, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.15.0](v1.14.0...v1.15.0)
(2026-10-21)


### Features

* **acq-kits:** add OpenDesign browser kit
([#438](#438))
([83e202f](83e202f))
* **isolation:** define provider-neutral input contract
([#518](#518))
([28a8ebd](28a8ebd))
* **usai-catalog:** refresh models and withhold undeployed gateway
entries
([#519](#519))
([03421e0](03421e0))


### Bug Fixes

* **usai-catalog:** refuse a near-miss instead of enriching from the
wrong model
([#484](#484))
([c3a6dac](c3a6dac))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
mogul pushed a commit to GSA-TTS/agentic-coding-quickstart that referenced this pull request Oct 21, 2026
## Summary

Moves `PATTERNS_KIT_REF` from v1.12.0 (`56d1f5f`) to
agentic-coding-patterns v1.15.0 (`f3c6acb`), so the built-in kit bundle
picks up:

- **opencode kit → OpenCode 2.0.30**
(GSA-TTS/agentic-coding-patterns#499). OpenCode 2.0.0–2.0.29 ignore
config `instructions` (anomalyco/opencode#51341, fixed in 2.0.30), so a
sandbox on an image without a baked OpenCode (`devenv-shell`, or the
`devenv-shell` default proposed in #584) currently runs the bundled
2.0.22 and silently drops `instructions`-based conventions.
- **paseo kit → Paseo 0.12.0** (GSA-TTS/agentic-coding-patterns#504):
fixes for OpenCode v2 under Paseo (daemon OOM on long v2 streams,
multi-select answers, HTTP 500s instead of tool errors) and the
host-sleep daemon-status fix.
- **Kit verify scripts gain a "could not check" verdict**
(GSA-TTS/agentic-coding-patterns#460); it only affects kit verify
output.

Also v1.13.0: usai-provider's host-side catalog normalizer (#436), the
paseo identity-gate script (#453), and the team-kit and personal-kit
templates under `acq-kits/examples/`. None changes what acq applies by
default beyond the two kits above.

Also v1.15.0: refreshed usai-provider model catalog
(GSA-TTS/agentic-coding-patterns#519,
GSA-TTS/agentic-coding-patterns#484), the OpenDesign opt-in kit
(GSA-TTS/agentic-coding-patterns#438), and the provider-neutral input
contract (GSA-TTS/agentic-coding-patterns#518). acq's provider-facts
loader reads `provider-facts/usai.env`, which v1.15.0 does not change.

The doc examples and Bats assertions that spell the pin move with it.
KNOWN_FAILURE_MODES §9 now names 2.0.30 as the version the kit installs
and notes its 15-minute default `chunkTimeout` (the timeout message and
retry limits are unchanged from 2.0.22).

## Verification

On the v1.15.0 pin:

- Focused Bats: `135-configure`, `95-kit-ref-persistence`,
`36-agent-catalog`, `50-kit-list-completeness` (63/63)
- markdownlint on the changed docs

On the earlier v1.14.0 pin (not re-run for v1.15.0):

- `npm run lint:md`
- `RUN_ACQ=1 scripts/verify-backends --only msb` on macOS, msb 0.7.8: 16
passed, 1 skipped (playbook fetch, no `gh` login), run with `TMPDIR` set
to its resolved `/private/var/...` path to get past an unrelated create
failure that also hits `main` (#594)
- Downstream, with this pin on msb 0.7.8 and
`ACQ_IMAGE=devenv-shell:1.0.0`: a team kit's end-to-end verify passed
71/71 (OpenCode 2.0.30 runs and loads `instructions`); with the paseo
kit added, Paseo 0.12.0 drove an OpenCode 2.0.30 agent that received the
team `instructions`, and its sessions survived a backup, `acq rm`,
recreate and restore

## Rollback

Revert this PR to restore the v1.12.0 bundle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants