# I0-B Provider / Account / VCS Progress

- Lane: Development Agent 3 — Lane B Provider / Account / VCS Boundary
- Branch: `impl/i0-b-providers`
- Worktree: `/home/user/Projects/awp-i0-b-providers`
- Current base: `origin/main` at `6318999` (`feat(core): reconcile C1 provider-neutral contracts (#16)`)
- C1 stable Lane A signal: `fa6c7d95fbef9194fb9b3b90767b347f87dc11b6` (squash-landed to `main` as `08276e7`)
- C0 implementation baseline: `114b57a4ad37f9178b9c6309497c39663d4580e9`
- State: final Lane B C1.x convergence complete on PR #14; newly landed provider-neutral contracts are consumed, trusted Merge reconciliation is implemented, the authorized root lockfile integration artifact is regenerated, frozen install and full repository gates pass; remaining blockers are other-lane or live-evidence requirements only

## Owned paths

- `packages/providers/account-subrouter/**`
- `packages/providers/vcs-github/**`
- `packages/providers/factory-fabro/**`
- `packages/providers/agent-acp/**`
- `tests/providers/account-subrouter/**`
- `tests/providers/vcs-github/**`
- `tests/providers/factory-fabro/**`
- `tests/providers/agent-acp/**`
- `docs/progress/i0-b-providers.md`

Lane B does not modify Lane A domain/application/persistence/contracts files, approved mockups, or other lanes.

## C1 integration

After PR #16 landed, this branch fetched `origin` and rebased its own history onto `origin/main@6318999`. The C1.x reconciliation supplies the provider-neutral seams previously requested by Lane B: canonical candidate manifests, trusted Merge request/result/reconciliation contracts, typed `ProviderFailure`, durable credential-authority fencing, immutable Attempt retry/fallback selection provenance, and one-time Attempt provider-reference binding.

C1 now provides canonical readonly Attempt provenance fields and persistence for:

```text
Attempt.providerId
Attempt.accountId
Attempt.model
```

Lane B consumes those fields rather than defining a provider-local Attempt shape:

- `AcpAgentProvider` resolves the canonical `Attempt` through the landed `AttemptRepository` port before native session creation;
- execution fails closed if the canonical Attempt is missing, does not match `agentRunId`/`workspaceId`, lacks provider/account/model provenance, or is assigned to a different provider;
- only canonical non-secret `providerId` / `accountId` / `model` selections are projected into the ACP native session request;
- `ProviderOperationContext.credentialReferenceId` and reusable publication/provider credentials are deliberately not projected into AgentRun/session authority;
- ACP replay verifies provider/account/model in addition to Attempt/AgentRun/Task/Workspace identity;
- Subrouter exposes `createAuthorizedForceAccountHeadersForAttempt(...)`, projecting the landed canonical `Attempt.accountId` only after application/policy supplies the authorized account-key set;
- no self-reported user metadata participates in account authorization.

The GitHub publisher was also tightened during C1 integration: an already-completed matching idempotent publication is reconciled before consulting mutable repository-head state. This preserves correct replay behavior if `main` advances after the original publication, while expected-head validation remains mandatory before every new mutation.

## Source / consumer proof

### Subrouter

Current source reviewed on 2026-08-20: `manaflow-ai/subrouter@1c5719c702e16d7f458a2b5e20be9084fa88d86b`.

Verified current consumer surface:

- `GET /_subrouter/accounts` is admin-protected and returns safe account records with `id`, `provider`, `auth_mode`, optional `label`/`email`, and `source`;
- auth observations are exposed separately at `/_subrouter/account-status`;
- usage/headroom observations are exposed separately at `/_subrouter/usage-status`;
- `X-Subrouter-Account-ID` is the explicit account-selection header;
- `SUBROUTER_CODEX_ACCOUNT_ID` is the Codex wrapper input for that explicit account pin;
- `X-Subrouter-User-Email` / `SUBROUTER_CODEX_USER_EMAIL` are documented as observability metadata, not authentication or account authorization;
- Subrouter strips its account/user routing metadata before forwarding upstream;
- admin and account-import token boundaries are distinct.

Reference-consumer / reuse proof completed on 2026-08-21:

