Warden plan
tier: needs-postgres requires: []
Issue #306's deletion holds against the code + a live database: the seven pre-KA wiki types — belief, decision, agent, principle, skill, research, voice — are gone from every exhaustive map (WikiType, the generation schemaMap, WIKI_TYPE_TO_GUIDE_KEY, the inference descriptors), their YAML + schema files are deleted from disk, and migration 0033 removes their wiki_types rows rather than leaving them to be silently re-offered as "user-created" (the trap: a row whose disk spec is gone reads as deprecated: false, so a leftover row would come BACK into the create picker instead of staying retired). Only the canonical six — Log, POV, Process, Choice, Project, Objective — remain creatable on every transport. Step 1 is a fast file/grep structural floor; step 2 confirms zero live data sits on a retired type and re-runs the committed dbtests that pin the server-side refusal on both HTTP and MCP.
greenlight-pg :5433 with the vector extension, greenlight-redis :6380). See .warden/HANDOFF.md.PROJECT_ROOT points at a tree with commit 395fa93b ("delete the seven pre-KA types, leaving six") merged — canary already carries it. Invoke through that tree's .warden symlink so the greps + dbtests target the branch code.pnpm, grep, awk, psql on PATH. The env file is provisioned automatically by .warden/run.sh from the tracked .warden/env/ci-env.template.sh plus the machine-local secrets file ~/.config/robin/warden-secrets.sh (mode 600, outside every git repository; override with WARDEN_SECRETS_FILE); first-time setup: mkdir -p ~/.config/robin && cp .warden/env/secrets.local.example.sh ~/.config/robin/warden-secrets.sh && chmod 600 ~/.config/robin/warden-secrets.sh.set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
RETIRED="agent belief decision principle research skill voice"
SPEC_DIR=packages/shared/src/prompts/specs/wiki-types
# WTG-1: no retired .yaml/.schema.ts file survives on disk; exactly the six
# canonical types' two files each (12 files) remain.
leak=0
for slug in $RETIRED; do
if [ -f "$SPEC_DIR/$slug.yaml" ] || [ -f "$SPEC_DIR/$slug.schema.ts" ]; then
warden_observe "retired spec file still on disk: $slug"
leak=1
fi
done
COUNT=$(find "$SPEC_DIR" -maxdepth 1 -type f | wc -l | tr -d ' ')
if [ "$leak" = 0 ] && [ "$COUNT" = "12" ]; then
warden_pass "WTG-1: the seven retired wiki-type spec files are gone (12 files remain: 6 types x yaml+schema)"
else
warden_fail "WTG-1: a retired wiki-type spec file survives on disk (found $COUNT files in $SPEC_DIR)"
fi
# WTG-2: the WikiType union carries only the six canonical slugs.
WT=packages/shared/src/types/wiki.ts
UNION=$(awk '/^export type WikiType =/,/^$/' "$WT")
leak=0
for slug in $RETIRED; do
if printf '%s' "$UNION" | grep -qE "'$slug'"; then
warden_observe "WikiType union still carries '$slug'"
leak=1
fi
done
if [ "$leak" = 0 ] \
&& printf '%s' "$UNION" | grep -q "'log'" && printf '%s' "$UNION" | grep -q "'pov'" \
&& printf '%s' "$UNION" | grep -q "'process'" && printf '%s' "$UNION" | grep -q "'choice'" \
&& printf '%s' "$UNION" | grep -q "'project'" && printf '%s' "$UNION" | grep -q "'objective'"; then
warden_pass "WTG-2: WikiType is exactly the canonical six"
else
warden_fail "WTG-2: WikiType union regressed — a retired slug survives or a canonical slug is missing"
fi
# WTG-3: the generation schemaMap (wiki-generation.ts) has no retired import
# or map entry.
WG=packages/shared/src/prompts/loaders/wiki-generation.ts
leak=0
for slug in $RETIRED; do
if grep -qE "${slug}WikiSchema|specs/wiki-types/${slug}\.schema" "$WG"; then
warden_observe "wiki-generation.ts still imports/maps the retired '$slug' schema"
leak=1
fi
done
[ "$leak" = 0 ] \
&& warden_pass "WTG-3: wiki-generation.ts schemaMap carries no retired schema import/entry" \
|| warden_fail "WTG-3: wiki-generation.ts still references a retired wiki-type schema"
# WTG-4: config.ts's WikiGuideKey / WIKI_TYPE_TO_GUIDE_KEY has no retired key.
CFG=packages/shared/src/types/config.ts
leak=0
for slug in $RETIRED; do
if grep -q "wiki-guide-$slug" "$CFG"; then
warden_observe "config.ts still carries wiki-guide-$slug"
leak=1
fi
done
[ "$leak" = 0 ] \
&& warden_pass "WTG-4: config.ts guide-key map carries no retired entry" \
|| warden_fail "WTG-4: config.ts still maps a retired wiki-guide key"
# WTG-5: the inference descriptor map (server-side) has no retired key.
INF=server/src/lib/wiki-type-inference.ts
leak=0
for slug in $RETIRED; do
if grep -qE "^\s*$slug:" "$INF"; then
warden_observe "wiki-type-inference.ts still carries a '$slug' descriptor"
leak=1
fi
done
[ "$leak" = 0 ] \
&& warden_pass "WTG-5: wiki-type-inference.ts descriptor map carries no retired entry" \
|| warden_fail "WTG-5: wiki-type-inference.ts still has a retired descriptor"
# WTG-6: migration 0033 exists and its DELETE targets exactly the seven
# retired slugs against wiki_types.
MIG=server/drizzle/migrations/0033_drop_pre_ka_wiki_types.sql
if [ -f "$MIG" ] && grep -q 'DELETE FROM "wiki_types"' "$MIG"; then
ok=1
for slug in $RETIRED; do
grep -q "'$slug'" "$MIG" || ok=0
done
[ "$ok" = 1 ] \
&& warden_pass "WTG-6: migration 0033 deletes exactly the seven retired wiki_types slugs" \
|| warden_fail "WTG-6: migration 0033 is missing one of the seven retired slugs in its DELETE"
else
warden_fail "WTG-6: migration 0033 (drop pre-KA wiki types) is missing"
fi
set -uo pipefail
source "$WARDEN_LIB/assert.sh"
cd "${PROJECT_ROOT:-$(git rev-parse --show-toplevel)}"
# shellcheck disable=SC1091
source "${WARDEN_ENV_FILE:?WARDEN_ENV_FILE not set — run this plan via .warden/run.sh}"
# WTG-7 (the issue's "guard before deleting", re-run as a standing floor):
# no live wiki sits on a retired type. Read-only count against $DATABASE_URL.
CNT=$(psql "$DATABASE_URL" -tA -c \
"SELECT count(*) FROM wikis WHERE type IN ('agent','belief','decision','principle','research','skill','voice');" \
2>/tmp/warden-wtg-guard.log)
if [ "$CNT" = "0" ]; then
warden_pass "WTG-7: zero live wikis reference a retired type"
else
cat /tmp/warden-wtg-guard.log
warden_fail "WTG-7: found $CNT live wiki(s) on a retired type — deletion is NOT a free delete anymore"
fi
# WTG-8: the committed dbtests that pin the server-side refusal (HTTP +
# MCP), the fresh-workspace seed set, and the cross-tenant listing all pass.
if pnpm --filter @robin/server exec vitest run \
src/modules/wikis/deprecated-type-guard.dbtest.test.ts \
src/bootstrap/seed-wiki-types.dbtest.test.ts \
src/mcp/__tests__/wiki-types-isolation.dbtest.test.ts \
src/modules/preferences/wiki-types.routes.test.ts \
>/tmp/warden-wtg-dbtests.log 2>&1; then
warden_pass "WTG-8: deprecated-type-guard + seed + isolation + preferences dbtests all pass"
else
tail -30 /tmp/warden-wtg-dbtests.log
warden_fail "WTG-8: a wiki-type ghost-retirement dbtest FAILED — see /tmp/warden-wtg-dbtests.log"
fi
Backend-only cleanup, no web surface — no agent-browser E2E here. Step 1 is the cheap structural floor that would catch a future re-add of a retired type to any of the five exhaustive maps (WikiType, schemaMap, WIKI_TYPE_TO_GUIDE_KEY, the inference descriptors, migration 0033) without touching a live DB. Step 2 is read-only against the shared robin_ci database for WTG-7 (a plain SELECT count(*), not a schema mutation) and re-runs the four committed suites — including deprecated-type-guard.dbtest.test.ts, which still manually inserts a deprecated: true row to prove the YAML-flag refusal mechanism holds even if a stray row like that ever reappeared, belt-and-suspenders on top of the "unknown type" 400/isError path a freshly-seeded workspace takes today.
On the v11-batch tier label: .warden/TIERS.md fixes the tier: vocabulary to seven operational labels (hermetic/needs-redis/ needs-postgres/needs-server/needs-model/destructive/volatile), and .warden/run.sh's tier:<label> selector only recognizes that list — a literal tier: v11-batch would be rejected by the CLI selector. I did not put v11-batch in the frontmatter; I tagged it in the title instead, the way other plans carry issue/decision numbers. If the batch actually needs to be a CLI-selectable group, it should be a phase: subdirectory (.warden/plans/v11-batch/17-...md), not a tier: value — flagging this for confirmation rather than guessing.
Stays manual / not asserted here:
useWikiTypesList / AddWikiModal / QuickCreate client-side filtering is covered by app unit tests, not a warden browser step; this plan only proves the server-side floor (the thing #306 actually asked for, given an old audit had flagged the filter as client-side only).types/wiki.ts, not something warden should do automatically.