| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…-metadata (SA-teardown-A) dataset-separation SA-teardown, part A. `levels sync-metadata` already applies the CSV columns by stable id with delete-safety (#146); reach.geom/reach.gradient_profile are EXCLUDED_COLUMNS, applied only from reaches.json/reaches-gradient.json. So make import_metadata.py a **sidecar-only** applier and standardize CSV loads on sync-metadata: - import_metadata.py: drop the full-CSV upsert path (and the `metadata_csv` import); it now applies only the geometry sidecars. No flags = both; --geom-only / --gradient-only = one. This removes the parallel-to-sync-metadata CSV channel that skipped #146's delete-safety (the #148 review's "optional hardening" — the unsafe channel is gone, not just gated). It stays the sanctioned sidecar applier (no refuse_configured_db), per the safety.py enumeration; deploy.sh 3.25/3.26 (--geom-only/--gradient-only) are unchanged, and 3.1 already does the CSV via sync-metadata. - Fresh-load / recovery / onboarding runbooks now run init-db --no-seed → sync-metadata → import_metadata (sidecars) → pipeline: CLAUDE.md, README.md, CONTRIBUTING.md, deploy/SETUP.md (§4 + the §-755 block), and docs/migrations.md's recovery runbook (incl. the --no-seed-rationale paragraph: the collision + FK semantics are sync-metadata's now, not import's). - Docstring sweep: safety.py (import_metadata has no full-CSV mode) and metadata_csv.py (its sole upsert caller is now sync-metadata). - Tests: the full-CSV round-trip tests now apply the CSV half via sync_metadata (new `_sync_csvs` helper writes the minimal contract); the geom/gradient sidecar tests are unchanged. Renamed the two that were import-CSV-specific (test_csv_apply_preserves_geom_absent_from_snapshot, test_resync_idempotent_across_pk_shapes). Verified on a copy of the live DB: init-db --no-seed → sync-metadata → import_metadata reproduces prod exactly (328 sources / 231 gauges / 432 reaches incl. all 432 geoms + 432 gradients) and builds. No schema change; no kayak_data change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Adversarial review findings:
What I verified:
|
Sorry, something went wrong.
Adversarial review — PR #149 (SA-teardown-A: import_metadata sidecar-only; CSV loads via sync-metadata)Reviewed on the live host. This implements the #148 review's "optional hardening" — removing import_metadata.py's full-CSV upsert (the parallel-to-sync-metadata channel that skipped #146's delete-safety) entirely, leaving it the sidecar-only applier. I traced the flag logic, audited every import_metadata.py invocation in the post-PR tree for the one real regression risk (a bare call that silently skips CSVs), and checked the test rework. Verdict: ready to merge. The code change is small and correct, the runtime behavior I can verify locally is unchanged, and all runbooks/deploy paths are consistent. One claim rests on the author's reproduction rather than mine (see Findings); it's low-risk for deploy and I note where I'd keep it as an acceptance step. What I verified
Findings1. [Low / informational] The "sync-metadata is a complete CSV load path from empty" claim rests on the author's real-DB reproduction, not mine. I confirmed the live DB has the target rows, but I did not independently run the init-db --no-seed → sync-metadata empty→full load (I started to and stopped). The substantive behavioral difference from the removed path is FK enforcement: the old import_metadata ran foreign_keys=OFF (tolerant bulk load, orphan-tolerant); sync-metadata runs foreign_keys=ON. An empty→full load under FK-ON requires parent-before-child insert ordering (or no orphan FKs in the CSVs). The PR's stated reproduction (432 reaches + geoms loaded cleanly) is the evidence this is handled. Distinction that lowers risk: the deploy path (deploy.sh 3.1) is an incremental sync against the populated live DB — already proven across the #146/#147/#148 deploys — not a fresh load. The empty→full path matters only for disaster recovery and onboarding. Recommend keeping that empty→full reproduction as a documented acceptance step for this slice (it's the load-bearing guarantee for the recovery runbooks this PR rewrites). 2. [Low] Fresh-load runbooks assume a status: publishable dataset. sync-metadata refuses a status: scaffold dataset unless --allow-scaffold (exit 1). The rewritten runbooks run a plain levels sync-metadata, which is correct for the real (publishable) kayak_data but would dead-end an installer who cloned a scaffold dataset with a bare "refused" exit. Pre-existing dataset behavior, not introduced here — worth at most a one-line note in the recovery runbook. (No action required if all real datasets are publishable.) 3. [Nit] No CHANGELOG.md entry for a documented behavior change (import_metadata no longer loads CSVs). The existing CHANGELOG lines describing its upsert are now historically-superseded; a one-line entry would help an operator who reads CHANGELOG before a recovery. Scope / deployNo schema change, no migration, no kayak_data change. Same low-risk class as #148: a code-only pull where the runtime delta is confined to a dev/deploy maintenance script (import_metadata.py) — not in the hourly pipeline path. The doc sweep is the bulk of the diff and is internally consistent. |
Sorry, something went wrong.
Follow-up: Finding #1 independently verified (empty→full load)I reproduced the empty→full load myself on a scratch DB from the real kayak_data dataset (never touching the live DB), using this PR's sidecar-only import_metadata.py: levels init-db --no-seed → levels sync-metadata → import_metadata.py Result — byte-for-byte reproduces prod:
So Finding #1 is resolved — sync-metadata is a complete CSV load path from empty, independently confirmed, not just author-attested. No remaining concerns; the residuals (#2 scaffold-status assumption, #3 CHANGELOG) stay informational. Verdict unchanged: ready to merge. |
Sorry, something went wrong.
…n setup runbooks (review) Address the two P2s (and the Low/Nit notes) from the #149 review. [P2] import_metadata.py reported success while applying ZERO sidecar rows. After A removed the CSV-load path, a no-flag run against an empty/wrong DB (the "ran before `levels sync-metadata`" mistake) applied 0/432 geoms + 0/432 gradients and exited 0 — invisible under `set -e`. Now `_apply_geom`/`_apply_gradient` return the count of snapshot ids that matched no reach row, and main() rolls back + exits non-zero when any are unmatched, with `--allow-missing-reaches` to opt into a deliberate partial apply. Verified: empty DB no-flag → exit 1, nothing applied (rolled back); --allow-missing-reaches → exit 0; full DB (after sync-metadata) → exit 0. Deploy 3.25/3.26 (--geom-only/--gradient-only against the full prod DB, after the 3.1 sync) all match, so this never false-positives on deploy. New test: a sidecar id with no reach row fails loud + rolls back; the flag allows the partial. [P2] Two setup runbooks ran `levels sync-metadata` without cloning kayak_data / setting DATASET_DIR, so they dead-ended at "csv dir does not exist: …/data/db": CONTRIBUTING.md (standalone dev quick-start) and deploy/SETUP.md's self-contained condensed install recap (its .env omitted DATASET_DIR and it cloned no metadata repo). Both now clone kayak_data + set DATASET_DIR before the load. (Pre-existing — import_metadata needed DATASET_DIR too — surfaced because A touches these blocks.) [Low] Note in the recovery runbook that sync-metadata refuses a `status: scaffold` dataset (--allow-scaffold to override; the real kayak_data is publishable). [Nit] CHANGELOG entry for the import_metadata sidecar-only behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Both P2s fixed in 49e78c4 (plus the Low/Nit notes). Thanks for the thorough probing — and for independently confirming the empty→full load reproduces prod byte-for-byte. [P2] import_metadata.py reported success on a zero-row apply. Right — after removing the CSV path, a no-flag run against an empty/wrong DB (the "ran before sync-metadata" mistake) applied 0/432 + 0/432 and exited 0. Now _apply_geom/_apply_gradient return the count of snapshot ids that matched no reach row, and main() rolls back + exits non-zero when any are unmatched — with --allow-missing-reaches to opt into a deliberate partial apply. Verified your exact repro:
Deploy 3.25/3.26 (--geom-only/--gradient-only against the full prod DB, after the 3.1 sync inserts any new reaches; validate-dataset's reach/snapshot-integrity check enforces reaches.json ids ⊆ reach.csv ids) all match, so this never false-positives on deploy. New test test_import_fails_loud_on_unmatched_sidecar_reach covers fail-loud + rollback + the flag. [P2] Setup runbooks ran sync-metadata without DATASET_DIR. Fixed: CONTRIBUTING.md and deploy/SETUP.md's condensed install recap now clone kayak_data + set DATASET_DIR before the load (the recap's .env was missing it). (Pre-existing — import_metadata needed DATASET_DIR too — but A touches these blocks, so swept now.) [Low] recovery runbook now notes sync-metadata refuses a status: scaffold dataset (--allow-scaffold to override; real kayak_data is publishable). [Nit] added a CHANGELOG entry for the import_metadata behavior change. Full gate green: ruff/format (rc 0), mypy, pytest -m "not slow" = 1403, wheel-smoke, git diff --check clean. Still not merging — yours. |
Sorry, something went wrong.
|
Adversarial rereview of 49e78c4:
The two previous P2s look resolved:
Verification run:
|
Sorry, something went wrong.
…locks (review) Address the #149 re-review P3. The condensed local-dev install recap (step 6) and the §4 "apply geometry by hand" snippet ran `python scripts/import_metadata.py` with a relative path while every other command in those blocks uses absolute paths (`/home/pat/.venv/bin/levels`, …) — so they read as self-contained but fail from outside /home/pat/kayak ("can't open file '.../scripts/import_metadata.py'"). Use the absolute `/home/pat/kayak/scripts/import_metadata.py` so both blocks are copy-paste-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Fixed the P3 in d5228ef: both deploy/SETUP.md blocks (the condensed local-dev recap step 6 and the §4 "apply geometry by hand" snippet) now use the absolute /home/pat/kayak/scripts/import_metadata.py, matching the absolute venv/levels paths around them — copy-paste-safe from any cwd. (Swept both occurrences, not just the recap.) Thanks for re-confirming the two P2s resolved + the idempotent re-run. Docs-only; git diff --check clean. Still not merging — yours. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
What
Dataset-separation SA-teardown, part A (the load-path slice). Makes scripts/import_metadata.py a sidecar-only applier and routes all CSV metadata loads through levels sync-metadata.
Why
levels sync-metadata already applies the CSV columns by stable id with delete-safety (#146). reach.geom/reach.gradient_profile are EXCLUDED_COLUMNS — applied only from reaches.json/reaches-gradient.json. So import_metadata.py's full-CSV upsert was a redundant parallel-to-sync-metadata channel that skipped #146's delete-safety (the #148 review's "optional hardening"). This removes that channel entirely (not just gates it) and keeps the one thing only import_metadata can do: apply the geometry sidecars.
This is the master-plan's "import_metadata → wrapper / standardize on sync-metadata", reconciled with the reality that sync-metadata can't apply the geom/gradient sidecars.
Change
Verification
Scope / next
No schema change; no kayak_data change. Next: SA-teardown-B removes the snapshot script + systemd units + hc_metadata_snapshot config + export_metadata→levels recover-metadata; then SA-teardown-C (operational) disables the prod timer and enables kayak_data branch protection.
🤖 Generated with Claude Code