- Overdeck pins upstream Subrouter `v0.1.81@29c7ebb306ac54739206f4752449e437047dd150` in `modules/subrouter/upstream.json` and layers `modules/subrouter/patches/0001-overdeck-authority-safety.patch`; this is evidence of a deployed consumer boundary, **not** an AWP implementation source. AWP does not copy the Overdeck authority patch, route/grant model, filesystem layout, service-user mechanics or local-admin protocol.
- Current `platform-modules/mod` authoritative remote `main` is `801cad34010b87ed58e6450bed31c59d12b8f21a` (`chore: modernize Node and Cloudflare toolchain (#147)`). Its landed AWP Step-0 capability work provides realtime/config/logger seams and explicitly defers generic idempotency; it exposes no provider-account or mutable provider-token authority capability suitable for this Lane B seam.
- Reuse disposition: use Subrouter as the provider-native account/routing authority behind AWP `AccountProvider`/Connection/Attempt contracts; keep AWP identity/policy/provenance canonical; do not introduce a duplicate Platform/AWP token refresher.

The exact upstream, reference-consumer and Platform reuse-gate revisions are embedded in `SUBROUTER_SOURCE_PROOF` and asserted by the provider test suite.

Adapter pin: `awp-i0-subrouter-2026-08-20`.

### GitHub

GitHub remains the initial Forge/VCS provider. Lane B implements repository inspection plus a trusted publication boundary with deterministic AWP-owned refs, expected-base/head comparison, idempotency lookup, post-mutation read-back fidelity checks, reconciliation tokens, and explicit denial for `agent` principals at the trusted publisher boundary. No reusable publication credential is projected into AgentRun inputs.

### Fabro

Current source reviewed on 2026-08-20: `fabro-sh/fabro@03c3412e513b845c5acc992b30dede3a34dc6858`. The source-fit contract covers workflow/run execution, stage/checkpoint observations, cancellation, reconciliation and durable run identity mapping. Adapter pin: `awp-i0-fabro-2026-08-20`. Live API/runtime proof remains unavailable in this lane environment, so the adapter uses a narrow native-client seam with realistic failure/replay fakes.

### ACP

Current official source reviewed on 2026-08-20: `agentclientprotocol/typescript-sdk@b7d6e81feae289e171ebaf78b4b3db8386c1fff0`. Stable ACP v1 is the normal target and experimental v2 remains opt-in. Current npm evidence is `@agentclientprotocol/sdk@1.3.0`; tag `v1.3.0` resolves to `fa32570936b42bf4f3aef175c6e926860914b638`. Adapter pin: `awp-i0-acp-v1-2026-08-20`.

## Implemented

### Subrouter AccountProvider

- current safe account response -> canonical `AccountDescriptor` mapping;
- provider references for account observations;
- provider/auth-mode capability normalization without credential material;
- explicit force-account helper requiring a caller-supplied authorized-account set;
- canonical C1 Attempt account provenance -> authorized force-account projection;
- unauthorized or missing account provenance fails closed;
- self-reported user metadata is structurally absent from authorization input;
- provider failures normalized into the shared provider error taxonomy.

### GitHub Forge / trusted publication

- `ForgeProvider.inspectRepository` mapping;
- repository native ID/head evidence mapping;
- trusted publication separated from `AgentProvider`;
- direct `agent` principal invocation rejected at the trusted publisher boundary;
- current repository head must equal ChangeSet `baseRevision` before a new mutation;
- deterministic `refs/heads/awp/<ChangeSetId>` target ref;
- idempotency-key read-before-mutate behavior;
- completed matching replay reconciles even after unrelated repository-head advancement;
- idempotency collision/fidelity mismatch fails `conflict-stale`;
- post-mutation read-back verifies repository/base/candidate/ref fidelity and unchanged target revision;
- reconcile/read-back maps provider reference and reconciliation token;
- no publication credential is accepted as AgentRun/session input.

### Fabro FactoryProvider

- FactoryRun + PlanRevision -> provider run mapping;
- idempotent start with collision detection;
- current stage/checkpoint/failure observation mapping;
- cancellation with terminal replay safety;
- reconcile/read-back by provider reference;
- provider outage/rate/auth/permission/conflict error normalization.

### ACP AgentProvider

- capability discovery -> provider descriptor;
- canonical C1 AttemptRepository lookup before execution;
- canonical provider/account/model provenance -> ACP session start mapping;
- AgentRun/Attempt/Task/Workspace + provider/account/model replay fidelity checks;
- missing/mismatched provenance fails closed before native mutation;
- credential reference and reusable token/publication authority are not projected into ACP session start input;
- native-session cancellation helper with replay-safe terminal behavior;
- reconcile/read-back by provider reference;
- normalized protocol/provider errors.

## FIRE convergence accounting

The FIRE-learning corpus landed on `origin/main@89d5300` and was consumed after the C1 integration. Lane B treats all 8 urgent findings and all 13 proposed I1-blocking tests as mandatory convergence input. No Overdeck implementation was copied; the evidence was translated into AWP provider invariants using the existing provider/application/domain seams.

