Contracts

ble001-guardrail.md

Contract: Auth/Storage BLE001 Guardrail

Scope

Guard scoped paths:

  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/auth/
  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/cli/commands/auth.py
  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/cli/commands/_auth_doctor.py
  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/cli/commands/_auth_login.py
  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/cli/commands/_auth_logout.py
  • /Users/robert/spec-kitty-dev/spec-kitty-20260505-085847-6BpmsS/spec-kitty/src/specify_cli/cli/commands/_auth_status.py

Passing Suppression

except Exception as exc:  # noqa: BLE001 - specific reason that names the safe boundary

The reason must explain why the exception is being translated, logged, downgraded, or ignored.

Failing Suppressions

except Exception:  # noqa: BLE001
except Exception:  # noqa: BLE001 - broad catch
except Exception:  # noqa: BLE001 - ignore

Output Contract

On failure, the guard reports:

  • File path.
  • Line number.
  • The problematic suppression text.
  • A remediation hint to add a specific safety reason or narrow the exception type.

Acceptance Fixtures

  • One auth/storage sample with a justified suppression passes.
  • One auth/storage sample with no reason fails.
  • One auth/storage sample with a generic reason fails.
  • Unrelated non-auth paths are outside this mission's guard scope unless the existing review command already audits them separately.

diagnostic-classification.md

Contract: Hosted Sync And Tracker Diagnostic Classification

Scope

Applies to CLI command paths that require hosted sync, tracker, Teamspace, or direct-ingress state.

Categories

ConditionCategoryUser guidance
No active local auth session and hosted state is requiredunauthenticatedRun spec-kitty auth login
Local session exists but hosted access is denied because Private Teamspace is missingdirect_ingress_missing_private_team or existing direct-ingress peerExplain Private Teamspace requirement; do not call it server failure
Hosted service rejects access for authorization or permission reasonunauthorizedExplain access/permission issue without token details
Timeout, connection failure, or temporary transport issueretryable_transportRetry later or check network
True 5xx or unexpected hosted server failureserver_errorRetry later or check server status

Invariants

  • Missing Private Teamspace direct ingress never maps to server_error.
  • Logged-out Teamspace/tracker-bound commands include spec-kitty auth login.
  • User-facing output and machine-facing classification agree on the broad category.
  • Raw tokens, lookup hashes, peppers, family IDs, and audit metadata are never displayed.

Regression Fixtures

  • Logged-out Teamspace-bound repository.
  • Tracker-bound repository with no active auth session.
  • Direct-ingress 403/missing Private Teamspace.
  • Retryable transport failure.
  • True hosted 5xx.

Non-Goals

  • Changing SaaS route contracts.
  • Changing tracker package contracts unless investigation proves CLI cannot classify correctly without that package change.

refresh-lock-hermeticity.md

Contract: Refresh-Lock Hermeticity

Scope

Applies to tests/auth/concurrency/test_machine_refresh_lock.py and related fixtures that validate local refresh-lock behavior.

Required Behavior

developer shell sets SPEC_KITTY_SAAS_URL
  |
  v
run auth refresh-lock concurrency test
  |
  +-- fake session already has Private Teamspace OR membership hook is patched out
  |
  +-- no real hosted /api/v1/me request
  |
  v
test completes within 60 seconds

Assertions

  • With SPEC_KITTY_SAAS_URL=https://spec-kitty-dev.fly.dev, the focused concurrency suite makes zero real hosted membership requests.
  • With SPEC_KITTY_SAAS_URL unset, the same focused suite still passes.
  • Tests that intentionally contact hosted SaaS are named, marked, or invoked as dev smoke tests and are not part of default hermetic concurrency coverage.

Allowed Fix Shapes

  • Include a Private Teamspace in refreshed fake sessions.
  • Monkeypatch _apply_post_refresh_membership_hook() in concurrency fixtures where membership rehydrate is out of scope.
  • Clear hosted auth environment only inside the test fixture and assert the no-network invariant.

Disallowed Fix Shapes

  • Depend on https://spec-kitty-dev.fly.dev in the default concurrency suite.
  • Remove production post-refresh membership rehydrate behavior to make a test pass.
  • Treat this diagnosis as proof that the refresh-lock algorithm is broken without a separate failing fixture.

session-hot-path.md

Contract: Local Session Hot Path

Scope

Applies to many short-lived local CLI processes that need hosted auth/session state.

Authority Model

encrypted file-only session storage
  |
  | authoritative read/write
  v
derived local handoff/cache
  |
  | fast-path read when fresh and valid
  v
short-lived CLI process

The derived handoff/cache never becomes the durable root of trust.

Required Behavior

  • If handoff state is fresh and matches durable session identity, a process may use it to avoid repeated expensive local session work.
  • If handoff state is missing, stale, unreadable, mismatched, or invalid, the process falls back to encrypted durable storage.
  • Refresh remains coordinated across processes by the existing machine-wide lock semantics or an equivalent proven boundary.
  • Benign refresh replay and lock contention are handled as coordination outcomes, not fatal user errors.

Security Rules

  • No Keychain, keyring, Secret Service, or OS credential-manager dependency.
  • No raw token material in user output, logs, or diagnostics.
  • No raw token material in any plaintext handoff artifact unless a later reviewed design proves equivalent local protection; default plan assumes no plaintext token cache.
  • Handoff/cache invalidation must be tied to durable session change.

Tests

  • Many short-lived processes sharing a valid session avoid repeated expensive work.
  • Concurrent refresh peers converge on a consistent session result.
  • Stale handoff falls back to encrypted storage.
  • Packaging checks still prove no forbidden credential-manager dependency.