Files
member-console/scripts/notebook-citations.sh
cgalo5758 a5a4b9c591 Gate archives on notebook citations and add the harvest skill
A notebook's lessons survive only if they are written into a tracked
home before the decision lands, so landing a change now has three
pieces. The contract: a "Landing a change" section in MAINTAINING.md and
a fifth item in the UI definition of done. The labor: a harvest skill
that inventories the notebook, names each file's kind and routes
findings to the owning docs page, reasoning to the change's design.md,
problems to issues.md and reusable tools to a tracked home. The gate:
scripts/notebook-citations.sh, a git grep over what git would commit for
the notebook's directory shape, which make lint runs after the program's
own lint, and scripts/archive-gate.sh, which refuses an mv into the
archive or an openspec archive while the check reports hits.

The gate is one script that any harness calls with the command it is
about to run; Claude Code reaches it through a PreToolUse hook and
opencode through a plugin. Both checks live in scripts/ rather than the
lint subcommand because they are repository hygiene, not part of the
shipped program. The generated openspec-archive-change skill is not
edited; the post-archive reminder carries the harvest step instead.
2026-09-19 19:47:15 -05:00

48 lines
1.9 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Refuse tracked text that names a path under status/explorations/.
#
# status/explorations/ is a local lab notebook git ignores
# (status/MAINTAINING.md, "Where things live"), so a tracked file naming a
# path under it points at something another clone does not have. This check
# reads what git would commit (the index plus untracked files the ignore rules
# do not exclude, binaries skipped) for the notebook's directory shape,
# explorations/<topic>-<yyyy-mm>, and leaves out what MAINTAINING.md freezes
# (archived changes, status/archive, status/log), design/ (synced from
# upstream, never edited here) and the notebook itself. The <topic>-<yyyy-mm>
# template MAINTAINING.md and the skills use has no digits, so a description
# of the convention is not a hit.
#
# It lives here and not in internal/lint because it is repository hygiene,
# not part of the shipped program; `make lint` runs it after the program's
# own lint. Exits 1 with one file:line per hit, 0 on a clean tree.
#
# Usage: ./scripts/notebook-citations.sh [repo-root]
set -euo pipefail
cd "${1:-$(dirname "$0")/..}"
pattern='explorations/[a-z0-9]+(-[a-z0-9]+)*-20[0-9]{2}-[0-9]{2}'
hits=$(git grep -n -I -E --untracked "$pattern" -- . \
':!design' ':!openspec/changes/archive' ':!status/archive' \
':!status/explorations' ':!status/log' ':!test/screens' || true)
if [[ -z "$hits" ]]; then
echo "notebook-citations: ok" >&2
exit 0
fi
count=0
while IFS= read -r line; do
file=${line%%:*}
rest=${line#*:}
lineno=${rest%%:*}
text=${rest#*:}
cite=$(grep -oE "$pattern" <<<"$text" | head -1)
printf '%s:%s: [notebook-citation] cites the exploration notebook "%s", which a clone does not have; state the fact or cite its tracked home (status/MAINTAINING.md, "Where things live")\n' \
"$file" "$lineno" "$cite" >&2
count=$((count + 1))
done <<<"$hits"
echo >&2
echo "notebook-citations: $count hit(s)" >&2
exit 1