diff --git a/.forgejo/workflows/publish-source.yml b/.forgejo/workflows/publish-source.yml index a08875ae..8220bac9 100644 --- a/.forgejo/workflows/publish-source.yml +++ b/.forgejo/workflows/publish-source.yml @@ -34,16 +34,7 @@ jobs: SOURCE_NPM_REG="https://source.soulcraft.com/api/packages/soulcraft/npm/" VERSION="$(node -p "require('./package.json').version")" - # The dist-tag follows the version: a prerelease (any hyphen — - # 10.4.0-rc.1) publishes under 'rc' and must NEVER move 'latest' — - # every consumer resolving 'latest' from this registry would otherwise - # be handed a release candidate. Same rule scripts/release.sh applies - # to the storefront leg. - NPM_TAG="latest" - case "$VERSION" in - *-*) NPM_TAG="rc" ;; - esac - echo "Publishing @soulcraft/brainy@${VERSION} to The Source registry (dist-tag: ${NPM_TAG})..." + echo "Publishing @soulcraft/brainy@${VERSION} to The Source registry..." TMPRC="$(mktemp)" chmod 600 "$TMPRC" @@ -56,7 +47,7 @@ jobs: # this tag's checkout already carries the version being published — # nothing here re-derives it from the tag name. PUBLISH_OK=true - if ! npm publish --tag "$NPM_TAG" --userconfig "$TMPRC"; then + if ! npm publish --tag latest --userconfig "$TMPRC"; then PUBLISH_OK=false fi diff --git a/CHANGELOG.md b/CHANGELOG.md index cd64d88f..f99584e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,6 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -### [10.4.0-rc.1](https://source.soulcraft.com/soulcraft/brainy/compare/v10.3.1...v10.4.0-rc.1) (2026-08-24) - -- ci(publish): the home dist-tag follows the version — a prerelease publishes under 'rc' and never moves 'latest' (a1376e4a) -- chore(release): --source-only — a home-only prerelease mode (The Source, never the storefront) (dcbad176) -- test(fold-checkpoint): the ARM-AT-FLIP pin arms its crash instead of racing the pending-flush timer (4176439b) -- fix(health): one contract for a throwing probe — heal is none, serving is not withheld; repair report gains missing/rebuilt/reason (116550eb) -- feat(storage): the canonical count ledger — ALL-visibility scalars, unclamped totals, suspect-on-unprovable-delete (7c8c8be3) -- fix(delete): the null-metadata skip closes — index legs run id-keyed or narrate, never silently strand postings (607e9f54) -- feat(repair): repairIndex returns the per-family receipt and narrates its summary (8d45f964) -- fix(reads): the readiness gate guards every index read surface — serving empty from a not-ready provider is unrepresentable (40e7119b) -- ci(gate): the machine-health preflight and the truncation verdict guard (1e046aa1) - - ### [10.3.1](https://source.soulcraft.com/soulcraft/brainy/compare/v10.3.0...v10.3.1) (2026-08-18) - docs(releases): the 10.3.1 consumer entry — the fold that behaves (900cc895) diff --git a/package-lock.json b/package-lock.json index 8cee0038..afce417d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@soulcraft/brainy", - "version": "10.4.0-rc.1", + "version": "10.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@soulcraft/brainy", - "version": "10.4.0-rc.1", + "version": "10.3.1", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/package.json b/package.json index ef803c11..75e5bfbc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@soulcraft/brainy", - "version": "10.4.0-rc.1", + "version": "10.3.1", "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns × 127 verbs covering 96-97% of all human knowledge.", "main": "dist/index.js", "module": "dist/index.js", diff --git a/scripts/gate/README.md b/scripts/gate/README.md deleted file mode 100644 index 0a8afab0..00000000 --- a/scripts/gate/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# Gate Guards - -Two standalone scripts that stand between a test/build gate and a false -verdict: one refuses to let the gate start on a noisy machine, the other -refuses to let a truncated or crashed vitest run be read as green. - -## Why these exist - -Both guards exist because of the 2026-08-13 lost-day ledger: a gate ran on -a machine under load, and separately a vitest worker pool died mid-suite -while still printing a plausible-looking summary line, and in both cases -the bad result was trusted and acted on for the better part of a day before -anyone noticed. Neither failure mode announces itself — a loaded machine -still finishes and reports numbers, and a truncated test run still prints a -`Test Files` / `Tests` line — so both guards check the evidence explicitly -rather than trusting that a gate finishing means the gate was valid. - -## gate-preflight.sh - -Run before any gate lane starts. Exits 1 the moment the machine isn't -gate-clean, with one `FATAL:` line per violation naming the exact offender -(the pid and command, the path, the measured value). Prints one `OK:` line -per check that passes. `WARNING:` lines mark checks that were skipped, not -failures. - -Checks: - -| # | Check | Default threshold | Override | -|---|-------|--------------------|----------| -| a | 1-minute load average | `nproc / 2` | `GATE_MAX_LOAD` | -| b | any non-allowlisted process over 50% of one core | 50% | `GATE_ALLOW_REGEX` (extra pattern matched against the process's args) | -| c | cpu0 scaling governor must be `performance` | — | none (warns and skips if the sysfs path is absent) | -| d | free space on `/` and `/tmp` | 10G each | `GATE_SKIP_DISK_CHECK=1` to skip entirely | - -The allowlist for check (b) is always: this script's own process tree -(its ancestors and its direct child processes), `sshd`, `systemd`, and -kernel threads (recognizable by args wrapped in brackets, e.g. -`[kworker/0:1]`). `GATE_ALLOW_REGEX` extends it — it does not replace it. - -## vitest-verdict-check.sh - -Run after every vitest lane, against that lane's captured log. Fails -loudly, quoting the exact line or string that tripped it, when the log's -own summary can't be trusted: - -- no `Test Files` (or, in `--count-tests` mode, `Tests`) summary line is - present at all -- the parenthesized total in that line doesn't match what was expected -- fewer files/tests are accounted for (passed + failed + skipped) than the - total claims — a truncated run -- the log contains `Unhandled Error` or `Timeout calling` anywhere — a dead - worker pool, regardless of what the summary line claims - -``` -vitest-verdict-check.sh -vitest-verdict-check.sh --count-tests -``` - -The first form checks `Test Files` for an exact match. The second checks -`Tests` for a minimum (a floor, not an exact count, since the total number -of individual tests moves more often than the number of test files). - -## Wiring into a CI lane - -```sh -# Before any lane that will report a verdict: -scripts/gate/gate-preflight.sh || exit 1 - -# Run the suite, capturing its output: -npx vitest run tests/unit 2>&1 | tee /tmp/unit.log - -# After every vitest lane, check the log against the actual file count: -EXPECTED_FILES=$(ls tests/unit/**/*.test.ts | wc -l) -scripts/gate/vitest-verdict-check.sh /tmp/unit.log "$EXPECTED_FILES" || exit 1 -``` - -## Exit-code contract - -| Script | Exit 0 | Exit 1 | -|--------|--------|--------| -| `gate-preflight.sh` | machine is gate-clean | one or more `FATAL:` violations printed | -| `vitest-verdict-check.sh` | log's summary is trustworthy and matches | usage error, missing/unreadable log, or one or more `FATAL:` violations printed | - -Non-zero from either script means: do not trust the gate that was about to -run, or the result of the one that just ran. diff --git a/scripts/gate/gate-preflight.sh b/scripts/gate/gate-preflight.sh deleted file mode 100755 index c6208f49..00000000 --- a/scripts/gate/gate-preflight.sh +++ /dev/null @@ -1,206 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Brainy Gate Preflight -# Refuses to let a test/build gate run on a machine that isn't clean enough -# to trust the numbers it produces. See scripts/gate/README.md for why (the -# 2026-08-13 lost-day ledger). -# -# Checks: 1-minute load average, any non-allowlisted process pinning a core, -# the cpu0 scaling governor, and free space on / and /tmp. -# -# Exit 0 and print one OK line per passing check when the machine is clean. -# Exit 1 and print one FATAL line per violation, naming the offender, when -# it is not. -# -# Known trap: a helper function whose last executed statement is a `while` -# (or any command whose own exit status happens to be nonzero) hands that -# status back as the function's return value. Called as a plain statement, -# that silently kills this script under `set -e`. Every helper below ends -# on an explicit `return 0` as its own statement, never on a loop or test. -# -# The same failure mode hides in plainer-looking lines too: `var=$(cmd)` is -# a bare assignment, so `set -e` DOES treat a nonzero `cmd` (or, under -# `pipefail`, a nonzero stage anywhere in `cmd`'s pipeline) as a failure of -# that statement and kills the script right there — even mid-loop, even -# when the "failure" is routine (a process that exited before a second -# lookup, a path that doesn't exist). Every such assignment below is paired -# with an explicit `|| var=""` fallback so a routine miss degrades to an -# empty value instead of an exit. - -VIOLATIONS=0 -ANCESTOR_PIDS="" - -fatal() { - echo "FATAL: $1" - VIOLATIONS=$((VIOLATIONS + 1)) -} - -ok() { - echo "OK: $1" -} - -# Walks this process's parent chain up to pid 1, then takes one snapshot of -# its direct children (the ps/read pipeline in check_processes), and -# records both in ANCESTOR_PIDS — so the process-scan below can recognize -# its own tree (the shell/terminal/session that launched it, plus its own -# helper commands) instead of flagging it. Children are captured once, up -# front, rather than re-queried per row later, so a helper command that has -# already exited by the time it's looked up can't be mistaken for a miss. -build_ancestor_pids() { - local pid="$$" - local ppid child - ANCESTOR_PIDS=" $pid " - while [ "$pid" != "1" ]; do - ppid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ') || ppid="" - if [ -z "$ppid" ]; then - break - fi - ANCESTOR_PIDS="${ANCESTOR_PIDS}${ppid} " - pid="$ppid" - done - - while IFS= read -r child; do - [ -z "$child" ] && continue - ANCESTOR_PIDS="${ANCESTOR_PIDS}${child} " - done < <(ps --ppid "$$" -o pid= 2>/dev/null || true) - - return 0 -} - -# (a) 1-minute load average vs. threshold (default: nproc / 2). -check_load() { - local max_load="${GATE_MAX_LOAD:-}" - if [ -z "$max_load" ]; then - max_load=$(( $(nproc) / 2 )) - if [ "$max_load" -lt 1 ]; then - max_load=1 - fi - fi - - local load_1m - load_1m=$(cut -d' ' -f1 /proc/loadavg) - - if awk -v l="$load_1m" -v m="$max_load" 'BEGIN { exit !(l > m) }'; then - fatal "1-minute load average ${load_1m} exceeds threshold ${max_load} (GATE_MAX_LOAD=${max_load})" - else - ok "1-minute load average ${load_1m} is within threshold ${max_load}" - fi - return 0 -} - -# (b) any process outside the allowlist pinning more than half a core. -# Parsed with `read` into named fields, not an awk/cut chain — a fixed-column -# awk/cut split on `ps` output duplicated fields the first time this was -# tried, because process args vary in word count. `read` with a fixed list -# of variables dumps everything left over into the last one (args), which -# handles that correctly. -check_processes() { - local max_pcpu=50 - local extra_regex="${GATE_ALLOW_REGEX:-}" - local violation_found=0 - local line pcpu pid args pcpu_int - - while IFS= read -r line; do - [ -z "$line" ] && continue - read -r pcpu pid args <<< "$line" - - # Kernel threads report their comm in brackets, e.g. "[kworker/0:1]". - case "$args" in - \[*\]) continue ;; - esac - - # This script's own tree: its ancestors (shell, terminal, session) and - # its direct children, both captured once by build_ancestor_pids. - case " $ANCESTOR_PIDS " in - *" $pid "*) continue ;; - esac - - case "$args" in - *sshd*|*systemd*) continue ;; - esac - - if [ -n "$extra_regex" ] && [[ "$args" =~ $extra_regex ]]; then - continue - fi - - pcpu_int="${pcpu%.*}" - if [ -z "$pcpu_int" ]; then - pcpu_int=0 - fi - if [ "$pcpu_int" -gt "$max_pcpu" ]; then - fatal "pid ${pid} ('${args}') is using ${pcpu}% of one core" - violation_found=1 - fi - done < <(ps -eo pcpu,pid,args --sort=-pcpu | tail -n +2) - - if [ "$violation_found" -eq 0 ]; then - ok "no process outside the allowlist exceeds ${max_pcpu}% of one core" - fi - return 0 -} - -# (c) cpu0 scaling governor must be "performance". Skipped with a warning -# (not a violation) when the sysfs path doesn't exist on this machine. -check_governor() { - local gov_path="/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" - if [ ! -r "$gov_path" ]; then - echo "WARNING: ${gov_path} not present; skipping governor check" - return 0 - fi - - local governor - governor=$(cat "$gov_path" 2>/dev/null) || governor="" - if [ "$governor" != "performance" ]; then - fatal "cpu0 governor is '${governor}', not 'performance'" - else - ok "cpu0 governor is 'performance'" - fi - return 0 -} - -# (d) free-space floors on / and /tmp (default 10G each). Skip entirely via -# GATE_SKIP_DISK_CHECK=1. -check_disk() { - if [ "${GATE_SKIP_DISK_CHECK:-0}" = "1" ]; then - echo "WARNING: disk free-space check skipped (GATE_SKIP_DISK_CHECK=1)" - return 0 - fi - - local floor_gb=10 - local floor_bytes=$((floor_gb * 1024 * 1024 * 1024)) - local path avail_bytes avail_gb - - for path in / /tmp; do - avail_bytes=$(df --output=avail -B1 "$path" 2>/dev/null | tail -n 1 | tr -d ' ') || avail_bytes="" - if [ -z "$avail_bytes" ]; then - echo "WARNING: could not determine free space on ${path}; skipping" - continue - fi - if [ "$avail_bytes" -lt "$floor_bytes" ]; then - avail_gb=$((avail_bytes / 1024 / 1024 / 1024)) - fatal "${path} has only ${avail_gb}G free, below the ${floor_gb}G floor" - else - ok "${path} has enough free space (floor ${floor_gb}G)" - fi - done - return 0 -} - -echo "Brainy gate preflight" -echo "----------------------" - -build_ancestor_pids -check_load -check_processes -check_governor -check_disk - -echo "----------------------" -if [ "$VIOLATIONS" -gt 0 ]; then - echo "FATAL: gate preflight failed with ${VIOLATIONS} violation(s) — machine is not gate-clean" - exit 1 -fi - -echo "gate preflight passed — machine is gate-clean" -exit 0 diff --git a/scripts/gate/vitest-verdict-check.sh b/scripts/gate/vitest-verdict-check.sh deleted file mode 100755 index 36243a1d..00000000 --- a/scripts/gate/vitest-verdict-check.sh +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/bash -set -euo pipefail - -# Brainy Vitest Verdict Check -# Confirms a vitest run's own summary line is trustworthy before anything -# downstream treats a green run as green. See scripts/gate/README.md for why -# (the 2026-08-13 lost-day ledger). -# -# Usage: -# vitest-verdict-check.sh -# vitest-verdict-check.sh --count-tests -# -# The first form checks the "Test Files" summary line's total against an -# exact expected count. The second checks the "Tests" summary line's total -# against a minimum. Both also fail on any sign the worker pool died -# mid-run, whether or not a summary line still made it into the log. -# -# Exit 0 and print one OK line per passing check when the log is clean. -# Exit 1 and print one FATAL line per violation, quoting the exact line or -# string that tripped it, when it is not. -# -# Known trap (shared with gate-preflight.sh): every helper below ends on an -# explicit `return 0` as its own statement, never on a loop or test, so a -# helper's last command can never hand its own exit status back as the -# function's under `set -e`. The same applies to `var=$(cmd)` assignments -# mid-helper: a bare assignment IS checked by `set -e`, so a `grep` that -# legitimately finds nothing (exit 1) would otherwise kill the script -# instead of just leaving the variable empty — every such assignment below -# is paired with an explicit `|| true` inside the substitution. - -usage() { - echo "Usage: $0 " - echo " $0 --count-tests " - exit 1 -} - -MODE="files" -if [ "${1:-}" = "--count-tests" ]; then - MODE="tests" - shift -fi - -LOG_FILE="${1:-}" -THRESHOLD="${2:-}" - -if [ -z "$LOG_FILE" ] || [ -z "$THRESHOLD" ]; then - usage -fi - -if [ ! -f "$LOG_FILE" ]; then - echo "FATAL: log file '${LOG_FILE}' does not exist" - exit 1 -fi - -if ! [[ "$THRESHOLD" =~ ^[0-9]+$ ]]; then - echo "FATAL: threshold '${THRESHOLD}' is not a non-negative integer" - exit 1 -fi - -VIOLATIONS=0 - -fatal() { - echo "FATAL: $1" - VIOLATIONS=$((VIOLATIONS + 1)) -} - -ok() { - echo "OK: $1" -} - -# Vitest colorizes its summary with ANSI escapes; strip them before parsing -# anything, or the color codes end up embedded in the fields we grep for. -CLEAN_LOG="$(sed 's/\x1b\[[0-9;]*m//g' "$LOG_FILE")" - -# Worker-pool death: if either string appears, the run's own summary line — -# even if present and even if its numbers look fine — cannot be trusted, -# because the process died mid-suite and vitest's own accounting is what -# died with it. -check_worker_death() { - if echo "$CLEAN_LOG" | grep -q "Unhandled Error"; then - fatal "log contains 'Unhandled Error' — worker pool died mid-run" - fi - if echo "$CLEAN_LOG" | grep -q "Timeout calling"; then - fatal "log contains 'Timeout calling' — worker pool died mid-run" - fi - return 0 -} - -# Shared shape between the "Test Files" and "Tests" summary lines: -#