### Eight urgent cross-lane findings

| Finding | Lane B disposition | Evidence / exact test or owner |
| --- | --- | --- |
| U1 — excluded recoverable Git/WIP | not owned by Lane B | Lane C owns collection/workspace transport and `RT-001`; Lane A owns terminal collection semantics. |
| U2 — destructive cleanup fencing | not owned by Lane B | Lane C + Lane A own `RT-002`, `RT-003`, `RT-030`. |
| U3 — ambiguous publication success | **implemented** | `RT-006-GITHUB` in `tests/providers/vcs-github/vcs-github.test.ts`: fake applies publication then drops response; retry reconciles exact existing publication and `publishCalls` remains 1. GitHub replay lookup now precedes mutable-head validation for an already-completed matching operation. `RT-007` is now implemented by `GitHubTrustedMerger`: an ambiguous merge response is reconciled using the exact immutable request before any retry, and replay does not perform a second merge mutation. |
| U4 — mutable credential authority single-writer | **provider invariant implemented; canonical concurrency authority now supplied by C1.x** | `RT-008-B` tests in `tests/providers/account-subrouter/account-subrouter.test.ts` declare Subrouter as sole mutable owner and reject AWP refresh/rotate/revocation mutation. C1.x now owns durable authority generation/claim/fence/transfer state; Lane B continues to treat Subrouter as the sole provider-native mutable account owner and does not invent a second token writer. |
| U5 — process lock/heartbeat is not durable ownership | not owned by Lane B | Lane A + Lane C own `RT-010`, `RT-011`, `RT-012`. |
| U6 — UI cannot outrun authoritative state | Lane B source evidence implemented; lifecycle/UI projection not owned | `RT-025-B` verifies GitHub publication observations contain publication state only and do not invent shipped/deployed fields. Lane A + Lane D own authoritative lifecycle/read-model/UI completion. |
| U7 — exact execution eligibility | not owned by Lane B | Lane C owns `RT-013`, `RT-014`, `RT-015`; Lane A owns typed state semantics. |
| U8 — semantic completion not process/provider completion | **Lane B portion implemented** | `RT-034-B` in ACP tests proves provider terminal `completed` remains provider observation only and does not emit Task completion/semantic outcome. Lane A owns already-satisfied-vs-unsatisfied Task semantics; Lane C owns execution evidence. |

### Thirteen I1 blocking FIRE tests

| Blocking test | Required disposition | Lane B accounting |
| --- | --- | --- |
| RT-001 | not owned by this lane | Lane C — Workspace/result collector. |
| RT-002 | not owned by this lane | Lane C + Lane A — cleanup generation/fencing. |
| RT-006 | **implemented + test ID** | `RT-006-GITHUB`; ambiguous provider success is reconciled by idempotency/candidate/provider identity before any second mutation. |
| RT-008 | **canonical C1.x authority landed + Lane B guard implemented** | `RT-008-B` keeps the provider side single-writer; C1.x now supplies durable authority generation/claim/fence/transfer semantics for cross-lane concurrency proof. |
| RT-010 | not owned by this lane | Lane A + Lane C — durable workflow ownership. |
| RT-013 | not owned by this lane | Lane C — execution-profile attestation/placement. |
| RT-016 | **implemented + test ID for Lane B portion** | `RT-016-B`: ACP native start input receives canonical non-secret provider/account/model only; credentialReference/token/publication authority are absent. Lane C owns pod/env/mount/runtime-filesystem inspection in the gVisor/Kubernetes execution environment. |
| RT-020 | not owned by this lane | Lane A + Lane C — durable history through restart. |
| RT-023 | not owned by this lane | Lane A + Lane D — realtime sequence gap/re-query. |
| RT-025 | **implemented + test ID for Lane B portion** | `RT-025-B`: publication evidence remains semantically `published`, never `shipped`/`deployed`. Lane A + Lane D own downstream lifecycle and UI. |
| RT-026 | not owned by this lane | Lane A + Lane D own persistence→application→transport→UI failure projection. Lane B preserves provider details without inventing stronger semantics. |
| RT-034 | **implemented + test ID for Lane B portion** | `RT-034-B`: provider completion is semantic-neutral. Lane A owns verified already-satisfied/no-op versus unmet intent; Lane C owns execution evidence. |
| RT-040 | **implemented + test ID** | `RT-040` in the GitHub provider suite passes the complete canonical `CandidateManifest` (tree digest, patch digest, full paths and add/modify/delete metadata) through publication and trusted Merge and verifies fidelity. |

No I1-blocking FIRE test is unaccounted for in Lane B. Tests spanning multiple lanes are explicitly split at the provider boundary rather than claimed end-to-end.

