Files
SeedPass/scripts/ci_prepush.sh
T
thePR0M3TH3ANandClaude Opus 5 72b3e52f50 Delete 38 assertions that were never necessary, and the bug one was hiding
I expected the 35 remaining findings to need a VaultIndex remodel. They did
not. `vaultIndexSchema` and every entry schema are `.loose()`, which already
gives both types an index signature — so `index["_system"]`, `entry["label"]`
and assignment to `Record<string, unknown>` all compile with no cast at all. I
checked before rewriting anything, and the answer was that 38 of the 44 were
simply redundant, copied from each other rather than needed.

That is the linter's real value here: it did not find a design flaw, it made
me test an assumption I would otherwise have acted on. The remodel would have
been work done to satisfy a belief that was false.

Removing them let the compiler see three things the casts had been hiding:

- `nextTotpIndex` filtered on `type === "totp" || kind === "totp"`, and TS
  reported the second half as unreachable. It is: withKind() populates kind
  from type at parse time and the union is discriminated on kind, so the
  fallback could never fire. Now filters on the discriminant alone.
- `ensureIndex0Payload` always ran normalizeIndex0 and then returned `Dict`,
  throwing the guarantee away, so all three callers asserted it back with
  `as unknown as Index0`. It now returns an `Index0Payload` that carries what
  the function established, built in that shape rather than asserted into it,
  and the type propagates through compactIndex0Payload and
  rebuildCanonicalViewsPayload.
- `sign()` in recoveryDrills declared a DrillRecord parameter it never used
  as one — it HMACs a canonical serialization — which forced the verifier to
  assert a shape it had not established while checking a signature.

Also `rebuildIndex0Checkpoints` typed to the one field it reads, and
console.ts asking `"isTTY" in this.out` rather than asserting a shape onto a
WritableStream.

One assertion remains, in entrySchema, and it is structural rather than
evidential: z.preprocess types its output from an inner union deliberately
wider than Entry, and no zod spelling expresses "parses to a superset, hands
back the narrow type". Disabled inline with that written down.

44 -> 0. The lint step is now in ci_prepush.sh, and the gate runs green in
44.5 seconds. 689 tests still pass.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01Vtx94nXDmNgXEeThUZP4QN
2026-08-20 13:40:42 -04:00

73 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# The gate that runs before every push. Target: well under a minute.
#
# WHAT IS IN HERE AND WHY THAT LIST
#
# The budget is the design constraint, not an afterthought. A hook that takes
# minutes becomes `git push --no-verify` within a week, at which point it is a
# ceremonial control that everyone believes in and nobody runs. So this holds
# only checks that are cheap AND catch things CI would otherwise catch late.
#
# Measured on this machine, 2026-08-20:
#
# preflight 2.6s
# poetry check --lock 0.6s
# black --check 2.5s
# oxlint 0.9s
# tsc --noEmit (workspace) 7.3s
# pytest determinism subset 5.4s
# vitest core (node) 24.0s
# -----
# ~44s
#
# What is deliberately NOT here:
#
# vitest cli 176.3s <- alone, three times the budget
# pytest (full) ~350s
# cross-impl, fuzz, packaging smoke
#
# Those live in ci_parity.sh, which is what you run before calling a branch
# ready rather than before every push. The cli suite is slow for a good
# reason -- it spawns real daemons, real sockets and real subprocesses rather
# than mocking them -- and that is worth keeping, not worth waiting on twenty
# times a day.
#
# EVERY TOOL IS INVOKED THROUGH THE REPOSITORY ENVIRONMENT. `poetry run ...`
# and `pnpm -C js ...`, never a bare `black` or `vitest` off PATH. That rule is
# the whole reason preflight runs first: a bare tool name is how a local gate
# ends up passing while CI fails.
set -euo pipefail
cd "$(dirname "$0")/.."
step() { printf "\n\033[1m==> %s\033[0m\n" "$1"; }
step "preflight: does this machine agree with the lockfiles?"
python3 scripts/ci_preflight.py
step "python: lockfile consistency"
poetry check --lock
step "python: formatting (the pinned black, not whatever is on PATH)"
poetry run black --check .
step "javascript: lint"
pnpm -C js lint
step "javascript: typecheck"
pnpm -C js typecheck
step "javascript: core tests"
pnpm -C js --filter @seedpass/core test:node
step "python: deterministic artifact regression"
poetry run pytest -q src/tests/test_deterministic_artifact_regression.py
if command -v actionlint >/dev/null 2>&1; then
step "workflows: actionlint"
actionlint
else
printf "\n\033[2m(actionlint not installed — skipping workflow lint)\033[0m\n"
fi
printf "\n\033[32mci:prepush passed.\033[0m Run ./scripts/ci_parity.sh before calling a branch ready.\n"