Warden plan
tier: hermetic requires: []
The inverted, signal-native, multi-tenant substrate foundation shipped still holds structurally: one fresh baseline migration, zero legacy vocabulary (fragment/thread/blueprint) anywhere, the new knowledge primitives present and the retired ones gone, and the D32 User/Person decoupling intact (no users.person_key, no people.is_owner). These are file/grep-level assertions — fast, deterministic, no DB — that later sprints re-run as a regression floor; the DB-backed boot + full test suite is covered by plan 01's green bar.
None beyond a clean checkout of the branch under test. (Plan 01 covers the container-backed gates.)
set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
# D0 pinned ONE clean baseline with no legacy migrations; later sprints add
# sanctioned migrations on top (connect's 0001-0003, etc.). Guard D0's surviving
# intent: 0000_baseline.sql is the root (lowest-numbered) migration.
FIRST=$(ls server/drizzle/migrations/*.sql 2>/dev/null | xargs -n1 basename | sort | head -1)
[ "$FIRST" = "0000_baseline.sql" ] \
&& warden_pass "0000_baseline.sql is the root migration ($(ls server/drizzle/migrations/*.sql | wc -l | tr -d ' ') total; sanctioned sprint migrations layer on top)" \
|| warden_fail "expected 0000_baseline.sql as the root migration, first found: $FIRST"
# The drizzle meta snapshot must agree with the baseline (a drifted snapshot
# makes the next sprint's `drizzle-kit generate` emit a spurious migration).
if grep -q "is_owner\|person_key" server/drizzle/migrations/meta/0000_snapshot.json; then
warden_fail "meta snapshot still references dropped is_owner/person_key (D32 drift)"
else
warden_pass "meta snapshot is free of the D32-dropped columns"
fi
set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
SCOPE="server/src server/scripts packages/agent/src packages/queue/src packages/shared/src packages/editor/src app/src server/drizzle"
# Robin concepts only: assert the retired CONCEPT is gone from CODE, not raw
# substrings. Both-ends word boundary (`\bfragments?\b`) so proper nouns and
# camelCase are not the concept — the Plate editor API (`deleteFragment`,
# `InsertFragmentPayload`) and a redacted-corpus wikiLink proper noun
# (`'Fragmenter'`) are not Robin's retired `fragments` module/table. Comment
# lines are excluded (same as the thread check below): the socrates fold left
# docblocks explaining what the retired sandbox `fragments` path was replaced
# with — history in a comment is not a live reference. React's own `Fragment`
# API (`import { Fragment } from 'react'`, `<Fragment key>` JSX) is legal React,
# not D1 vocabulary — excluded by the case-sensitive React-API filter below.
FRAG_HITS() { grep -rniE '\b(fragments?|blueprint)\b' $SCOPE --include='*.ts' --include='*.tsx' --include='*.css' 2>/dev/null \
| grep -viE 'never .*blueprint|not .*blueprint' \
| grep -vE ':[0-9]+:[[:space:]]*(\*|//|/\*)' \
| grep -vE "\bFragment\b.*from ['\"]react['\"]|</?Fragment[ >]" \
| grep -viE 'a chat fragment'; }
FRAG=$(FRAG_HITS | wc -l | tr -d ' ')
[ "$FRAG" = "0" ] \
&& warden_pass "no fragment/blueprint vocabulary in code (D1)" \
|| { FRAG_HITS | head; warden_fail "$FRAG fragment/blueprint references remain"; }
# Exclude comment lines (`* ...` TSDoc / `//` / `/* */`) after the file:line
# prefix — the retired thread CONCEPT would surface in code (identifiers,
# routes, types), not an English "threads X through" verb in a docblock.
THREAD_HITS() { grep -rniE '\bthreads?\b' $SCOPE --include='*.ts' --include='*.tsx' 2>/dev/null | grep -vE ':[0-9]+:[[:space:]]*(\*|//|/\*)'; }
THREAD=$(THREAD_HITS | wc -l | tr -d ' ')
[ "$THREAD" = "0" ] \
&& warden_pass "no thread vocabulary in code (D1)" \
|| { THREAD_HITS | head; warden_fail "$THREAD thread references remain in code"; }
set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
# New signal-native modules exist.
MISSING=0
for m in signals workspaces signal-databases domains; do
[ -f "server/src/modules/$m/index.ts" ] || { echo "missing module: $m"; MISSING=1; }
done
[ "$MISSING" = "0" ] \
&& warden_pass "signal/workspace/signal-database/domain modules present" \
|| warden_fail "a foundation module barrel is missing"
# Retired modules are gone (D1/D7).
{ [ ! -d server/src/modules/fragments ] && [ ! -d server/src/modules/groups ]; } \
&& warden_pass "retired modules removed (fragments→signals, groups deleted)" \
|| warden_fail "a retired module dir still exists (fragments/groups)"
# Baseline carries the new tables + the workspace boundary.
BASE=server/drizzle/migrations/0000_baseline.sql
MISS=0
for t in workspaces signal_databases signal_database_signals knowledge_domains domain_subscriptions domain_signals guardian_grants; do
grep -qiE "CREATE TABLE[^;]*\"?$t\"?" "$BASE" || { echo "baseline missing table: $t"; MISS=1; }
done
[ "$MISS" = "0" ] \
&& warden_pass "baseline creates the workspace/signal-database/domain/guardian tables" \
|| warden_fail "baseline is missing a foundation table"
set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
# The user→Person self-link machinery must not exist (D32).
[ ! -f server/src/lib/user-person-link.ts ] \
&& warden_pass "user-person-link module is gone (D32)" \
|| warden_fail "server/src/lib/user-person-link.ts reintroduced"
LINK=$(grep -rn "linkUserToPerson\|backfillUserPeople" server/src --include='*.ts' 2>/dev/null | wc -l | tr -d ' ')
[ "$LINK" = "0" ] \
&& warden_pass "no linkUserToPerson/backfillUserPeople references (D32)" \
|| warden_fail "$LINK references to the retired link machinery remain"
# Schema is free of the coupling columns/index.
COUP=$(grep -cE "person_key|is_owner|isOwner|personKey" server/src/db/schema.ts 2>/dev/null | tr -d ' ')
[ "$COUP" = "0" ] \
&& warden_pass "schema.ts has no person_key / is_owner (D32)" \
|| warden_fail "schema.ts still references the User↔Person coupling"
# The standard owner tag survives: created_by_user_id is stamped at write paths.
STAMP=$(grep -rn "createdByUserId:" server/src/modules/entries/routes.ts server/src/modules/signals/routes.ts server/src/mcp/handlers.ts 2>/dev/null | wc -l | tr -d ' ')
[ "$STAMP" -ge 3 ] \
&& warden_pass "created_by_user_id owner-tag stamped on entry/signal/mcp write paths ($STAMP sites)" \
|| warden_fail "created_by_user_id stamping thinned out (expected >=3, got $STAMP)"