Skip to content

Declare the optional public EdgarTools request cap - #858

Merged
seathatflowsinourveins merged 1 commit into
mainfrom
codex/ns2604-edgar-rate-limit-20261008
Oct 8, 2026
Merged

seathatflowsinourveins merged 1 commit into
mainfrom
codex/ns2604-edgar-rate-limit-20261008

Conversation

@seathatflowsinourveins

@seathatflowsinourveins seathatflowsinourveins commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Scope

EDGAR research commands can now declare EDGAR_RATE_LIMIT_PER_SEC through the existing sec-contact inventory. The runner passes this optional public cap unmasked and continues masking both contact identities. The example leaves a cap of5 commented out; an unset cap preserves EdgarTools' native default of9 requests/sec, separate from the SEC maximum10.

  • Base commit: eb5fee4db9a494729deb29bdf38dbabac23ee643
  • Lane: lane:foundation
  • Owned paths: adoption/credential-inventory.json, docs/examples/sec-contact.env.example, docs/secret-storage.md, the two existing credential test modules, and the integration receipt. manifests/evidence.json only registers the changed files and receipt in the last commit.

SOTA sources

  • dgunning/edgartools v5.61.1@7338aa335f6442c52dfa0695422cf1cd27e946e0: the existing native environment override and integer/default9 contract. Matching official docs/resources/sec-compliance.md and docs/configuration.md describe its rate cap.
  • dgunning/edgartools v5.60.0@1e7a61b3a142dbf5d19bc82444f85239c1786348: installed source at the13:43Z observation is byte-identical to the selected5.61.1 file, SHA256 63675da6f438d5e06422882a07b20802eded59a944a8357242969b53d7876ecc.
  • SEC Fair access: the current maximum10requests/sec is distinct from the vendor9 default.
  • Reuses this repository's existing optional/public-variable runner and validator at the base commit, tools/credentials/credential_run.py and scripts/credential_status.py; no new runner, dependency or installer.

Evidence-class table

Claim Evidence class Command / receipt
Optional public cap and private contact classification local_integration Existing inventory/runner classification assertions
Missing stored cap stays absent despite inherited8; stored5 is public; identities mask on stdout/stderr synthetic Existing isolated credential-runner fixture
Default9 and selected override contract; SEC maximum10 source_review Pinned upstream files and official SEC page
Publication integrity and scope local_integration python3 scripts/validate.py, rc0 at13:55:02Z

Local commands run

python3 -m unittest tests.test_credential_status.CredentialStatusTests.test_public_variables_classify_every_optional_stored_variable tests.test_credential_run.InventoryAndGrammarTests.test_every_injected_name_is_masked_or_public tests.test_credential_run.InventoryAndGrammarTests.test_a_required_variable_is_masked_even_when_a_planted_entry_lists_it_public tests.test_credential_run.InjectionTests.test_sec_contact_optional_rate_cap_is_public_and_identities_stay_masked tests.test_credential_run.InjectionTests.test_parser_never_expands tests.test_credential_run.CheckAndIsolationTests.test_check_mode_prints_names_only -v
rc0; Ran6 tests in1.192s; OK

python3 scripts/validate.py
rc0; 69components,10831hashed_files,4profiles,228receipts; passed
Integrity and scope checks only; no live provider or GPU execution.

git diff --check
rc0; empty output

The first focused check stopped before tests on an introduced indentation error, then the corrected same check passed. Both attempts, exact argv, returned stderr and timestamp limits are retained in evidence/artifacts/edgar-rate-limit-inventory-20261008/receipt.json. These are repository integration/synthetic tests, not upstream vendor acceptance.

Decision record

The receipt records the bounded choice to expose an existing vendor control through the existing inventory and the independent completeness critic. No native SEC request, pacing measurement, numerical cap validator, runtime sync or host setting is part of this evidence. Inverse: revert this landed commit, re-register affected hashes and run the native validator. Landing remains on the command center's cue.

Host evidence

No files under evidence/hosts/ change. Actual runtime installation and its24-check acceptance are owned by the separate runtime lane.

Checklist

  • No GitHub Actions change.
  • No real credential value or authentication store was read, printed, copied or committed.
  • No new paid hosting, subscription or billing surface.
  • Peer-owned untracked files and worktrees preserved.

