Skip to content

ADR 0004 phase 4: migrate lifecycle validation, overlays, and harness eligibility #10294

Open

Description

@lpcox

Objective and readiness

Implement ADR 0004, Gate 4: generated lifecycle consumers, run-scoped overlays, and actual-harness eligibility. Parent: #10290.

2026-10-21 user-directed scope correction: retain model-management functionality only. Harness eligibility means detecting/comparing the selected harness version through existing execution backends and applying model constraints. It does not mean proving an adversarial process cannot modify its runtime. Remove the unmerged Yama/kernel builder, native hardening addon, new cgroup/pidfd/controller authentication, protected spawn/launch-attestation, private execution-plan transport, and complete Node/SDK closure work and their dedicated tests/CI/docs. Preserve existing security controls. Unknown/missing actual-runtime version evidence fails an applicable constraint explicitly; do not invent a new isolation architecture to eliminate that unknown.

Phase 3 is no longer a blocker. The foundation PRs are merged:

The compatibility-reader migration is now active. The next work is shared eligibility, actual-environment harness checks, and the cross-repository overlay contract/wiring. Workflow/config wiring and phase completion remain blocked on agreement with github/gh-aw. Companion tracking now exists at github/gh-aw#70728; it records the proposed contract and remaining decisions, not completed agreement or implementation. Do not treat the local Phase 2 issue's closure or the companion issue's creation as cross-repository agreement, or invent final frontmatter/config field names independently. Companion compiler support and compiler-to-AWF round-trip coverage are required for completion, not optional follow-ups.

This phase may run alongside Phases 5/8 against the merged contracts. Read the current ADR's Gate 1 handoff, Phase 2 compatibility matrix and cross-repository blocker, and Phase 3 source/projection ownership before implementation. Keep PRs bounded; a partial lifecycle PR must not close the entire phase.

Merged partial progress and remaining work

#10360 replaced host availability/retirement tables and proxy retirement tables with generated projections, preserved host/proxy matching boundaries and legacy suggestion ties, restricted general CLI support to exact Copilot records with supported deployment-unscoped CLI availability, and added scope, staged-exclusion, prototype-key, and isolated compiled/bundled/proxy-loading regressions.

The merged ADR's Partial Phase 4 handoff: compatibility readers only is the current implementation baseline. auto remains a selector whose eventual candidates are not yet validated by a shared eligibility resolver. No staged #10029/#10030 availability, pricing, reasoning, context, or translation corrections were activated.

Remaining deliverables are a reusable scoped eligibility decision/re-evaluation contract, actual-execution-environment harness detection and enforcement across explicit/selector/routing/fallback paths, and an agreed versioned github/gh-aw payload with run-local overlay wiring and round-trip evidence. This issue must remain open until those requirements are complete; follow-on partial PRs should reference it without automatic closing keywords.

Reuse the merged foundation

  • shared/model-information/schema.v1.json: canonical model, scoped overlay, availability, provenance, and harness contracts. Harness constraints already carry scope, name, scheme, minimum, optional excludedRanges, reason, and provenance.
  • shared/model-information/identity.js and .d.ts: identity, normalizeId, matchModel, and matchFamilyRule. Provider identity/raw IDs survive normalization; prefix/date/separator handling is explicit policy, not a universal rewrite. Identity matching alone does not establish availability, policy permission, or harness eligibility.
  • shared/model-information/contracts.js and .d.ts: validate and validateRecords; reuse schema and complete-set checks rather than creating parallel validators or tables.
  • shared/model-information/sources/ and catalog.generated.json: maintained facts and the baseline static catalogue. Imported entries and schema-required lifecycle placeholders are not evidence of CLI availability or verified harness support.
  • src/model-information.compat.generated.json: active legacy-compatible host supported, retired, and suggestionOrder projection, consumed by src/copilot-model.ts.
  • containers/api-proxy/model-information.retired.generated.json: active legacy-compatible proxy retirement projection, consumed by the guard and copied by the proxy Dockerfile.
  • shared/model-information/sources/lifecycle-compatibility.json: legacy suggestion ordering only, validated as a permutation of canonical supported CLI IDs plus auto; it cannot author availability.
  • shared/model-information/target.generated.json and baseline-to-target.generated.json: staged Add curated AI-credit prices for current Copilot models #10029/Complete routing effort metadata for current OpenAI and Anthropic models #10030 corrections and complete before/after review data, not automatically active inputs.

Use npm run models:generate after canonical source/compiler changes and npm run models:check to verify generated bytes. Do not hand-edit projections or add an independent allowlist/retirement authoring path. The endpoint updater is already manual/read-only; do not restore generated-output authoring.

Deliverables

1. Migrate lifecycle consumers with explicit compatibility boundaries

The reader/data-ownership portion landed in #10360; do not reimplement it. Build on those readers to wire provider/channel/deployment-scoped eligibility without treating Copilot CLI support as native-API or Copilot-API support. Use scoped aliases and exact records; family rules, imported tariffs, or endpoint mappings cannot establish deployability.

