idx-cli/scripts/build-ownership-snapshot.sh
hermes 6abc4a0712 fix(ownership): one release order everywhere; keep the old search API
From the Codex re-gate of the 0.3.3 fixes:
- `changes` broke ties between same-date releases by row id, but the
  ticker, entity, and graph queries and the snapshot builder did not, so
  two files imported in the same second could resolve differently per
  query. Order by as_of_date, imported_at, then id everywhere.
- search::fts_search and search::rebuild_fts were public in a published
  crate; keep them as deprecated wrappers.
- Invalid --source and --by are INVALIDINPUT, like other argument errors.
- The prefix-ranking test could not tell prefix from exact-alias ranking;
  add one where only prefix vs substring differs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
2026-10-17 05:07:41 +00:00

136 lines
3.9 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: scripts/build-ownership-snapshot.sh --db <ownership.db> --output-dir <dir> [--base-url <url>]
Create a publishable ownership SQLite snapshot plus a manifest JSON file.
Options:
--db <path> Source ownership SQLite database
--output-dir <dir> Directory to write the copied snapshot and manifest
--base-url <url> Optional URL prefix to use for snapshot.download_url
--help Show this help
EOF
}
sha256_file() {
local path="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$path" | awk '{print $1}'
return 0
fi
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$path" | awk '{print $1}'
return 0
fi
echo "sha256sum/shasum not found in PATH" >&2
exit 1
}
DB_PATH=""
OUTPUT_DIR=""
BASE_URL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--db)
DB_PATH="${2:-}"
shift 2
;;
--output-dir)
OUTPUT_DIR="${2:-}"
shift 2
;;
--base-url)
BASE_URL="${2:-}"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
done
if [[ -z "$DB_PATH" || -z "$OUTPUT_DIR" ]]; then
echo "--db and --output-dir are required" >&2
usage >&2
exit 2
fi
if [[ ! -f "$DB_PATH" ]]; then
echo "ownership database not found: $DB_PATH" >&2
exit 1
fi
if ! command -v sqlite3 >/dev/null 2>&1; then
echo "sqlite3 is required to build ownership snapshots" >&2
exit 1
fi
mkdir -p "$OUTPUT_DIR"
LATEST_AS_OF="$(sqlite3 "$DB_PATH" "SELECT as_of_date FROM ownership_releases ORDER BY as_of_date DESC, imported_at DESC, id DESC LIMIT 1;")"
LATEST_RELEASE_SHA="$(sqlite3 "$DB_PATH" "SELECT sha256 FROM ownership_releases ORDER BY as_of_date DESC, imported_at DESC, id DESC LIMIT 1;")"
LATEST_ROW_COUNT="$(sqlite3 "$DB_PATH" "SELECT row_count FROM ownership_releases ORDER BY as_of_date DESC, imported_at DESC, id DESC LIMIT 1;")"
RELEASE_COUNT="$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM ownership_releases;")"
TICKER_COUNT="$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM tickers;")"
if [[ -z "$LATEST_AS_OF" || -z "$LATEST_RELEASE_SHA" ]]; then
echo "ownership database has no imported releases: $DB_PATH" >&2
exit 1
fi
MANIFEST_PATH="$OUTPUT_DIR/ownership-snapshot-manifest.json"
TMP_ARTIFACT_PATH="$OUTPUT_DIR/.ownership-snapshot-${LATEST_AS_OF}.sqlite.tmp.$$"
# Remove a partial copy if the script fails before the atomic rename below.
trap 'rm -f "$TMP_ARTIFACT_PATH"' EXIT
cp "$DB_PATH" "$TMP_ARTIFACT_PATH"
# Immutable, content-addressed name. The publisher relies on this to upload and
# verify the SQLite asset before it publishes the manifest that references it.
SQLITE_SHA256="$(sha256_file "$TMP_ARTIFACT_PATH")"
ARTIFACT_NAME="ownership-snapshot-${LATEST_AS_OF}-${SQLITE_SHA256}.sqlite"
ARTIFACT_PATH="$OUTPUT_DIR/$ARTIFACT_NAME"
mv "$TMP_ARTIFACT_PATH" "$ARTIFACT_PATH"
SIZE_BYTES="$(wc -c < "$ARTIFACT_PATH" | tr -d ' ')"
GENERATED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
if [[ -n "$BASE_URL" ]]; then
DOWNLOAD_URL="${BASE_URL%/}/$ARTIFACT_NAME"
else
DOWNLOAD_URL="$ARTIFACT_PATH"
fi
cat > "$MANIFEST_PATH" <<EOF
{
"schema_version": 1,
"generated_at": "$GENERATED_AT",
"snapshot": {
"kind": "sqlite",
"compression": "none",
"version": "$LATEST_AS_OF",
"download_url": "$DOWNLOAD_URL",
"sqlite_sha256": "$SQLITE_SHA256",
"size_bytes": $SIZE_BYTES,
"release_count": $RELEASE_COUNT,
"latest_as_of_date": "$LATEST_AS_OF",
"latest_release_sha256": "$LATEST_RELEASE_SHA",
"latest_row_count": $LATEST_ROW_COUNT,
"ticker_count": $TICKER_COUNT
}
}
EOF
printf 'Wrote snapshot artifact: %s\n' "$ARTIFACT_PATH"
printf 'Wrote snapshot manifest: %s\n' "$MANIFEST_PATH"