Citation repair

The first hosted head failed five existing cited-line assertions because the EDGAR documentation paragraph shifted their source lines. This head updates those five catalog locators without changing dispositions or the test oracle. The unchanged affected citation test passes (1 test,0.065s), and final python3 scripts/validate.py returned0 at14:23:29Z:69 components,10832 files,4 profiles,228 receipts. The original failed hosted attempt, actual failure cause and returned affected-test output are retained in evidence/artifacts/edgar-rate-limit-inventory-20261008/ci-citation-repair.json. Hosted checks must pass at the updated head before landing.

@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Oct 8, 2026
@seathatflowsinourveins
seathatflowsinourveins force-pushed the codex/ns2604-edgar-rate-limit-20261008 branch from e77598b to b14da93 Compare October 8, 2026 14:24
@seathatflowsinourveins
seathatflowsinourveins merged commit d523b3f into main Oct 8, 2026
35 of 49 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the codex/ns2604-edgar-rate-limit-20261008 branch October 8, 2026 15:35
seathatflowsinourveins added a commit that referenced this pull request Oct 8, 2026
### 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](https://code.claude.com/docs/en/env-vars#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`; #858 made the same repair for its own insertion.

### SOTA sources

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

- Anthropic [API overview, Getting API keys](https://platform.claude.com/docs/en/api/overview#getting-api-keys) and [Authentication, Create and use a key](https://platform.claude.com/docs/en/manage-claude/authentication#create-and-use-a-key): keys are created on the Console key page, the client SDKs pick up `ANTHROPIC_API_KEY` automatically, and a key scoped to one workspace needs no workspace header.
- Anthropic [Get your API key, Choose a key type](https://platform.claude.com/docs/en/get-api-key#choose-a-key-type), [Workspaces, API keys and resource scoping](https://platform.claude.com/docs/en/manage-claude/workspaces#api-keys-and-resource-scoping) and [Set workspace limits](https://platform.claude.com/docs/en/manage-claude/workspaces#set-workspace-limits): personal, service-account and legacy workspace keys; a multi-workspace key needs the `anthropic-workspace-id` header; spend limits are set per workspace.
- Claude Code [environment variables](https://code.claude.com/docs/en/env-vars#variables) and [authentication precedence](https://code.claude.com/docs/en/authentication#authentication-precedence): in non-interactive mode (`-p`) a present key is always used; in interactive mode the key is approved once before it overrides the subscription. These support the corrected wording.
- Anthropic [WIF reference, Profile configuration file](https://platform.claude.com/docs/en/manage-claude/wif-reference#profile-configuration-file): the configuration-profile alternative that the decision record names.
- [This repository at `c9ab2212142398234b6ba39a4cf33c5c2a6a643e`](https://github.com/seathatflowsinourveins/native-agent-stack/tree/c9ab2212142398234b6ba39a4cf33c5c2a6a643e), the reference implementation this change follows; the cited files are unchanged at the base commit: inventory entries `anthropic-api` (#841, `a35369aa`) and `alpaca-paper-2`; `tools/credentials/set_credential.py:load_entry`; `tools/credentials/credential_run.py:find_entry` and `injectable`; the guard's `SECRET_NAMES`, `STORE_PATHS` and `ENV_FILE_WORD` in `scripts/hooks/secret_path_guard.py`; the `RunnerCase` fixtures in `tests/test_credential_run.py`; `scripts/host_receipts.py:register_file` and `scripts/validate.py`. No credential runtime or dependency is added.

### 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

- [x] New/changed GitHub Actions are pinned to a full commit SHA with a version comment (none changed).
- [x] New/changed workflows declare least-privilege permissions (none changed).
- [x] 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.
- [x] 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.
- [x] Peer-owned untracked files and worktrees were preserved.

### Landing notes

- This PR declares a store; it neither creates one nor opens the paste window.
- #850 (open) inserts `anthropic-admin` at the same position in the inventory and edits the same `INJECTABLE_IDS` line; #769 and #770 (drafts) also touch the inventory, `docs/secret-storage.md` and `tests/test_credential_run.py`. Whichever lands second needs a rebase and a fresh `register_file` pass.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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