The current host validates trimmed/case-folded, separator-equivalent exact IDs and rejects undeclared prefixes, dates, queries, and specialized variants. The proxy retirement guard currently lowercases but does not normalize separators. Preserve these characterized boundaries until an explicit lifecycle correction is reviewed and tested; sharing identity/data must not silently broaden accepted IDs. Resolve host/proxy inconsistencies deliberately, distinguishing an intentional normalization correction from accidental behavior drift.

Preserve host result/error contracts, replacement suggestions, and suggestion behavior. The generated host list is sorted differently from the legacy insertion order: investigate equal-distance suggestion tie behavior rather than assuming set equality proves parity. auto remains a selector, not a deployable model; validate the eligible candidates it can select.

Use one shared eligibility decision contract for explicit requests, selectors, routing, and fallback candidates. Keep structured rejection reasons and sanitized provenance available for subsequent phases. Remove superseded local lifecycle table ownership/comments as each consumer migrates, but retain compatibility adapters and valuable characterization fixtures; broad legacy cleanup remains Phase 9.

2. Activate only reviewed lifecycle corrections

Phase 3 stages six #10029 CLI additions: claude-opus-5.5, claude-sonnet-5.5, gemini-3.8-flash, grok-4.5, grok-4.6, and grok-4.7. Review their exact source evidence and eligibility scope before activation; current target provenance cites issue evidence with estimated confidence.

Separate a compatibility-only reader migration from intentional activation of these additions. If activated here, update canonical inputs/compiler projections and named expectations together, documenting the exact behavior change. Preserve price, effort, context, and protocol behavior: loading the entire target export or target mapping merely to enable availability would prematurely activate Phases 5/6.

Do not close #10029 based on availability alone; Phase 5 still owns its pricing requirements. #10030's reasoning/context activation belongs to Phase 6. Do not invent harness minimums or other missing facts to complete records.

3. Agree and wire the workflow/config contract

Before wiring workflow-defined entries, agree the exact frontmatter and AWF config keys, payload version/supported range, scope, and error behavior with github/gh-aw; link the companion issue/PR and agreement in the handoff.

The companion is github/gh-aw#70728. The implementation direction is model-information frontmatter -> AWF modelInformation; reconcile the model-only payload after removing execution-plan/attestation metadata. Retain the existing 21,000-byte final expression-bearing rendered-script limit, counting escaping and command overhead, with an actionable oversize error; larger-snapshot staging is excluded. Go/WASM and JS model validation must agree. Prove the supporting version's model-config capability, not a new immutable runtime closure. Where routing/startup ordering prevents an ordinary actual-environment probe, resolve the ordering within existing backend behavior or report an unsupported/unknown check explicitly; host versions must not masquerade as guest versions.

The agreed payload must cover existing canonical overlay records, sanitized original-source workflow provenance, inline snapshot/source enabled/offline settings, and model-relevant harness selection semantics. Compiler-owned metadata must not include raw private argv, prompts, or credentials; no new protected execution-plan channel is required. Initial active live-URL mode rejects actionably. Phase 4 owns model config transport/validation; Phase 5 owns fetching, cache, freshness, and pricing resolution. Source replacement must not imply fallback to an unconfigured default; offline/local-only settings must retain their no-feed-network contract. Imported and secondary-engine declarations must retain scope and reach their actual consumer; silently dropping them is not acceptable.

Both compiler and AWF validate the same versioned payload. Unsupported versions, including use with older pinned AWF, fail actionably rather than silently dropping fields. Cross-contribution workflow/operator assignments to the same semantic field reject when provider/channel match and deployment scopes intersect, even for identical values; there is no implicit specificity/import-order override. Operator lifecycle status, including active, counts as an assignment, so authors must consolidate overlapping model contributions. Preserve legitimate scoped facts within a consolidated record. Provider/channel are exact boundaries; deployment-specific overlays cannot introduce broader unscoped facts.

Keep overlays run-local; never mutate bundled records or shared caches. Retain existing open, unversioned apiProxy.providers and configured pricing-catalogue v1 behavior. Strict unknown-field rejection applies to new explicitly versioned formats, not retroactively to legacy inputs. Existing workflows with no new payload remain unchanged. Config schema edits must use the repository's canonical schema-generation mechanism.

4. Enforce actual-execution-environment harness eligibility

Detect the selected binary/version in the environment that will execute the command, including the chosen runtime/chroot/guest where applicable, not merely the host's installed CLI. Use the existing runtime/probe architecture where suitable and carry the result to all model-selection paths without assuming backend environments are identical.

Define and test the supported semver and numeric-components comparison/constraint semantics, including prerelease ordering and excluded ranges. Unknown, unavailable, or unparsable detected versions cannot satisfy an applicable requirement. Distinguish absent/unverified model constraints from a known satisfied minimum; do not fabricate floors or claim verified compatibility from missing metadata.

Explicit incompatible requests fail with required/detected versions, scope, reason, and upgrade guidance. Automatic paths filter incompatible candidates and fail if none remain. Never silently substitute an explicitly requested model or upgrade the harness. Overlays cannot bypass network restrictions, model policy, picker exclusions, or harness checks.

