Files
shared-memory/apps/web/drizzle/0002_snippets_scope.sql
T
shadowdaoandClaude Opus 4.7 5b2bf7d19d fix: address code review on merged feature set
Five high-confidence findings from the post-merge reviewer pass:

1. memory.update MCP tool description claimed "Project is upserted if it
   doesn't exist", but the handler used resolveProjectId and would error.
   Matched the description to the actual behavior (call project.identify
   first) — keeps parity with memory.write.

2. updateMemoryAction's UPDATE statement was missing the userId guard.
   The preceding scoped SELECT made it not exploitable in practice, but
   it diverged from deleteMemoryAction's pattern. Added the guard for
   defense in depth.

3. putSnippet's UPDATE statement had the same missing userId guard —
   fixed the same way.

4. MemoryUpdateInput's refine for scope='user' accepted both
   project=undefined AND project=""; the snippets refine only accepted
   undefined. Tightened MemoryUpdateInput to require undefined, matching
   the snippets rule. Web actions already coerce "" → undefined before
   parsing, so no caller is affected.

5. 0002_snippets_scope.sql created two indexes unconditionally —
   replaced with CREATE INDEX IF NOT EXISTS so re-runs after a
   drizzle-kit push won't trip.

Also adds .claude/ to .gitignore so worktree directories from
multi-agent builds aren't accidentally committed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 06:53:32 -07:00

40 lines
1.6 KiB
SQL

-- Snippets gain scope/project mirroring memories.
--
-- Phase 1 created `snippets` as a flat per-user table. To make snippets
-- behave like memories (user-scope = global, project-scope = tied to a
-- repo) we add the same three columns: scope, project_id, deleted_at.
--
-- Uniqueness of `name` is enforced WITHIN a scope:
-- - within (user_id) for user-scope rows
-- - within (user_id, project_id) for project-scope rows
-- Soft-deleted rows are excluded from uniqueness so a name can be reused
-- after deletion.
ALTER TABLE "snippets"
ADD COLUMN "scope" memory_scope NOT NULL DEFAULT 'user',
ADD COLUMN "project_id" uuid REFERENCES "projects"("id") ON DELETE SET NULL,
ADD COLUMN "deleted_at" timestamptz;
-- Scope/project_id consistency mirrors memories_scope_project_chk.
ALTER TABLE "snippets"
ADD CONSTRAINT "snippets_scope_project_chk"
CHECK (
(scope = 'project' AND project_id IS NOT NULL)
OR (scope = 'user' AND project_id IS NULL)
);
-- Drop the old global per-user uniqueness; replace with two partial
-- unique indexes scoped to live (non-deleted) rows.
DROP INDEX IF EXISTS "snippets_user_name_uq";
CREATE UNIQUE INDEX "snippets_user_name_user_scope_uq"
ON "snippets" ("user_id", "name")
WHERE scope = 'user' AND deleted_at IS NULL;
CREATE UNIQUE INDEX "snippets_user_project_name_uq"
ON "snippets" ("user_id", "project_id", "name")
WHERE scope = 'project' AND deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS "snippets_user_idx" ON "snippets" ("user_id");
CREATE INDEX IF NOT EXISTS "snippets_project_idx" ON "snippets" ("project_id");