From af9412b988fa5748ab7341b9f4f2f166dd54a5ab Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 6 Jun 2026 12:49:42 +0200 Subject: [PATCH] chore(config): wire pql hooks + Makefile decision targets (pql migration phase 4) Folds pql's planning logic into the version-controlled .config/hooks/* (pql's own .pql/hooks installer is dead under core.hooksPath=.config/hooks): - pre-commit: + `pql decisions validate` (decision-ID/format gate, supersedes the never-built check-decision-ids TODO) and `pql plan export --stage` (flush ticket mutations to the git-tracked changelog and stage them into the commit). Both guarded by `command -v pql`; export is a clean no-op when nothing changed. - post-merge: `pql plan import` + `pql decisions sync` (replay incoming changelog, re-sync markdown decisions). - post-checkout (branch only): `pql plan rebuild` + `decisions sync`. - post-rewrite (rebase/amend): `pql plan rebuild`. - install-hooks chmods the three new hooks. Makefile decision targets repointed to pql: decisions-sync -> `pql decisions sync`, decisions-active -> `pql decisions list --type confirmed`, new decisions-validate -> `pql decisions validate`. Dropped the SQLite-query conveniences (coverage/orphan/ orphan-tickets); per-decision coverage is `pql decisions show --with-tickets`. db-backup/db-install and SR_DB_PATH are intentionally kept until Phase 6 so the legacy SQLite store stays intact as the migration rollback path. Co-Authored-By: Claude Opus 4.8 (1M context) --- .config/hooks/post-checkout | 11 +++++++++++ .config/hooks/post-merge | 11 +++++++++++ .config/hooks/post-rewrite | 11 +++++++++++ .config/hooks/pre-commit | 20 ++++++++++++++++++-- Makefile | 34 +++++++++++++++------------------- 5 files changed, 66 insertions(+), 21 deletions(-) create mode 100755 .config/hooks/post-checkout create mode 100755 .config/hooks/post-merge create mode 100755 .config/hooks/post-rewrite diff --git a/.config/hooks/post-checkout b/.config/hooks/post-checkout new file mode 100755 index 000000000..179beb252 --- /dev/null +++ b/.config/hooks/post-checkout @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Post-checkout hook. Folds in pql's planning logic (its .pql/hooks installer is +# dead under core.hooksPath=.config/hooks). +# +# On a branch checkout (third arg == 1), rebuild pql.db from the changelog so the +# local planning cache reflects the new branch's state. File-level checkouts +# ($3 == 0) are skipped. Args: . +if [ "${3:-0}" = "1" ] && command -v pql >/dev/null 2>&1; then + pql plan rebuild >/dev/null 2>&1 || true + pql decisions sync >/dev/null 2>&1 || true +fi diff --git a/.config/hooks/post-merge b/.config/hooks/post-merge new file mode 100755 index 000000000..f2602044f --- /dev/null +++ b/.config/hooks/post-merge @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Post-merge hook (also fires after `git pull`). Folds in pql's planning logic; +# pql's own .pql/hooks installer is dead under core.hooksPath=.config/hooks. +# +# Replays any changelog files the merge brought in (idempotent, LWW — D-16) and +# re-syncs decisions from governance/*.md so the markdown-sourced half stays in +# step. Both are no-ops when nothing changed. +if command -v pql >/dev/null 2>&1; then + pql plan import >/dev/null 2>&1 || true + pql decisions sync >/dev/null 2>&1 || true +fi diff --git a/.config/hooks/post-rewrite b/.config/hooks/post-rewrite new file mode 100755 index 000000000..d39a7780e --- /dev/null +++ b/.config/hooks/post-rewrite @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# Post-rewrite hook (fires after `git rebase` / `git commit --amend`). Folds in +# pql's planning logic; its .pql/hooks installer is dead under +# core.hooksPath=.config/hooks. +# +# Rewriting history can reorder or drop changelog edits, so a full rebuild from +# the changelog is the safe, deterministic refresh (incremental replay would miss +# removals — D-16). +if command -v pql >/dev/null 2>&1; then + pql plan rebuild >/dev/null 2>&1 || true +fi diff --git a/.config/hooks/pre-commit b/.config/hooks/pre-commit index a9012e26c..c5564d17a 100755 --- a/.config/hooks/pre-commit +++ b/.config/hooks/pre-commit @@ -21,8 +21,24 @@ run_check() { # --- Checks --- run_check "tooling/check-fact-ids" "fact_id validation" -# TODO: uncomment when tooling/check-decision-ids is implemented -# run_check "tooling/check-decision-ids" "decision ID duplication" + +# --- pql: decision integrity + durable planning changelog --- +# Replaces the old SQLite decisions-sync hook. Decisions are markdown-sourced (D-8): +# `decisions validate` is the decision-ID/format gate (supersedes the never-built +# check-decision-ids), and `plan export --stage` flushes any ticket mutations to the +# git-tracked .pql/changelog/ and stages them so planning state lands in this commit. +# pql installs its own hooks into .pql/hooks, which git ignores under +# core.hooksPath=.config/hooks — so the logic is folded in here by hand instead. +if command -v pql >/dev/null 2>&1; then + if ! pql decisions validate >/dev/null; then + echo "pre-commit: pql decisions validate failed — malformed decision record(s)." + ERRORS=$((ERRORS + 1)) + fi + pql plan export --stage >/dev/null 2>&1 || \ + echo "pre-commit: WARNING — pql plan export failed; changelog not refreshed." +else + echo "pre-commit: WARNING — pql not on PATH; decision validate + changelog export skipped." +fi # Run cargo audit only when Cargo.toml or Cargo.lock changed if git diff --cached --name-only | grep -qE '(Cargo\.toml|Cargo\.lock)$'; then diff --git a/Makefile b/Makefile index 0086914e3..3beff9186 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null) .PHONY: help setup build check-protocol client server game stop test lint lint-python setup-venv ci ci-client ci-server clean \ - decisions-sync decisions-coverage decisions-active decisions-orphan decisions-orphan-tickets \ + decisions-sync decisions-active decisions-validate \ db-backup db-install validate-content check-fact-ids setup-hooks install-hooks \ audit deny atlas-verify economy-db regen-db check-systems-db \ pre-pr pre-pr-lint pre-pr-build pre-pr-test pre-pr-validate pre-pr-fixtures \ @@ -45,11 +45,9 @@ help: @echo " make db-backup Backup shared database to git (main only)" @echo " make db-install Restore shared database from backup" @echo "" - @echo " make decisions-sync Sync decisions/*.md into SQLite" - @echo " make decisions-coverage Each decision with its implementing ticket(s)" - @echo " make decisions-active List active decisions" - @echo " make decisions-orphan Decisions without implementing tickets" - @echo " make decisions-orphan-tickets Tickets with invalid or missing decision_ref" + @echo " make decisions-sync Sync governance/*.md decision records into pql.db" + @echo " make decisions-active List active confirmed decisions (pql)" + @echo " make decisions-validate Validate decision records — malformed-record gate (pql)" @echo " make audit Run cargo audit (security advisory check)" @echo " make deny Run cargo deny check (license/ban policy)" @echo " make validate-content Validate content YAML against schemas" @@ -114,8 +112,9 @@ setup-hooks: @echo "Git hooks path set to .config/hooks" install-hooks: setup-hooks - @chmod +x .config/hooks/pre-push .config/hooks/pre-commit - @echo "Hooks installed — pre-push and pre-commit are active." + @chmod +x .config/hooks/pre-push .config/hooks/pre-commit \ + .config/hooks/post-merge .config/hooks/post-checkout .config/hooks/post-rewrite + @echo "Hooks installed — pre-commit, pre-push, post-merge, post-checkout, post-rewrite are active." setup-venv: @python3 -m venv .venv @@ -374,22 +373,19 @@ econ-sim-run: ## Run a quick economics simulation (100 ticks, output to /tmp/ec econ-sim-stability: ## Run D-179 stability checks (Tests 1 and 2) @tooling/econ-sim/target/release/econ-sim --stability-check -# --- Decisions --- +# --- Decisions (pql) --- +# Decision records are markdown-sourced under governance/{decisions,questions,rejected}/ +# and indexed into .pql/pql.db by `pql decisions sync`. Per-decision ticket coverage: +# `pql decisions show --with-tickets`. Cross-references: `pql decisions refs `. decisions-sync: - @tooling/db/decisions-sync - -decisions-coverage: - @tooling/db/sqlite-query "SELECT d.id, d.domain, d.title, COALESCE(GROUP_CONCAT(t.id, ', '), '') as implementing_tickets FROM decisions d LEFT JOIN tickets t ON d.id = t.decision_ref WHERE d.status='active' AND d.type='confirmed' GROUP BY d.id ORDER BY d.domain, d.id" + @pql decisions sync decisions-active: - @tooling/db/sqlite-query "SELECT id, domain, title FROM decisions WHERE status='active' AND type='confirmed' ORDER BY domain, id" + @pql decisions list --type confirmed -decisions-orphan: - @tooling/db/sqlite-query "SELECT id, title FROM decisions WHERE type='confirmed' AND status='active' AND id NOT IN (SELECT DISTINCT decision_ref FROM tickets WHERE decision_ref IS NOT NULL)" - -decisions-orphan-tickets: - @tooling/db/decision orphan-tickets +decisions-validate: + @pql decisions validate # --- Content Validation ---