### Additional FIRE requirements applicable to Lane B

| Requirement | Disposition | Exact evidence / remaining requirement |
| --- | --- | --- |
| RT-005 / INV-FIRE-003 Git isolation | **implemented + test ID `RT-005`** | GitHub native mutation receives only exact repository key, deterministic target ref, expected base revision, candidate digest and idempotency key; no workspace/local-ref/working-tree input exists. |
| INV-FIRE-004 provider mutation idempotency beyond Git | **implemented** | `B-FIRE-MUT-001` (Fabro) and `B-FIRE-MUT-002` (ACP) inject post-mutation response loss and prove retry finds existing run/session without a second start mutation. |
| INV-FIRE-011 mutable branch names are not provenance | already guaranteed | `RT-005` + `INV-FIRE-003` GitHub tests: mutation is bound to exact base revision/candidate digest, not a workspace branch name. |
| INV-FIRE-015 same key/conflicting fingerprint | **implemented** | GitHub `INV-FIRE-015` test; Fabro/ACP idempotency-collision tests reject different immutable run/Attempt inputs. |
| RT-024 stale provider endpoint | not owned by the current Lane B adapter instance lifecycle | Lane C/provider-runtime integration owns concrete endpoint discovery/client construction. Lane B adapters are injected native clients and hold no endpoint cache; if endpoint discovery moves into these adapters, add bounded rediscovery/reconcile contract tests there. |
| RT-031 provider delivery dedup | requires shared event-ingress contract when provider webhook/event ingestion is introduced | Existing `ProviderReference.nativeId/nativeRevision` preserves native identity, but C1 has no provider-delivery/event-ingress operation to deduplicate. Lane A owns durable event ingress; Lane B will map provider delivery IDs when that seam exists. |
| RT-033 authoritative capability omission | **implemented + test ID `RT-033`** | ACP descriptor derives `agent.start`/`agent.cancel` only from authoritative native `session.new`/`session.cancel`; no hidden capability fallback. Fabro remains a live-provider contract evidence gate because no authoritative runtime capability discovery endpoint is currently exposed by the native seam. |
| RT-036 fallback provenance | **canonical contract landed; provider mapping remains fail-closed** | C1.x now persists immutable Attempt selection kind/reason/previousAttempt provenance. ACP still consumes the canonical Attempt and refuses provider/account/model mismatch; it does not fabricate provider-local retry provenance. |
| INV-FIRE-019 semantic result interpretation | **implemented for provider boundary** | `RT-034-B`; provider/process state never maps directly to Task semantic completion. |

### C1.x reconciliation closure

`origin/main@6318999` resolves all four provider-neutral contract requests previously recorded by Lane B:

1. durable credential authority with generation/claim/handoff/fence/transfer semantics;
2. immutable structured `CandidateManifest`;
3. provider-neutral trusted Merge mutation/result/reconciliation contracts;
4. immutable Attempt retry/fallback selection provenance and canonical provider-reference binding.

Lane B consumes these contracts without modifying or replacing Lane A domain/application/persistence ownership. The newly enabled provider implementation is the GitHub trusted Merge adapter plus canonical candidate-manifest fidelity on publication/Merge.

## Validation evidence

Final C1.x convergence was validated on authorized buildbox `debian1` with Node `v22.23.1` and pnpm `9.7.0`.

- `CI=true pnpm install --frozen-lockfile`: **PASS** from a clean build copy;
- aggregate `pnpm check`: **PASS**;
- repository tests: **19 files / 71 tests PASS**;
- Lane B provider tests inside the aggregate suite: **4 files / 38 tests PASS**;
- typecheck, lint and build: **PASS**;
- architecture tests: **6/6 PASS**;
- dependency-cruiser: **45 modules / 53 dependencies, 0 violations**;
- Prettier: **PASS**;
- trusted Merge ambiguity/replay (`RT-007`) and complete candidate-manifest fidelity (`RT-040`): **PASS**.

### Root lockfile integration

The convergence authorization explicitly permits Lane B to regenerate the shared root `pnpm-lock.yaml`. The final lockfile contains importers for all Lane B provider workspaces, including the new `@awp/domain` dependency of `provider-vcs-github`. The clean frozen install proof above closes the previous `ERR_PNPM_OUTDATED_LOCKFILE` integration blocker.

## Shared contract status after C1.x

The previously blocking provider-neutral gaps for durable credential authority, candidate safety, trusted Merge and retry/fallback provenance are closed by `origin/main@6318999`. Lane B has not introduced any provider-local replacement domain contract. Remaining work is limited to live provider/runtime evidence and cross-lane end-to-end proofs owned outside Lane B.

