Warden plan

17 - wiki-type ghost retirement (issue #306, batch v11-batch)

← eval suite index


tier: needs-postgres requires: []


17 - wiki-type ghost retirement (issue #306, batch v11-batch)

What it proves

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.

Prerequisites

Step 1: the seven ghosts are gone from disk and from every exhaustive map (static)

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

Step 2: zero live data on a retired type + the committed refusal dbtests (live DB)

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

Shape (a note for the next author)

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: