diff --git a/.gaai/core/VERSION b/.gaai/core/VERSION index 9a9feb08..132775c2 100644 --- a/.gaai/core/VERSION +++ b/.gaai/core/VERSION @@ -1 +1 @@ -2.48.0 +2.49.0 diff --git a/.gaai/core/hooks/post-commit.d/03-memory-index-check.sh b/.gaai/core/hooks/post-commit.d/03-memory-index-check.sh index 262bdf45..3931a136 100755 --- a/.gaai/core/hooks/post-commit.d/03-memory-index-check.sh +++ b/.gaai/core/hooks/post-commit.d/03-memory-index-check.sh @@ -57,4 +57,53 @@ if git diff-tree --no-commit-id --name-only -r HEAD | grep -q 'contexts/memory/. else echo "⚠️ ${UNREGISTERED} memory file(s) not found in any registry (run memory-index-sync to fix)" fi + + # ── Registry row width ──────────────────────────────────────────────────── + # An index row is a pointer: metadata + a short topic, capped at 200 characters + # by the base rules. Substance belongs in the target file. + # + # This is a RATCHET, not an audit. Registries in the wild already carry rows well + # past the cap, and enumerating every one of them on each memory commit would bury + # the signal under warnings nobody can act on in the moment. So only rows that THIS + # commit introduces are reported — the standing debt is left to a compaction pass + # (memory-index-compact), while a new violation is caught while it is still one line + # in one commit. + CAP=200 + NEW_OVER=0 + + # Characters, not bytes: a topic carrying arrows or accents is shorter than its byte + # count, and the cap is stated in characters. Without python3 the check falls back to + # bytes, which can only over-report — it never lets a long row through unseen. + if command -v python3 >/dev/null 2>&1; then + _rows_over_cap() { python3 -c ' +import sys +cap = int(sys.argv[1]) +for line in sys.stdin.read().splitlines(): + if len(line) > cap: + print("%d\t%s" % (len(line), line[:72])) +' "$CAP"; } + else + _rows_over_cap() { awk -v cap="$CAP" 'length($0) > cap { printf "%d\t%.72s\n", length($0), $0 }'; } + fi + + for idx in "${INDEX_FILES[@]}"; do + rel_idx="${idx#"$ROOT"/}" + # Added lines only (leading '+'), table rows only, minus the header separator. + added="$(git diff-tree --no-commit-id -r -p HEAD -- "$rel_idx" 2>/dev/null \ + | sed -n 's/^+\(|.*\)$/\1/p' \ + | grep -Ev '^\|[-: |]+\|?[[:space:]]*$')" + [ -z "$added" ] && continue + while IFS=$'\t' read -r len excerpt; do + [ -z "$len" ] && continue + if (( NEW_OVER == 0 )); then + echo "⚠️ Registry rows over the ${CAP}-char pointer cap were added:" + fi + echo " ⚠️ ${len} chars in $(basename "$rel_idx"): ${excerpt}…" + ((NEW_OVER++)) + done < <(printf '%s\n' "$added" | _rows_over_cap) + done + + if (( NEW_OVER > 0 )); then + echo " → Trim to a metadata + ≤30-word topic pointer; the detail belongs in the target file." + fi fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 852870f9..ae768632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,18 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- -## [Unreleased] +## [2.49.0] - 2026-08-17 ### Changed +- feat: catch registry rows that break the pointer cap, as they are added - docs: the remote branch may be deleted by the forge, not by hand - docs: the post-merge cleanup clause prescribed a flag that breaks an invariant - fix: record run identity on the handle instead of inferring it - fix: keep and poll the handle until a terminal receipt - fix: make generated execution plans carry artefact frontmatter --: Make hosted CI the sole daemon merge authority --: Consume the two-axis handoff and route remediation --: 'The CI test-gate wait outlasts a normal CI run, so local --: Produce and validate the two-axis QA handoff + ## [2.49.0] - 2026-08-11 diff --git a/README.md b/README.md index 4dfb4f47..c14ab45d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Version](https://img.shields.io/badge/version-2.48.0-blue) +![Version](https://img.shields.io/badge/version-2.49.0-blue) ![License: ELv2](https://img.shields.io/badge/license-ELv2-green) ![No SDK](https://img.shields.io/badge/stack-markdown%20%2B%20yaml%20%2B%20bash-orange)