## Security invariants held

- no reusable Git publication credential enters ACP/AgentRun start input;
- canonical Attempt provider/account/model are non-secret selection provenance only;
- an agent principal cannot call the trusted GitHub publisher;
- self-reported Subrouter user metadata cannot select an account;
- forced account must already be present in the AWP-authorized set supplied to the adapter;
- provider-native identities remain `ProviderReference`s and do not replace AWP IDs;
- replay never silently changes FactoryRun/Attempt/ChangeSet identity/provenance inputs;
- stale repository head blocks new publication or Merge mutations;
- matching completed publication replay does not duplicate mutation;
- mismatched publication or Merge read-back fails closed;
- trusted Merge replay reconciles exact ChangeSet/publication/candidate/base/target identity before any repeated mutation.

## Evidence gates still requiring live environment

- intended deployed Subrouter binary/release/API contract against the authorized AWP account pool;
- live wrong-account, revoked-account and cross-tenant Subrouter denial/attribution matrix;
- GitHub App authenticated publication/PR/update/reconcile E2E against an AWP-owned test repository, including webhook verification and rate-limit/backoff behavior;
- Fabro live start/cancel/restart/checkpoint/reconcile mapping;
- ACP live Codex path, Claude path and one additional compatible agent, including capability negotiation, cancellation, restart/recovery and error mapping;
- execution-plane runtime inspection proving AgentRun/workspace contains no reusable publication credential.

These unavailable live proofs remain explicit evidence gates; they are not replaced with invented success claims.

## Publication state

- Provider implementation/FIRE convergence history was rebased onto C1.x; final convergence commit is recorded on the PR head.
- Exact Platform/Subrouter reuse/consumer proof closure: `4f1345d` (`docs(provider): close Subrouter reuse proof`).
- Remote branch: `origin/impl/i0-b-providers`.
- Provider-ready PR: **#14 — `feat(providers): implement C1/FIRE provider boundaries`**.
- PR base: `main@6318999` after C1.x reconciliation landing.
- Root `/etc/hosts` was temporarily overridden only to work around the VM DNS failure for GitHub API access and was restored byte-for-byte from backup immediately after PR creation.

## Next exact task

Lane B final convergence is complete. Keep PR #14 open for merge review; do not merge it from this lane. Remaining evidence gates are the live Subrouter/GitHub/Fabro/ACP/runtime checks listed above and cross-lane I1 integration owned by the coordinator.


## Coordinator convergence after Lane C landing — 2026-08-21

The root coordinator resumed this lane after Lane C PR #15 landed on `origin/main` as `5eca896`.

- Rebase onto `origin/main@5eca896`: completed locally.
- The only convergence conflict was the expected shared root `pnpm-lock.yaml` conflict.
- The lockfile was regenerated with repository-pinned Node 22 / pnpm and now includes both Lane B and Lane C provider workspace importers: `account-subrouter`, `agent-acp`, `factory-fabro`, `vcs-github`, `ci-github`, `workflow-dbos`, and `workspace-kubernetes`.
- No Lane B provider source conflict with Lane C implementation occurred.
- This section supersedes the earlier instruction to keep PR #14 untouched while Lane C/C1.x were unlanded.

### Remaining coordinator gate before PR #14 may land

1. Push the rebased branch with lease protection.
2. Run a clean `CI=true pnpm install --frozen-lockfile` on an authorized buildbox (`debian1/2/3`).
3. Run aggregate `pnpm check` and focused Lane B provider tests on an authorized buildbox.
4. Confirm PR #14 remains clean/mergeable against latest `main` and inspect the final diff for ownership/FIRE regressions.
5. Only then merge PR #14.

Until those remote gates are recorded, the rebased branch is convergence-ready but not yet accepted for landing.

### Post-Lane-C rebase validation — 2026-08-21

The coordinator re-ran the required convergence gates on authorized buildbox `debian1` against the rebased branch. Runtime selection used `mise x node@22`, resolving Node `v22.23.2` and pnpm `9.7.0`.

- `CI=true pnpm install --frozen-lockfile`: **PASS**, all 17 workspace projects recognized.
- aggregate `pnpm check`: **PASS**.
- repository tests: **24 files / 94 tests PASS**.
- focused Lane B provider tests: **4 files / 38 tests PASS**.
- architecture: **6/6 PASS**.
- dependency-cruiser: **63 modules / 78 dependencies, 0 violations**.
- typecheck, lint, build and Prettier: **PASS**.

This closes the post-Lane-C rebase validation gate. PR #14 is now eligible for coordinator landing, subject only to confirming the remote head has not changed.
