Skip to content

Add a second Anthropic API key entry to the credential inventory - #889

Merged
seathatflowsinourveins merged 5 commits into
mainfrom
claude/cc-anthropic-api-2-20261008
Oct 8, 2026
Merged

seathatflowsinourveins merged 5 commits into
mainfrom
claude/cc-anthropic-api-2-20261008

Conversation

@seathatflowsinourveins

@seathatflowsinourveins seathatflowsinourveins commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Scope

  • What this PR changes: it adds the optional anthropic-api-2 entry directly after anthropic-api in adoption/credential-inventory.json, so one command can select an additional Console key. It is an additional key: nothing is replaced. The setter, the runner and the guard are unchanged: the setter and the runner read the inventory, and the guard's rules already cover the variable and the whole store directory. Both entries declare only ANTHROPIC_API_KEY, which stays in must_not_be_set.
  • Base commit: e48de2e6fa1dd3b740af4793ea5824ea35476dba
  • Lane: lane:foundation
  • Owned paths touched: adoption/credential-inventory.json, docs/secret-storage.md, docs/decisions/2026-10-08-anthropic-api-second-key.md, docs/harness-defaults.md, tests/test_credential_run.py, catalogs/foundation/upstream-surface-dispositions.json, and manifests/evidence.json (the hashes of those six files, written by scripts/host_receipts.py:register_file).