Expose eligibility re-evaluation integration points for Phase 5 refreshes so newly accepted constraints apply before subsequent dispatch. Phase 6 must be able to reuse the same decision/reasons rather than reconstruct eligibility independently.

Entry points and packaging

Discovery entry points, not mandatory module boundaries:

  • src/copilot-model.ts, src/cli-workflow.ts, AWF config readers/schema, and selected runtime backends/probes.
  • containers/api-proxy/{guards/retired-model-guard.js,guards/model-policy-guard.js,model-resolver.js,model-fallback-chain.js,scoped-auto-model.js} and routing candidate construction.
  • The shared contracts, canonical sources, generated lifecycle assets, and compiler listed above.

Shared repository modules are not automatically present inside the proxy's /app build context. Generated JSON interchange is already established; ensure any runtime shared logic/data works in actual host build/package and proxy/container contexts, not only via repository-relative imports. Add only focused, compatible contract/compiler refinements required by this integration, with corresponding fixtures and documentation.

Acceptance criteria

  • Host validation/suggestions and proxy retirement/replacements consume canonical-generated/shared data, not independently maintained lifecycle lists; source regeneration and stale-output checks cover every changed projection. Landed in Migrate lifecycle readers to generated data (ADR 0004 phase 4, partial) #10360.
  • Provider/channel/deployment scope, exact aliases, retirement, replacements, selectors, and exceptions are consistent with the declared eligibility policy. Characterized identity/error/suggestion behavior is preserved except explicitly reviewed corrections.
  • Any Add curated AI-credit prices for current Copilot models #10029 lifecycle additions have verified evidence, explicit activation boundaries, and named regression expectations; no staged pricing/reasoning/context/translation changes are activated incidentally.
  • Linked github/gh-aw agreement and companion implementation define the same opt-in versioned payload. End-to-end workflow-frontmatter -> compiler -> AWF config tests cover custom entries, scope, strict validation, schema-version mismatch, and older-pinned-AWF failure; existing workflows remain unchanged.
  • Intersecting cross-contribution assignments fail even when identical, including operator lifecycle status; consolidated records retain their valid scoped facts. Overlays remain run-local and do not modify shared cache or bundled records. Legacy provider overlays and configured-catalogue v1 inputs retain their existing acceptance/authority.
  • Overrides cannot bypass network, model-policy, picker, or harness checks; sanitized workflow provenance and structured eligibility reasons survive resolution without leaking secrets or arbitrary prompt text.
  • Harness boundary/prerelease/excluded-range/missing/unparsable-version and host-versus-execution-environment tests cover explicit requests, selectors, routing, and fallback; errors include required/detected versions and upgrade guidance.
  • Explicit incompatible requests are never silently substituted; automatic selection fails actionably when all candidates are ineligible.
  • Phase 5 receives a documented/tested eligibility re-evaluation integration point; Phase 6 can reuse the same eligibility decision contract.
  • Built/package/proxy-context tests prove generated assets and any shared runtime logic resolve outside the repository source tree; affected characterization/contract tests remain intact except named reviewed corrections.

Validation and completion handoff

Run targeted lifecycle, shared-contract, config, runtime/probe, policy, selector, routing, and fallback tests for the changed paths. At minimum retain the merged foundation checks:

# Repository root
npm run models:check
npm run build
npm run type-check
npx jest --runInBand src/model-information-contract.test.ts src/copilot-model.test.ts src/copilot-model-catalog-sync.test.ts scripts/model-information/compile.test.ts

# Run separately from containers/api-proxy
npm test -- --runInBand model-information-contract.test.js model-metadata-characterization.test.js guards/model-policy-guard.test.js model-fallback-chain.test.js scoped-auto-model.test.js

Also run affected retirement, request/routing integration, config transport/schema, actual-runtime harness, and packaging tests. Root Jest does not discover proxy tests. Use deterministic fixtures/probes; no production inference, live workflow dispatch, or external provider calls are required to validate this phase.

Deliver a handoff linking merged prerequisites, lifecycle activation changes, canonical source/output ownership, cross-repository agreement and round-trip evidence, actual-environment detection/comparison semantics, packaging evidence, and Phase 5/6 integration APIs. Leave this issue open if the companion contract/wiring or any other acceptance criterion remains incomplete.

Non-goals / handoff

No kernel build/policy change, native process-hardening addon, new process/controller authentication, protected agent spawn/attestation, private execution-plan ABI, immutable Node/SDK/agent closure distribution, or new isolation architecture. No new pricing resolver/source, live central refresh/cache, runtime-discount accounting, reasoning/context activation, directed translation migration, public model CLI/export rollout, feed publication, broad legacy removal, or unrelated runtime refactor. Phase 5 owns pricing/refresh; Phase 6 owns reasoning/compatibility; Phase 7 exposes resolved data additively through the existing /reflect. Do not add /reflect/v2, endpoint-version negotiation, or a v2-to-v1 fallback.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions