Skip to content
This repository was archived by the owner on May 13, 2026. It is now read-only.

refactor(identity): rename load_or_generate -> provision; route runtime callers through identity::load + 503 - #908

Merged
shiba4life merged 1 commit into
mainfrom
kanban/19fce-identity-provision
May 6, 2026
Merged

refactor(identity): rename load_or_generate -> provision; route runtime callers through identity::load + 503#908
shiba4life merged 1 commit into
mainfrom
kanban/19fce-identity-provision

Conversation

@shiba4life

Copy link
Copy Markdown
Collaborator

Summary

Bootstrap-collapse step 2 (PR #903 landed step 1).
Kanban task 19fce.

PR #903 made POST /api/setup/bootstrap the canonical first-launch
endpoint, but NodeManager::create_node and ensure_default_identity
still called identity::load_or_generate. That meant a stale
node_config.json could mint a ghost identity behind the user's back
and orphan every previously-ingested record. This closes that gap.

  • identity::load_or_generateidentity::provision, doc-commented
    bootstrap-only. A regression test (provision_only_called_from_setup_route)
    greps the source tree on every cargo test --lib run and fails if any
    file outside src/server/routes/setup.rs reintroduces the call.
  • NodeManagerError::NotProvisioned new variant. create_node and
    ensure_default_identity now use identity::load and return
    NotProvisioned when the tree is empty. create_node keeps a single
    escape hatch — node_config.seed_identity set via
    with_seed_identity — so existing test fixtures keep working without
    changes; tests mirror the bootstrap flow exactly.
  • HTTP 503 wired through utils/http_errors::node_not_provisioned_response
    with the canonical body {error: "node_not_provisioned", next: "POST /api/setup/bootstrap"}.
    Plumbed into routes::common::get_node_for_user (used by every require_node
    caller via the macro) and routes::config::auto_identity. Body shape
    matches the existing nodeProvisioning.ts UI interceptor exactly, so the
    frontend's folddb:node_not_provisioned event will fire as designed.

Audit notes

get_node callers and how 503 propagates:

Site Behavior after change
routes/common.rs:60 (require_node helper) 503 node_not_provisioned with canonical body
routes/setup.rs:417 (bootstrap) identity already saved upstream — never trips
routes/admin.rs:210, 310 (spawn jobs) error string surfaces via handle.fail(); not HTTP-direct
routes/config.rs:325 (get_database_status) identity::load pre-check still gates; behavior unchanged. OUT OF SCOPE per task prompt.

ensure_default_identity callers:

Site Behavior
routes/config.rs:77 (auto_identity) 503 node_not_provisioned
handlers/auth.rs:362 (signed_register) bubbles "Node is not provisioned. POST /api/setup/bootstrap to provision." string upward; route returns 5xx with informative message
handlers/auth.rs:927 (finalize_restore) identity already saved 4 lines above the call — never trips

Test plan

  • cargo clippy --workspace --all-targets -- -D warnings -A dead_code — clean (-A dead_code suppresses the macOS-only apple_import warning per MEMORY.md)
  • cargo test --lib — 977/977 pass, including new provision_only_called_from_setup_route, load_does_not_mint_on_empty_pool, get_node_returns_not_provisioned_when_pool_empty_and_no_seed, auto_identity_returns_503_when_not_provisioned
  • cargo test --bins — all bin suites pass
  • npm test (frontend) — 732/732 pass, including existing nodeProvisioning.test.ts that asserts the 503 contract
  • CI green

…me callers through identity::load + 503

Bootstrap-collapse step 2. PR #903 made POST /api/setup/bootstrap the
canonical first-launch endpoint, but NodeManager::create_node and
ensure_default_identity still called load_or_generate, so a stale
node_config.json could mint a ghost identity behind the user's back and
orphan every previously-ingested record.

- identity::load_or_generate -> identity::provision, documented
  bootstrap-only. A regression test enforces that only
  src/server/routes/setup.rs may call it.
- NodeManagerError::NotProvisioned variant; create_node and
  ensure_default_identity now call identity::load and surface
  NotProvisioned when the tree is empty (test seed_identity is the
  only escape hatch in create_node).
- HTTP layer maps NotProvisioned to the canonical 503 body
  {error: "node_not_provisioned", next: "POST /api/setup/bootstrap"}
  via utils/http_errors::node_not_provisioned_response, wired into
  routes::common::get_node_for_user (the require_node helper used by
  every handler) and routes::config::auto_identity. Matches the
  body shape the existing nodeProvisioning.ts UI interceptor watches for.
- Tests: provision_only_called_from_setup_route grep enforcer,
  load_does_not_mint_on_empty_pool, NodeManager NotProvisioned probe,
  auto_identity 503 response shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant