Files
Vijay Janapa Reddi cbdb566381 feat(vault): Phase-1 migration contract fully closed in-repo
v2.3 \u2192 v2.4. ARCHITECTURE.md header + Appendix reflect the completed
migration.

WHAT CLOSED (\u00a711.1 contract):
  1. `vault build --legacy-json` regenerates the site's
     interviews/staffml/src/data/corpus.json from YAML. 9,199 published
     questions, site-compatible shape (chain_positions back to 0-indexed
     dict form, bloom_level derived from zone, competency_area aliased
     from topic, scope aliased from track). Deterministic via sort_keys +
     id-sort.
  2. Pre-commit hook INSTALLED via worktree-aware Makefile target
     (`make -C interviews/vault-cli hooks`). Symlink points at
     pre_commit_corpus_guard.py. Tested end-to-end: direct edit to
     vault/corpus.json triggers exit-1 with §11.1 reference.
  3. CI equivalence check added to .github/workflows/vault-ci.yml:
     regenerates corpus.json from YAML, diffs against committed. Fails
     PR on drift with actionable error message.
  4. Legacy generators demoted with DEPRECATED headers:
     - interviews/paper/scripts/analyze_corpus.py \u2192 vault export-paper
     - interviews/staffml/scripts/sync-vault.py \u2192 vault build --legacy-json
     - interviews/staffml/scripts/generate-manifest.py \u2192 vault publish
     - interviews/vault/scripts/export_to_staffml.py \u2192 vault build --legacy-json
  5. New DEPRECATED.md files at interviews/vault/scripts/ and
     interviews/staffml/scripts/ map every legacy script to its
     replacement. Both directories keep the old scripts for git-history
     legibility and archaeology; new contributors see the vault CLI first.
  6. ARCHITECTURE.md \u00a7Appendix rewritten as current-state table instead
     of aspirational "gone. replaced by..." entries.

NEW TESTS (interviews/vault-cli/tests/test_legacy_export.py \u2014 +4):
  - test_legacy_shape_matches_site_interface: every field corpus.ts
    declares is present in regenerated JSON.
  - test_chain_positions_legacy_shape: 1-indexed new schema \u2192
    0-indexed legacy dict form.
  - test_emitter_deterministic: byte-stable across reversed input order
    (required for CI diff-check).
  - test_competency_area_aliases_topic: legacy alias fields populated
    correctly.

FULL MATRIX GREEN:
  pytest:  38/38 passed in 0.19s (34 + 4 legacy-export)
  ruff:    All checks passed
  hook:    exit 0 on clean diff / exit 1 on corpus.json direct edit
  e2e:     vault build --legacy-json regenerates a bit-identical corpus.json
           vs the committed one; CI check wired to catch drift

WHAT'S LEFT (deploy-gated, \u00a720.5 #1, #5, #6 partial, #8, #9):
  - Production serves from D1: requires Phase-3 wrangler d1 create + deploy
  - Manual QA per CUTOVER_QA.md: requires live staging
  - Zero data loss D1-side verification: requires live D1
  - 48h monitoring: requires production traffic

These are intrinsically user-action; the YAML-side migration is done.
2026-04-16 14:57:24 -04:00

50 lines
1.5 KiB
Makefile

# Makefile for vault-cli — convenience wrappers over CLI and tests (B.2).
PKG_DIR := $(shell pwd)
# `git rev-parse --git-path hooks` works correctly in both regular clones
# and worktrees (where .git is a file pointing at the main repo's hooks dir).
HOOKS_DIR := $(shell git rev-parse --git-path hooks 2>/dev/null)
HOOK_SRC := $(PKG_DIR)/scripts/pre_commit_corpus_guard.py
HOOK_DST := $(HOOKS_DIR)/pre-commit
.PHONY: install test lint hooks hooks-uninstall help
help:
@echo "Targets:"
@echo " install pip install -e with dev extras"
@echo " test run pytest"
@echo " lint ruff check (mypy is non-blocking at Phase 0)"
@echo " hooks symlink pre-commit-corpus-guard into .git/hooks/"
@echo " hooks-uninstall remove the hook symlink"
install:
pip install -e ".[dev]"
test:
pytest tests/ -v
lint:
ruff check src tests
@mypy src || echo "[mypy] strict is non-blocking at Phase 0"
hooks:
@if [ -z "$(HOOKS_DIR)" ]; then \
echo "could not resolve git hooks dir; run make from a git checkout"; exit 1; \
fi
@mkdir -p "$(HOOKS_DIR)"
@if [ -e "$(HOOK_DST)" ] && [ ! -L "$(HOOK_DST)" ]; then \
echo "refusing to overwrite non-symlink at $(HOOK_DST); remove it first"; \
exit 1; \
fi
@ln -sf "$(HOOK_SRC)" "$(HOOK_DST)"
@chmod +x "$(HOOK_SRC)"
@echo "installed hook: $(HOOK_DST) -> $(HOOK_SRC)"
hooks-uninstall:
@if [ -L "$(HOOK_DST)" ]; then \
rm "$(HOOK_DST)"; \
echo "removed $(HOOK_DST)"; \
else \
echo "no symlink at $(HOOK_DST)"; \
fi