The new entry differs from the first in exactly six fields: id, label, store.path_template (file anthropic-api-2.env in the same directory), loaders, rotation and notes. Class, status, lane, variables, optional and pointer variables, consumers and store kind are identical. The repository precedent is alpaca-paper-2 (#481, c26800f3).

Scope beyond the brief. Four edits go beyond adding the entry. They are declared here so that the read of this PR covers them:

  1. One sentence of the first entry's notes is corrected. Old: "exported in a shell it would override every Claude Code session's native sign-in". New: "a shell export can switch Claude Code from subscription sign-in to API billing (headless mode uses the key when present; interactive mode first asks for approval)". Source: Claude Code's environment variables page, where a present key is always used in non-interactive mode (-p) and is approved once in interactive mode before it overrides the subscription. The new entry gives the same reason, so the two entries agree. No other field of anthropic-api changes.
  2. One row is added to the anti-pattern log of docs/harness-defaults.md. It records that correction, which that page's "Record a correction the same turn" rule asks for.
  3. docs/secret-storage.md gains the first key's table row as well. The entry table had no anthropic-api row. It now lists both entries, followed by one paragraph on selecting a key for one command.
  4. Five line citations into docs/secret-storage.md are updated in catalogs/foundation/upstream-surface-dispositions.json, because the added rows moved the cited lines down by 18. The source locators of CLAUDE_CODE_ENABLE_TELEMETRY (1697 → 1715), OTEL_LOG_USER_PROMPTS and OTEL_LOG_ASSISTANT_RESPONSES (1684 → 1702), and OTEL_LOG_TOOL_CONTENT and OTEL_LOG_RAW_API_BODIES (1686 → 1704) change; no disposition or reason does. Hosted validate-shard-3 failed five subtests of DispositionCitationTests.test_every_cited_line_names_the_key at 88d981c7; Declare the optional public EdgarTools request cap #858 made the same repair for its own insertion.

SOTA sources

Public primary documentation, fetched 2026-10-08; every cited anchor resolves.

Evidence-class table

Claim Evidence class Command / receipt
The Console key and environment contract, and the mode-dependent sign-in wording source_review The official pages linked above, fetched 2026-10-08
The new entry differs from the first in six fields only; the inventory goes from 20 to 21 entries and from 10 to 11 injectable ids; of anthropic-api, only notes changes source_review Field-by-field comparison of both entries against origin/main, using the runner's own injectable()
The setter and the runner select separate files, leave the first file unchanged when the second is written, accept the same bare and quoted grammar, inject only the selected value and refuse expansion local_integration; synthetic InjectionTests.test_second_anthropic_key_uses_the_same_setter_and_runner_grammar: temporary store, generated fake values
The guard needs no edit: it lists no ids, its store rule covers the whole store directory, and the variable is already a guarded name source_review; synthetic STORE_PATHS and SECRET_NAMES in the guard; tests.test_secret_path_guard; guard.read_command on nine synthetic command forms returns the same reason for both ids (four store-path forms credential_store_path, the documented runner form allowed)
No leak in the six files of the first commit local_integration betterleaks dir 1.9.0 with .gitleaks.toml on a copy of those six files: no leaks, rc 0. The required gate is CI's pinned gitleaks 8.30.1, which is not installed on this host; hosted secret-scan passed at 88d981c7
Each of the five re-pointed catalog locators names its key again, and no other maintained citation moved local_integration; source_review tests.test_upstream_surface_watch: 5 of 128 repository citations failed with the catalog at 88d981c7, 0 fail now. Of 263 line citations into the four edited files, 126 point past the inserted lines: these 5; 46 pinned to a commit; 75 in dated records, frozen evidence or code comments that already pointed elsewhere before this PR or carry their own source revision

Not measured here: the actual key type, the workspace spend limit, credit, fast mode and provider acceptance. A multi-workspace key needs the anthropic-workspace-id header and is outside this single-variable entry.

Every changed existing test expectation

One constant changes, and two existing tests assert on it. The exact injectable set was alpaca-paper, alpaca-paper-2, sec-contact, databento, typesafe, omniroute, tavily, claude-oauth-token, canary-e2e and anthropic-api. INJECTABLE_IDS now adds only anthropic-api-2.

Existing test Old contract → new contract
InjectionTests.test_only_the_selected_entrys_own_pointer_variables_stay_in_the_child Exactly the ten ids above are injectable, and each keeps only its own pointer variables → the same contract for eleven ids, adding anthropic-api-2, whose own pointer list is empty.
InventoryAndGrammarTests.test_every_injected_name_is_masked_or_public Exactly those ten ids classify every injected variable as masked or public → eleven ids, adding the masked required variable of anthropic-api-2. The exact optional-variable classification is unchanged, because the new entry has none.

No other existing assertion is edited. NOT_INJECTABLE_IDS is unchanged. The status module checks the canonical inventory dynamically and by subset. The boot-receipt allowlist test compares the receipt's rows with the canonical inventory, so its expected id sequence follows the inventory (20 → 21 rows; file-kind rows 18 → 19). The guard's tie tests read the inventory's variable and pointer names, which do not change. Fixtures are unchanged.

InjectionTests.test_second_anthropic_key_uses_the_same_setter_and_runner_grammar is new coverage, not a relaxed assertion.

Local commands run

One module per command (no suite discovery). The twelve modules below ran on the tree committed as 5117734b, the first commit on e48de2e6. The second commit, 88d981c7, only removes two process claims from the decision record that nothing in the repository can verify; the docs module and the validator were run again on its tree. The third commit, 75fa64b3, re-points five catalog citations; the last block covers it and the whole suite.

$ timeout 600 nice -n 10 ionice -c2 -n7 python3 -m unittest tests.<module> -v
tests.test_credential_status            rc 0   Ran 48    OK
tests.test_credential_tools             rc 0   Ran 34    OK
tests.test_credential_run               rc 0   Ran 94    OK
tests.test_credential_boot_receipt      rc 0   Ran 21    OK
tests.test_secret_path_guard            rc 0   Ran 90    OK (skipped=2: scratch adapter supplied by the permanent-test mutation driver)
tests.test_canary_proof                 rc 0   Ran 143   OK (skipped=134: reviewed ripgrep unavailable on this host)
tests.test_codex_worker_lane            rc 0   Ran 123   OK (skipped=12: real app-server runs need NAS_CODEX_INTEGRATION=1)
tests.test_host_requests                rc 0   Ran 49    OK
tests.test_new_wsl_definitive_defaults  rc 0   Ran 130   OK (skipped=3: GNU chmod --reference and readlink -f commands)
tests.test_adoption_docs_consistency    rc 0   Ran 39    OK (skipped=1: no profile's coverage differs between the pinned release and HEAD)
tests.test_sota_convergence             rc 0   Ran 157   OK
tests.test_ecosystem_manifest           rc 0   Ran 82    OK
$ python3 scripts/evidence_manifest.py --check
rc 0   {"files": 10901, "status": "passed"}
$ timeout 900 nice -n 10 ionice -c2 -n7 python3 scripts/validate.py
rc 0   {"components": 70, "hashed_files": 10901, "profiles": 4, "receipts": 239, "status": "passed"}

On the tree committed as 88d981c7:

$ timeout 600 nice -n 10 ionice -c2 -n7 python3 -m unittest tests.test_adoption_docs_consistency -v
rc 0   Ran 39    OK (skipped=1)
$ timeout 900 nice -n 10 ionice -c2 -n7 python3 scripts/validate.py
rc 0   {"components": 70, "hashed_files": 10901, "profiles": 4, "receipts": 239, "status": "passed"}

Hosted validate at 88d981c7 (run 37846469750) failed one shard: validate-shard-3, Ran 1514 tests, FAILED (failures=5, skipped=127). All five failures were the stale catalog citations. The third commit, 75fa64b3, fixes them. On its tree:

$ timeout 600 python3 -m unittest tests.test_upstream_surface_watch -v
rc 0   Ran 114   OK (skipped=6)
$ timeout 600 python3 -m unittest tests.test_adoption_docs_consistency tests.test_credential_run
rc 0   Ran 133   OK (skipped=1)
$ timeout 900 python3 scripts/validate.py
rc 0   {"components": 70, "hashed_files": 10901, "profiles": 4, "receipts": 239, "status": "passed"}
$ for m in tests/test_*.py: timeout 600 python3 -m unittest tests.$m   (each module on its own, no discovery)
276 modules: 255 rc 0, 21 rc 1; 10,725 tests ran, 911 skipped

The 21 nonzero modules all passed in hosted validate at 88d981c7. Locally they fail for host reasons, not because of this diff:

  • 18 modules: exchange_calendars is not installed in this host's Python 3.13. Hosted installs 4.13.2 from .github/requirements-calendar.txt. Sixteen modules do not import: the 13 test_adaptive_paper_* modules other than credential_race, plus test_alpaca_admission_regressions, test_native_faults_min and test_order_throughput. test_ingest_snapshot has 2 errors. test_adaptive_paper_credential_race has 5 mutation self-test failures, because its pristine run imports the runner module. All 18 fail the same way on a checkout of the base e48de2e6.
  • test_token_e2e_grader: git clone --local from the worktree (on disk) into /tmp (tmpfs) fails with Invalid cross-device link. It passes on the base checkout, which lives on tmpfs.
  • test_windows_terminal_defaults: the Claude Code client installed on this host reports a plugin_notification notification type that has no repository decision. The base gives the same failure.
  • test_new_wsl_mcp_conformance_lifecycle: host-state dependent. Three runs at this head gave a listener assertion, a missing cleanup.json, then a pass; it passes on the base.

The fourth commit, 67d9e8d5, corrected a stale comment citation in blueprints/runtime-workers/openhands/resolver/patch_policy.py. That citation was already wrong on main, so it is outside this PR's scope and will be handled separately. The fifth commit, 2fa607e1, reverts it. The head's tree is identical to 75fa64b3's (tree d399373a). On it, timeout 900 python3 scripts/validate.py returns rc 0.

Decision record

docs/decisions/2026-10-08-anthropic-api-second-key.md: the decision, the handling rules, the sources, the alpaca-paper-2 precedent, the correction, the evidence boundaries, the alternatives and what would reopen the decision, and the inverse.

Host evidence

Not applicable: this PR adds or changes no file under evidence/hosts/.

Checklist

  • New/changed GitHub Actions are pinned to a full commit SHA with a version comment (none changed).
  • New/changed workflows declare least-privilege permissions (none changed).
  • No secrets are printed, logged or committed; no new required secret was added. No credential value or credential store was read, inspected, created or changed for this PR: the tests use a temporary store and generated fake values, and the setter, launcher and runner were not run against a real entry.
  • No new paid hosting, subscription or billing surface is introduced by this declaration. The key itself is supplied later through the existing hidden prompt; its credit and spend limit are not measured here.
  • Peer-owned untracked files and worktrees were preserved.

Landing notes

🤖 Generated with Claude Code

Add the optional anthropic-api-2 entry directly after anthropic-api. It
mirrors the first entry's class, status, lane, variables, consumers and
store kind, with its own env file, loader and rotation text. It is an
additional key: nothing is replaced, and the setter, the runner and the
guard are unchanged.

- docs/secret-storage.md lists both Anthropic entries and how one
  command selects a key.
- tests/test_credential_run.py expects eleven injectable ids instead of
  ten and adds one test that the setter and the runner treat both ids
  alike, using a temporary store and generated fake values.
- The first entry's note on why the key variable stays out of the shell
  is corrected to match Claude Code's current guidance (headless mode
  uses a present key; interactive mode asks once first), and the
  correction is recorded in the anti-pattern log of
  docs/harness-defaults.md.
- docs/decisions/2026-10-08-anthropic-api-second-key.md records the
  decision, its sources, the alpaca-paper-2 precedent and the inverse.
- manifests/evidence.json is refreshed with host_receipts.register_file.

No credential value or store was read.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Oct 8, 2026
seathatflowsinourveins and others added 4 commits October 8, 2026 17:22
Drop the sentence about a skill applied before editing, and state the
unmeasured boundaries (key type, workspace spend limits, installed
consumer acceptance and provider execution) directly instead of
attributing them to a reviewer. Nothing in the repository can verify
either claim. No other wording changes.

manifests/evidence.json is refreshed for the record with
host_receipts.register_file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The lines this branch adds to docs/secret-storage.md move its telemetry
section down 18 lines. Update the five source locators in
catalogs/foundation/upstream-surface-dispositions.json that cite those
lines (the telemetry switch and its four content flags), so that each
cited line names its key again. Only the line numbers change: no
disposition, reason or test is edited.

tests.test_upstream_surface_watch failed five subtests of
DispositionCitationTests.test_every_cited_line_names_the_key on the
previous head and passes with this change.

manifests/evidence.json is refreshed for the catalog with
host_receipts.register_file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
blueprints/runtime-workers/openhands/resolver/patch_policy.py cited
docs/secret-storage.md:199-200 for the directory that the repository's
relative core.hooksPath names. Those lines are about the runner's
masking and its output path, on main as well as on this branch; the
statement was already elsewhere (lines 412-413) when the comment was
written in 3b8f9c8. The comment now cites 442-443, where the page sets
`git config core.hooksPath scripts/git-hooks` and notes that the
relative path makes each worktree run its own checkout's hook. Only the
comment changes; the file keeps its line count.

The citation of docs/harness-defaults.md:208 in push_gate.py is left as
it is: its list ends "(at 56fced8)", and at that commit line 208 is
the instruction-file row the comment refers to.

manifests/evidence.json is refreshed for the file with
host_receipts.register_file.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ate it"

This reverts commit 67d9e8d.

The stale citation in patch_policy.py predates this pull request and is
outside its scope; it will be handled separately. With this revert the
tree is identical to 75fa64b's again: patch_policy.py and its
registered hash in manifests/evidence.json return to their previous
content.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@seathatflowsinourveins
seathatflowsinourveins marked this pull request as ready for review October 8, 2026 23:14
@seathatflowsinourveins
seathatflowsinourveins merged commit aba02ec into main Oct 8, 2026
36 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/cc-anthropic-api-2-20261008 branch October 8, 2026 23:17
seathatflowsinourveins added a commit that referenced this pull request Oct 9, 2026
main moved to aba02ec (#889 and others), and manifests/evidence.json
conflicted, so no pull_request workflow ran on the branch. The manifest is
resolved by the hot-file protocol: main's copy, then this branch's seven
changed files re-registered with host_receipts.register_file, followed by
component_matrix.py --write and new_host_grand_list.py --write;
validate.py exits 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins added a commit that referenced this pull request Oct 9, 2026
main moved to aba02ec (#889 and others), and manifests/evidence.json
conflicted, so no pull_request workflow ran on the branch. The manifest is
resolved by the hot-file protocol: main's copy, then this branch's 8
changed files re-registered with host_receipts.register_file, followed by
component_matrix.py --write and new_host_grand_list.py --write;
validate.py exits 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins added a commit that referenced this pull request Oct 9, 2026
main moved to aba02ec (#889 and others), and manifests/evidence.json
conflicted, so no pull_request workflow ran on the branch. The manifest is
resolved by the hot-file protocol: main's copy, then this branch's 8
changed files re-registered with host_receipts.register_file, followed by
component_matrix.py --write and new_host_grand_list.py --write;
validate.py exits 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
seathatflowsinourveins added a commit that referenced this pull request Oct 9, 2026
main moved to aba02ec (#889 and others), and manifests/evidence.json
conflicted, so no pull_request workflow ran on the branch. The manifest is
resolved by the hot-file protocol: main's copy, then this branch's 7
changed files re-registered with host_receipts.register_file, followed by
component_matrix.py --write and new_host_grand_list.py --write;
validate.py exits 0.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant