chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
---
|
||||
summary: "Current Claude behavior baseline before vNext refactor work."
|
||||
read_when:
|
||||
- Planning Claude refactor tickets
|
||||
- Changing Claude runtime/source selection
|
||||
- Changing Claude OAuth prompt or cooldown behavior
|
||||
- Changing Claude token-account routing
|
||||
---
|
||||
|
||||
# Claude current baseline
|
||||
|
||||
This document is the current-state parity reference for Claude behavior in CodexBar.
|
||||
|
||||
Use it when later tickets need to preserve or intentionally change Claude behavior. When the refactor plan,
|
||||
summary docs, and running code disagree, treat current code plus characterization coverage as authoritative, and use
|
||||
this document as the human-readable summary of that current state.
|
||||
|
||||
## Scope of this baseline
|
||||
|
||||
This baseline captures the current behavior surface that later refactor work must preserve unless a future ticket
|
||||
changes it intentionally:
|
||||
|
||||
- runtime/source-mode selection,
|
||||
- prompt and cooldown behavior that affects Claude OAuth repair flows,
|
||||
- token-account routing at the app and CLI edges,
|
||||
- provider siloing and web-enrichment rules,
|
||||
- the current relationship between the public Claude doc and the vNext refactor plan.
|
||||
|
||||
## Active behavior owners
|
||||
|
||||
Current Claude behavior is defined by several active owners, not one central planner:
|
||||
|
||||
- `Sources/CodexBarCore/Providers/Claude/ClaudeProviderDescriptor.swift`
|
||||
owns the main provider-pipeline strategy order and fallback rules.
|
||||
- `Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift`
|
||||
still owns a separate direct `.auto` path, delegated refresh, prompt/cooldown handling, and web-extra enrichment.
|
||||
- `Sources/CodexBar/Providers/Claude/ClaudeSettingsStore.swift`
|
||||
owns app-side token-account routing into cookie or OAuth behavior.
|
||||
- `Sources/CodexBarCLI/TokenAccountCLI.swift`
|
||||
owns CLI-side token-account routing and effective source-mode overrides.
|
||||
- `Sources/CodexBarCore/TokenAccountSupport.swift`
|
||||
owns the current string heuristics that distinguish Claude OAuth access tokens from cookie/session-key inputs.
|
||||
|
||||
## Current runtime and source-mode behavior
|
||||
|
||||
### Main provider pipeline
|
||||
|
||||
The generic provider pipeline currently resolves Claude strategies in this order:
|
||||
|
||||
| Runtime | Selected mode | Ordered strategies | Fallback behavior |
|
||||
| --- | --- | --- | --- |
|
||||
| app | auto | `oauth -> cli -> web` | OAuth can fall through to CLI/Web. CLI can fall through to Web only when Web is available. Web is terminal. |
|
||||
| app | oauth | `oauth` | No fallback. |
|
||||
| app | cli | `cli` | No fallback. |
|
||||
| app | web | `web` | No fallback. |
|
||||
| cli | auto | `web -> cli` | Web can fall through to CLI. CLI is terminal. |
|
||||
| cli | oauth | `oauth` | No fallback. |
|
||||
| cli | cli | `cli` | No fallback. |
|
||||
| cli | web | `web` | No fallback. |
|
||||
|
||||
This behavior is owned by `Sources/CodexBarCore/Providers/Claude/ClaudeProviderDescriptor.swift`
|
||||
through `ProviderFetchPlan` and `ProviderFetchPipeline`.
|
||||
|
||||
### Other active `.auto` decision sites
|
||||
|
||||
The codebase still contains multiple active `.auto` decision sites:
|
||||
|
||||
| Owner | Current behavior |
|
||||
| --- | --- |
|
||||
| `ClaudeProviderDescriptor.resolveUsageStrategy(...)` | Chooses `oauth`, then `cli`, then `web`, with final `cli` fallback when none are available. |
|
||||
| `ClaudeUsageFetcher.loadLatestUsage(.auto)` | Chooses `oauth`, then `web`, then `cli`, with final `oauth` fallback. |
|
||||
|
||||
This inconsistency is intentional to record here. RAT-107 directly characterizes the active direct-fetcher branches it
|
||||
can reach cleanly in tests and records the remaining current-state behavior without reconciling it.
|
||||
|
||||
## Prompt and cooldown baseline
|
||||
|
||||
Current behavior that later refactor work must preserve:
|
||||
|
||||
- The default Claude keychain prompt mode is `onlyOnUserAction`.
|
||||
- Prompt policy is only applicable when the Claude OAuth read strategy is `securityFramework`.
|
||||
- User-initiated interaction clears a prior Claude keychain cooldown denial before retrying availability or repair.
|
||||
- Startup bootstrap prompting is allowed only when all of these are true:
|
||||
- runtime is app,
|
||||
- interaction is background,
|
||||
- refresh phase is startup,
|
||||
- prompt mode is `onlyOnUserAction`,
|
||||
- no cached Claude credentials exist.
|
||||
- Background delegated refresh is blocked when prompt policy is `onlyOnUserAction` and the caller did not explicitly
|
||||
allow background delegated refresh.
|
||||
- Prompt mode `never` blocks delegated refresh attempts.
|
||||
- Expired credential owner behavior remains owner-specific:
|
||||
- `.claudeCLI`: delegated refresh path,
|
||||
- `.codexbar`: direct refresh path,
|
||||
- `.environment`: no auto-refresh.
|
||||
|
||||
## Token-account routing baseline
|
||||
|
||||
Accepted Claude token-account input shapes today:
|
||||
|
||||
- raw OAuth access token with `sk-ant-oat...` prefix,
|
||||
- `Bearer sk-ant-oat...` input,
|
||||
- raw session key,
|
||||
- full cookie header.
|
||||
|
||||
Current routing rules:
|
||||
|
||||
- OAuth-token-shaped inputs are not treated as cookies.
|
||||
- Cookie/header-shaped inputs are any value that already contains `Cookie:` or `=`.
|
||||
- App-side Claude snapshot behavior:
|
||||
- OAuth token account keeps the usage source setting as-is, disables cookie mode (`.off`), clears the manual cookie
|
||||
header, and relies on environment-token injection.
|
||||
- Session-key or cookie-header account keeps the usage source setting as-is, forces manual cookie mode, and
|
||||
normalizes raw session keys into `sessionKey=<value>`.
|
||||
- CLI-side Claude token-account behavior:
|
||||
- OAuth token account changes the effective source mode from `auto` to `oauth`, disables cookie mode, omits a
|
||||
manual cookie header, and injects `CODEXBAR_CLAUDE_OAUTH_TOKEN`.
|
||||
- Session-key or cookie-header account stays in cookie/manual mode.
|
||||
|
||||
## Siloing and web-enrichment baseline
|
||||
|
||||
Claude Web enrichment is cost-only when the primary source is OAuth or CLI:
|
||||
|
||||
- Web extras may populate `providerCost` when it is missing.
|
||||
- Web extras must not replace `accountEmail`, `accountOrganization`, or `loginMethod` from the primary source.
|
||||
- Snapshot identity remains provider-scoped to Claude.
|
||||
|
||||
This behavior is implemented in `Sources/CodexBarCore/Providers/Claude/ClaudeUsageFetcher.swift`
|
||||
inside `applyWebExtrasIfNeeded`.
|
||||
|
||||
## Documentation contract
|
||||
|
||||
- [docs/claude.md](../claude.md) is the summary doc for contributors who want an overview.
|
||||
- This file is the exact current-state baseline for contributor and refactor parity work.
|
||||
- [claude-provider-vnext-locked.md](claude-provider-vnext-locked.md)
|
||||
is the future refactor plan and should cite this file for present behavior.
|
||||
|
||||
## Characterization coverage
|
||||
|
||||
Stable automated coverage for this baseline lives in:
|
||||
|
||||
- `Tests/CodexBarTests/ClaudeBaselineCharacterizationTests.swift`
|
||||
- `Tests/CodexBarTests/ClaudeOAuthFetchStrategyAvailabilityTests.swift`
|
||||
- `Tests/CodexBarTests/ClaudeUsageTests.swift`
|
||||
- `Tests/CodexBarTests/TokenAccountEnvironmentPrecedenceTests.swift`
|
||||
- `Tests/CodexBarTests/SettingsStoreCoverageTests.swift`
|
||||
|
||||
`ClaudeUsageTests.swift` now directly characterizes the reachable `ClaudeUsageFetcher(.auto)` branches for:
|
||||
|
||||
- OAuth when OAuth, Web, and CLI all appear available,
|
||||
- Web before CLI when OAuth is unavailable,
|
||||
|
||||
The successful CLI-selected branch and the CLI-failure-to-OAuth fallback remain documented from code inspection plus
|
||||
surrounding Claude probe/regression coverage, because the current CLI-availability decision is sourced from process-wide
|
||||
binary discovery with no stable test seam that would keep RAT-107 in scope.
|
||||
@@ -0,0 +1,356 @@
|
||||
---
|
||||
summary: "Locked implementation plan for Claude provider vNext: resolved source-selection contracts, typed credential rules, siloing guarantees, and phase gates."
|
||||
supersedes: "Initial vNext draft (removed)"
|
||||
created: "2026-02-18"
|
||||
status: "Locked for implementation"
|
||||
---
|
||||
|
||||
# Claude provider vNext (locked plan)
|
||||
|
||||
This is the implementation-locked vNext plan.
|
||||
|
||||
It preserves the original architecture direction, but removes ambiguity in behavior-critical areas before refactor work starts.
|
||||
|
||||
Current-state parity reference for present behavior:
|
||||
|
||||
- [docs/refactor/claude-current-baseline.md](claude-current-baseline.md)
|
||||
|
||||
Use the baseline doc for present behavior. This vNext plan defines what the refactor should preserve and how it should
|
||||
be staged; it is not the sole source of truth for current implementation details, and RAT-107 does not re-approve the
|
||||
rest of the future architecture below.
|
||||
|
||||
## Assessment snapshot
|
||||
|
||||
- **Approach score:** `8.4/10`.
|
||||
- **Why not 9+ yet:** the original plan left runtime ordering, token-account credential typing behavior, and compatibility mapping under-specified.
|
||||
- **How this doc closes the gap:** explicit contracts + resolved decisions + phase exit gates + risk checklist.
|
||||
- **Validated gap coverage in this version:** explicit `.auto` inconsistency handling, `ClaudeUsageFetcher` decomposition, stronger parity gates, TaskLocal-to-DI migration, and OAuth decomposition sub-phases.
|
||||
|
||||
## Locked behavioral contracts
|
||||
|
||||
These behaviors are **non-negotiable** during refactor unless this doc is explicitly updated.
|
||||
|
||||
### 1) Runtime + source-mode contract
|
||||
|
||||
`ClaudeSourcePlanner` must reproduce this matrix exactly:
|
||||
|
||||
| Runtime | Selected mode | Ordered attempts | Fallback rules |
|
||||
| --- | --- | --- | --- |
|
||||
| app | auto | oauth -> cli -> web | oauth fallback allowed; cli fallback to web only when web available; web terminal |
|
||||
| app | oauth | oauth | no fallback |
|
||||
| app | cli | cli | no fallback |
|
||||
| app | web | web | no fallback |
|
||||
| cli | auto | web -> cli | web fallback allowed to cli; cli terminal |
|
||||
| cli | oauth | oauth | no fallback |
|
||||
| cli | cli | cli | no fallback |
|
||||
| cli | web | web | no fallback |
|
||||
|
||||
Notes:
|
||||
- `sourceLabel` remains the final step label for successful fetch output.
|
||||
- Planner diagnostics must include ordered steps and inclusion reasons.
|
||||
- Planner output must feed the existing generic provider fetch pipeline; do not introduce a second Claude-only
|
||||
execution stack alongside `ProviderFetchPlan` / `ProviderFetchPipeline`.
|
||||
|
||||
### 1a) `.auto` inconsistency characterization contract (must-do before reconciliation)
|
||||
|
||||
Current code has three `.auto` decision sites with inconsistent app ordering:
|
||||
|
||||
- Strategy pipeline resolve order (app): `oauth -> cli -> web`.
|
||||
- `resolveUsageStrategy` helper order: `oauth -> cli -> web -> cli fallback`.
|
||||
- `ClaudeUsageFetcher.loadLatestUsage(.auto)` order: `oauth -> web -> cli -> oauth fallback`.
|
||||
|
||||
Phase 0 must characterize these paths with tests where they are reachable through stable seams, and otherwise defer to
|
||||
the baseline doc before deleting any path.
|
||||
Phase 2 must reconcile this into planner-only source selection.
|
||||
|
||||
### 2) Prompt/cooldown contract
|
||||
|
||||
The planner must use one explicit `ClaudePromptDecision` equivalent, but outcome parity with current behavior is required:
|
||||
|
||||
- User-initiated actions can clear prior keychain cooldown denial.
|
||||
- Startup bootstrap prompt is only allowed when all are true:
|
||||
- runtime is app
|
||||
- interaction is background
|
||||
- refresh phase is startup
|
||||
- prompt mode is `onlyOnUserAction`
|
||||
- no cached credentials
|
||||
- Background delegated refresh is blocked when:
|
||||
- prompt policy is `onlyOnUserAction`
|
||||
- caller does not explicitly allow background delegated refresh
|
||||
- Prompt mode `never` blocks delegated refresh attempts.
|
||||
|
||||
### 3) Credential typing + routing contract
|
||||
|
||||
Typed credentials must be introduced at the settings snapshot edge, with behavior parity:
|
||||
|
||||
- `ClaudeManualCredential.sessionKey`
|
||||
- `ClaudeManualCredential.cookieHeader`
|
||||
- `ClaudeManualCredential.oauthAccessToken`
|
||||
|
||||
Accepted Claude token-account inputs must continue to work:
|
||||
|
||||
- Raw OAuth token (including `Bearer ...` input)
|
||||
- Raw session key
|
||||
- Full cookie header
|
||||
|
||||
Routing parity requirements:
|
||||
|
||||
- OAuth token account values must route to OAuth path (not cookie mode).
|
||||
- Cookie/session-key account values must route to web cookie path.
|
||||
- CLI token-account behavior must remain consistent in both app and `CodexBarCLI`.
|
||||
- Scope note: current string heuristics are mostly edge-routing logic, not deep OAuth credential decoding internals.
|
||||
|
||||
### 4) Ownership and refresh contract
|
||||
|
||||
Credential owner behavior must remain identical:
|
||||
|
||||
- `.claudeCLI` expired credentials: delegated refresh path.
|
||||
- `.codexbar` expired credentials: direct refresh endpoint path.
|
||||
- `.environment` expired credentials: no auto-refresh.
|
||||
|
||||
Refresh failure-gate semantics must remain unchanged.
|
||||
|
||||
### 5) Provider siloing + enrichment contract
|
||||
|
||||
Hard invariant:
|
||||
|
||||
- Never merge Claude Web identity into OAuth/CLI snapshots.
|
||||
- Web extras may enrich **cost only**.
|
||||
- Snapshot identity must always remain provider-scoped to `.claude` when persisted/displayed.
|
||||
|
||||
### 6) Plan inference compatibility contract
|
||||
|
||||
Canonical plan inference can live behind the existing `loginMethod` compatibility surface, but outward
|
||||
compatibility must be preserved:
|
||||
|
||||
- Existing detectable plans continue mapping to display strings:
|
||||
- `Claude Max`
|
||||
- `Claude Pro`
|
||||
- `Claude Team`
|
||||
- `Claude Enterprise`
|
||||
- Subscription detection behavior must remain compatible with current UI logic, including existing `Ultra` detection
|
||||
semantics until that behavior is explicitly changed.
|
||||
|
||||
### 7) Documentation + diagnostics contract
|
||||
|
||||
- During refactor, characterization coverage plus
|
||||
[docs/refactor/claude-current-baseline.md](claude-current-baseline.md)
|
||||
are the source of truth when docs and code disagree.
|
||||
- `docs/claude.md` must be updated as part of Phase 0 after characterization lands so it no longer presents divergent
|
||||
runtime ordering as settled behavior.
|
||||
- Debug surfaces must consume planner-derived diagnostics instead of recomputing Claude source decisions separately.
|
||||
|
||||
## Resolved decisions (from open questions)
|
||||
|
||||
### Web identity fill-ins
|
||||
|
||||
- **Decision:** do not use Web identity to fill missing OAuth/CLI identity fields.
|
||||
- **Allowed:** Web cost enrichment only.
|
||||
|
||||
### CLI runtime fallback ordering
|
||||
|
||||
- **Decision:** keep current CLI ordering in `auto`: `web -> cli`.
|
||||
- Planner must encode this explicitly and not rely on incidental strategy ordering.
|
||||
|
||||
### Startup bootstrap prompt in `onlyOnUserAction`
|
||||
|
||||
- **Decision:** keep support exactly under the startup bootstrap constraints listed above.
|
||||
- Any expansion/restriction requires explicit doc update and tests.
|
||||
|
||||
### Runtime policy unification timing
|
||||
|
||||
- **Decision:** do not unify app and CLI `auto` ordering before this refactor.
|
||||
- First consolidate to one planner implementation with current runtime-specific behavior preserved.
|
||||
- Any runtime-policy unification is a separate, explicit behavior-change follow-up.
|
||||
|
||||
### Planner integration timing
|
||||
|
||||
- **Decision:** `ClaudeSourcePlanner` must be integrated into the existing provider descriptor / fetch pipeline rather
|
||||
than added as a parallel orchestration layer.
|
||||
- Reuse current `ProviderFetchContext` / `ProviderFetchPlan` plumbing where possible.
|
||||
|
||||
### Dependency seam timing
|
||||
|
||||
- **Decision:** introduce dependency-container seams for newly extracted planner/executor components as they are
|
||||
created.
|
||||
- Full TaskLocal cleanup can remain later, but new components should not deepen TaskLocal coupling.
|
||||
|
||||
## Locked migration plan with exit gates
|
||||
|
||||
### Phase 0: Baseline lock
|
||||
|
||||
Deliverables:
|
||||
- Add `docs/refactor/claude-current-baseline.md` as the current-state behavior reference.
|
||||
- Add/refresh characterization tests for runtime/source matrix and prompt-decision parity.
|
||||
- Add explicit characterization tests for existing `.auto` decision paths where they are reachable through stable seams,
|
||||
and defer remaining current-state details to the baseline doc until later reconciliation.
|
||||
- Update `docs/claude.md` after tests land so documented ordering matches characterized behavior.
|
||||
|
||||
Exit gate:
|
||||
- Behavior matrix tests pass for app and cli runtimes.
|
||||
- `.auto` characterization coverage plus the baseline doc record current divergence explicitly without forcing new
|
||||
production seams in Phase 0.
|
||||
- `docs/claude.md` no longer contradicts characterized runtime/source behavior.
|
||||
|
||||
### Phase 1: Canonical plan resolver
|
||||
|
||||
Deliverables:
|
||||
- Introduce `ClaudePlan` + one resolver used by OAuth/Web/CLI mapping and downstream UI consumers.
|
||||
|
||||
Exit gate:
|
||||
- Plan mapping tests cover tier/billing/status-derived hints, compatibility display strings, and current UI subscription
|
||||
detection compatibility.
|
||||
|
||||
### Phase 1b: Typed credentials at the snapshot edge
|
||||
|
||||
Deliverables:
|
||||
- Parse manual Claude credentials once at the app + CLI snapshot edges into a typed model.
|
||||
- Remove duplicated edge-routing heuristics for OAuth-vs-cookie decisions across settings snapshots and token-account
|
||||
CLI code.
|
||||
|
||||
Exit gate:
|
||||
- Token account parity tests pass for app + CLI.
|
||||
- Snapshot-edge routing no longer duplicates Claude OAuth-token detection logic in multiple call sites.
|
||||
|
||||
### Phase 2: Single source planner
|
||||
|
||||
Deliverables:
|
||||
- Introduce `ClaudeSourcePlanner` + explicit `ClaudeFetchPlan`.
|
||||
- Integrate planner outputs into the existing provider pipeline / descriptor flow.
|
||||
- Remove duplicate `.auto` policy branches from lower layers.
|
||||
- Reconcile and remove `ClaudeUsageFetcher` internal `.auto` source selection.
|
||||
- Move debug/diagnostic surfaces to planner-derived attempt ordering instead of helper-specific recomputation.
|
||||
|
||||
Exit gate:
|
||||
- One authoritative planner path for mode/runtime ordering.
|
||||
- Fallback attempt logs still show expected sequence and source labels.
|
||||
- No surviving `.auto` source-order logic outside planner.
|
||||
- No surviving debug-only source-order recomputation outside planner diagnostics.
|
||||
- Old-vs-new planner parity tests pass before old branches are removed.
|
||||
|
||||
### Phase 2b: `ClaudeUsageFetcher` decomposition
|
||||
|
||||
Deliverables:
|
||||
- Split `ClaudeUsageFetcher` into smaller executor-focused components.
|
||||
- Extract delegated OAuth retry/recovery flow into dedicated units.
|
||||
- Remove embedded prompt-policy/source-selection ownership from fetcher; keep it execution-only.
|
||||
|
||||
Exit gate:
|
||||
- Fetcher no longer owns source-selection policy.
|
||||
- Delegated OAuth retry behavior is covered by dedicated tests and remains parity-compatible.
|
||||
|
||||
### Phase 3: Test injection cleanup
|
||||
|
||||
Deliverables:
|
||||
- Prefer dependency seams on extracted units instead of adding new TaskLocal-only override points.
|
||||
- Avoid expanding TaskLocal-only test hooks while decomposition work lands.
|
||||
|
||||
Exit gate:
|
||||
- New fetcher tests rely on explicit dependency seams where practical.
|
||||
|
||||
### Phase 4: OAuth decomposition
|
||||
|
||||
Deliverables (sub-phases):
|
||||
|
||||
- **Phase 4a (repository extraction):**
|
||||
- Extract IO + caching + owner/source loading into repository surface.
|
||||
- Keep prompt-gate semantics unchanged.
|
||||
- **Phase 4b (refresher extraction):**
|
||||
- Extract network refresh + failure gating to refresher component.
|
||||
- Keep owner-based refresh behavior unchanged.
|
||||
- **Phase 4c (delegated controller extraction):**
|
||||
- Extract delegated CLI touch + keychain-change observation + cooldown behavior.
|
||||
- Keep delegated retry outcomes unchanged.
|
||||
|
||||
Exit gate:
|
||||
- Existing OAuth delegated refresh / prompt policy / cooldown suites pass without behavior deltas at each sub-phase.
|
||||
- Owner semantics parity remains intact across all sub-phases (`claudeCLI`, `codexbar`, `environment`).
|
||||
|
||||
### Phase 5: Test injection migration (TaskLocal -> DI)
|
||||
|
||||
Deliverables:
|
||||
- Move test injection from TaskLocal-heavy overrides to `ClaudeFetchDependencies` and explicit protocol stubs.
|
||||
- Keep compatibility shims temporarily where needed, then remove them.
|
||||
|
||||
Exit gate:
|
||||
- Core planner/executor tests run without TaskLocal injection dependencies.
|
||||
- Legacy TaskLocal-only override surfaces are either removed or isolated to compatibility adapters with deletion TODOs.
|
||||
|
||||
### Phase 6: Web decomposition (optional)
|
||||
|
||||
Deliverables:
|
||||
- Separate cookie acquisition from web usage client.
|
||||
- Keep probe tooling isolated behind debug/tool surface.
|
||||
|
||||
Exit gate:
|
||||
- Web parsing and account mapping tests remain green.
|
||||
|
||||
## Implementation PR plan (stacked)
|
||||
|
||||
Use this sequence to keep each PR reviewable without turning the rollout into unnecessary PR overhead.
|
||||
|
||||
| PR | Title | Scope | Primary risks | Must-pass gate before merge |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| PR-01 | Baseline characterization + doc correction | Lock current matrix behavior, characterize `.auto` paths through stable seams, defer remaining lower-level current-state details to the baseline doc, characterize prompt bootstrap/cooldown and token-account routing, then update docs to match reality. | R1, R2, R5, R6, R10 | No production behavior changes; characterization suites green; docs no longer contradict tests or the baseline. |
|
||||
| PR-02 | Canonical plan resolver | Introduce `ClaudePlan` and central resolver; map OAuth/Web/CLI/UI compatibility through one model while preserving current `loginMethod` projections. | R8 | Plan compatibility tests green (`Max/Pro/Team/Enterprise` + current subscription compatibility). |
|
||||
| PR-03 | Typed credentials at the edge | Parse manual credentials once (`sessionKey`, `cookieHeader`, `oauthAccessToken`) in app + CLI snapshot shaping. | R6 | Token-account routing parity tests green in app + CLI contexts. |
|
||||
| PR-04 | Source planner introduction + cutover | Add `ClaudeSourcePlanner`, prove parity against old path, then remove duplicate `.auto` selection branches once parity is proven. | R1, R5, R10 | One `.auto` authority remains; attempt/source-label diagnostics remain parity-compatible. |
|
||||
| PR-05 | `ClaudeUsageFetcher` decomposition | Split fetcher into execution/retry-focused units; remove embedded source-selection ownership. | R2, R10 | Delegated OAuth retry/recovery tests green with no behavior deltas. |
|
||||
| PR-06 | OAuth decomposition | Extract repository, refresher, and delegated-controller seams from `ClaudeOAuthCredentialsStore` while preserving owner semantics. | R3, R4, R7, R9 | Cache/fingerprint/prompt/owner suites green (`claudeCLI`, `codexbar`, `environment`). |
|
||||
| PR-07 (optional) | TaskLocal -> DI migration | Move remaining tests and seams to `ClaudeFetchDependencies`, keep temporary compat adapters, then remove. | R9 | Core planner/executor tests run without TaskLocal globals. |
|
||||
| PR-08 (optional) | Web decomposition | Split cookie acquisition from web usage client and keep tooling isolated. | R8, R10 | Web parsing/account mapping suites remain green. |
|
||||
|
||||
Stacking rules:
|
||||
|
||||
1. Keep each PR scoped to one risk cluster and one merge gate.
|
||||
2. Do not remove old branches until a prior PR has old-vs-new parity tests in CI.
|
||||
3. If a PR intentionally changes behavior, update this locked doc in the same PR and call it out in summary.
|
||||
4. Prefer 6 core PRs unless parity risk forces a temporary split; do not fragment the rollout further without a
|
||||
concrete rollback or reviewability reason.
|
||||
|
||||
## Mandatory test additions
|
||||
|
||||
Add these test groups before or during Phases 1-3, then extend for later phases:
|
||||
|
||||
1. Planner matrix tests:
|
||||
- `(runtime x selected mode x interaction x refresh phase x availability)` -> exact step order + fallback.
|
||||
2. `.auto` divergence characterization tests:
|
||||
- Lock current behavior of strategy pipeline vs `resolveUsageStrategy` helper vs fetcher-direct `.auto`.
|
||||
- Use as guardrails while consolidating to planner-only logic.
|
||||
3. Typed credential parsing tests:
|
||||
- OAuth token, bearer token, session key, cookie header, malformed strings.
|
||||
4. Cross-provider identity isolation tests:
|
||||
- Ensure `.claude` identity does not leak via snapshot scoping/merging.
|
||||
5. Source-label and attempt diagnostics tests:
|
||||
- Validate final source label and attempt list parity.
|
||||
6. CLI token-account parity tests:
|
||||
- `TokenAccountCLIContext` and app settings snapshot behavior match for OAuth-vs-cookie routing.
|
||||
7. Old-vs-new parity tests:
|
||||
- Compare old path and planner path outputs before branch removals in Phase 2 and Phase 2b.
|
||||
8. DI migration tests:
|
||||
- Ensure new dependency container can drive planner/executor tests without TaskLocal globals.
|
||||
|
||||
## Risk checklist (implementation review)
|
||||
|
||||
Use these risk IDs in refactor PR checklists/reviews.
|
||||
|
||||
| Risk ID | Severity | Risk | Detail |
|
||||
| --- | --- | --- | --- |
|
||||
| R1 | Critical | Auto-ordering reconciliation | Three `.auto` paths are inconsistent today. Characterize strategy pipeline vs `resolveUsageStrategy` helper vs fetcher-direct `.auto` before deleting any path. |
|
||||
| R2 | High | Prompt policy consolidation | Prompt policy exists across strategy availability, fetcher flow, and credentials store gates. Preserve startup bootstrap constraints exactly to avoid prompt storms or silent OAuth suppression. |
|
||||
| R3 | High | `ClaudeOAuthCredentialsStore` decomposition | Large lock-protected state + layered caches + fingerprint invalidation + security calls. Splits can break cache coherence, invalidation timing, or prompt gating order. |
|
||||
| R4 | High | Owner semantics drift | Preserve exact owner-to-refresh mapping: `.claudeCLI` delegated, `.codexbar` direct refresh, `.environment` no refresh. |
|
||||
| R5 | Medium | CLI runtime parity | Preserve runtime-specific policy: CLI `auto` remains `web -> cli`; OAuth is available only when explicitly selected as `sourceMode=.oauth`. Do not accidentally default CLI runtime to app ordering. |
|
||||
| R6 | Medium | Token-account OAuth-vs-cookie misrouting | Keep routing parity for OAuth token vs session key vs full cookie header, including `Bearer sk-ant-oat...` normalization. |
|
||||
| R7 | Medium | Cache invalidation regressions | Preserve credentials file/keychain fingerprint semantics and stale-cache guards during repository extraction. |
|
||||
| R8 | Low-Medium | Plan inference heuristic drift | Preserve web-specific plan inference fallback (`billing_type` + `rate_limit_tier`) when unifying plan resolution. |
|
||||
| R9 | Medium | Strict concurrency / `@Sendable` regressions | Maintain thread-safe behavior from current NSLock-based state while moving to DI/decomposed components under Swift 6 strict concurrency. |
|
||||
| R10 | Low | Debug/diagnostic drift | Keep source labels, attempt sequences, and debug output aligned with real planner decisions after consolidation. |
|
||||
|
||||
## Change-control rule
|
||||
|
||||
Any refactor PR that intentionally changes one of the locked contracts above must:
|
||||
|
||||
1. Update this document.
|
||||
2. Add/adjust tests proving the new behavior.
|
||||
3. Call out the behavior change explicitly in the PR summary.
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
summary: "CLI refactor plan: JSON-only errors, config validation, SettingsStore split."
|
||||
read_when:
|
||||
- "Refactoring CodexBar CLI error handling or config parsing."
|
||||
- "Splitting SettingsStore into smaller files."
|
||||
- "Adding config validation or CLI config commands."
|
||||
---
|
||||
|
||||
# CLI Refactor Plan
|
||||
|
||||
## Goals
|
||||
- JSON-only: every error is valid JSON on stdout (no mixed stderr).
|
||||
- Per-provider errors: provider failures yield provider-scoped error payloads.
|
||||
- Config validation: warn on invalid fields, unsupported source modes, bad regions.
|
||||
- Config parity: add CLI command to validate (and optionally dump) config.
|
||||
- SettingsStore split: files <500 LOC; clear separation (defaults vs config).
|
||||
|
||||
## Constraints (keep)
|
||||
- Provider ordering stays driven by config `providers[]` order.
|
||||
- Provider enable/disable stays in config (`enabled`).
|
||||
- No Keychain persistence for provider secrets.
|
||||
- CLI still supports text output for non-JSON use.
|
||||
|
||||
## Error JSON shape
|
||||
- JSON output remains an array for `usage` and `cost` commands.
|
||||
- Errors appear as payload entries with `error` set.
|
||||
- Global/CLI errors use `provider: "cli"` and `source: "cli"`.
|
||||
|
||||
```json
|
||||
{
|
||||
"provider": "cli",
|
||||
"source": "cli",
|
||||
"error": { "code": 1, "message": "...", "kind": "config" }
|
||||
}
|
||||
```
|
||||
|
||||
## Config validation rules
|
||||
- `source` must be in provider descriptor `fetchPlan.sourceModes`.
|
||||
- `apiKey` only valid when provider supports `.api`.
|
||||
- `cookieSource` only valid when provider supports `.web`/`.auto`.
|
||||
- `region` only for `zai` or `minimax` with known values.
|
||||
- `workspaceID` only for `opencode`.
|
||||
- `tokenAccounts` only for providers in `TokenAccountSupportCatalog`.
|
||||
|
||||
## CLI commands
|
||||
- `codexbar config validate`
|
||||
- Prints JSON issues (or text summary).
|
||||
- Exit non-zero if any errors.
|
||||
- (Optional) `codexbar config dump`
|
||||
- Prints normalized config JSON.
|
||||
|
||||
## Step-by-step implementation guide
|
||||
1. **Add validation types**
|
||||
- `CodexBarConfigIssue` + `CodexBarConfigValidator` in `CodexBarCore/Config`.
|
||||
- Keep file <500 LOC.
|
||||
2. **Hook validation into CLI**
|
||||
- New `config validate` command.
|
||||
- `--json-only` emits JSON array of issues.
|
||||
3. **Unify CLI error reporting**
|
||||
- Parse `--json-only` early.
|
||||
- Route all exits through a JSON-aware reporter.
|
||||
- Use provider-scoped errors where possible.
|
||||
4. **Split CLIEntry.swift**
|
||||
- Extract helpers + payload structs into dedicated files (<500 LOC each).
|
||||
5. **Split SettingsStore.swift**
|
||||
- Move config-backed computed properties to `SettingsStore+Config.swift`.
|
||||
- Move defaults-backed computed properties to `SettingsStore+Defaults.swift`.
|
||||
- Move provider detection to `SettingsStore+ProviderDetection.swift`.
|
||||
6. **Provider toggles cleanup**
|
||||
- Remove unused `ProviderToggleStore` + tests; keep migrator path for legacy toggles.
|
||||
7. **Tests**
|
||||
- CLI json-only error payloads (invalid source, invalid provider selection).
|
||||
- Config validation (bad region/source/apiKey field).
|
||||
- SettingsStore order/toggle invariants still pass.
|
||||
8. **Verification**
|
||||
- `make test`, `swiftformat Sources Tests`, `swiftlint --strict`, `make check`.
|
||||
- `./Scripts/compile_and_run.sh`.
|
||||
- CLI e2e: `codexbar --json-only ...`, `codexbar config validate`.
|
||||
Reference in New Issue
Block a user