Skip to content

Remove the anonymous v2 household list - #4032

Draft
MaxGhenis wants to merge 4 commits into
masterfrom
max/remove-v2-household-list-20261024
Draft

MaxGhenis wants to merge 4 commits into
masterfrom
max/remove-v2-household-list-20261024

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #4031

Summary

  • Remove GET /v2/households. It returned stored households with their full inputs, page by page, without a credential. Nothing calls it: app-v2 reads households by ID, and a GitHub code search finds no other caller. Its response models, query model, service method and paging read go with it.
  • POST /v2/households and GET /v2/households/{household_id} are unchanged. A GET on the collection path now gets the v2 404.
  • Migration contract artifacts are regenerated (88 requests).
  • Adds hypothesis to the dev extra, with the same pyproject.toml, uv.lock and .gitignore lines as Remove the v1 user routes and keep complete simulation and report results final #4029.

What stays open

  • The v1 route GET /{country_id}/household/{id} still reads any household by its integer ID without a credential. POST /v2/user-households with a legacy_household_id also returns the v2 ID of that household's copy to any caller, including one with only the signed-out header. app-v2 loads saved and shared households through the v1 route, so closing these needs an app change first.
  • GET /v2/policies is still an anonymous list. Policies hold parameter values, not household inputs.
  • Every deploy tags its Cloud Run revision, and nothing removes the tags. Revisions from before this change would still serve the list at their tag URLs until those tags are removed. As with Remove the v1 user routes and keep complete simulation and report results final #4029, that is a production change for a maintainer.

Testing

  • Three new tests failed on master and pass here:
    • a regression test: the anonymous list request gets 404 and the service is not called;
    • a Hypothesis property over generated queries (country_id, offset, limit, default_year, extra parameters) and credentials (none, a bearer token, the signed-out header): the collection path never returns household content and never reaches the service, even one that would return a page;
    • an OpenAPI check that no operation open to a caller without an account returns an array or map of HouseholdItem. "Open" means no security requirement, or one met by the signed-out header alone, which the caller generates. A fourth test gives it positive controls for each list and credential shape.
  • scripts/run_quality_guards.py, scripts/export_migration_contracts.py, mypy, ruff format --check . and ruff check . pass. The make test suite (tests/to_refactor tests/unit tests/contract) passes locally: 3383 tests.

Review

A GPT-6.1 Sol review of 877b1e04 requested changes. It found that the OpenAPI check skipped routes gated only by the signed-out header and missed composed list items such as list[HouseholdItem | None]; 889a072d fixes both, and both of the reviewer's mutants now fail it. It also found the legacy-ID path through /v2/user-households, which predates this PR and is listed above.

axiom: n/a: API route removal, no policy change

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 24, 2026 14:11
Add a regression test, a Hypothesis property over generated queries and
credentials, and an OpenAPI check that no anonymous v2 operation returns a
list of households. All three fail against the current route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /v2/households returned complete stored households page by page with
no credential, and no client calls it. Remove the route with its response
models, query model, service method and paging read. Creating a household
and reading one by ID are unchanged; GET /v2/households now reaches the v2
not-found handler.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.78%. Comparing base (b5cf71d) to head (09d8e6b).

Additional details and impacted files
@@             Coverage Diff             @@
##           master    #4032       +/-   ##
===========================================
+ Coverage   50.96%   87.78%   +36.82%     
===========================================
  Files         242      258       +16     
  Lines       14527    15911     +1384     
  Branches     2334     2614      +280     
===========================================
+ Hits         7403    13968     +6565     
+ Misses       6501     1277     -5224     
- Partials      623      666       +43     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The OpenAPI check skipped any operation that declared security, but the
signed-out header carries a UUID the caller generates, so a route that
accepts it alone is open to anyone. It also matched only a direct
items reference, missing list[HouseholdItem | None], maps and wrapped
items. Follow element schemas through references and composition, treat
signed-out-header-only alternatives as open, and add positive controls
for each list and credential shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delete only the removed name, so the import keeps its existing form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove the unauthenticated v2 household list

1 participant