Expose createdById/updatedById in the query layer - #70
Merged
Merged
Conversation
Found during v0.5.1 post-deploy verification: created_by_id is correctly backfilled in the database, but no GET/LIST query or MCP tool response ever projected it out — only raw mutation responses (create_*/update_*, which return the inserted/updated row directly) happened to show it. Confirmed live against production: list_code_plans and get_code_plan never showed it despite the column being populated. Adds a shared Attribution interface (createdById/createdByKind/ updatedById/updatedByKind) to CodePlan, Release, Task, and WorkItem, and threads the columns through the corresponding lib/db/queries.ts projections (getCodePlans/getCodePlan, getTasks, getReleases/getRelease, getWorkItems/getWorkItem, and the task list nested inside getCodePlan). Since the MCP tools return these same query-layer objects directly, this fixes both the UI and MCP consumers in one place — no route.ts changes needed. Deliberately keeps this to raw IDs, matching what was asked, rather than resolving to display names — lib/db/wiki.ts already has a working precedent (batch users lookup + fallback to legacy creator/reporter fields) if that's wanted as a follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZM1Fxzj2sqge7EyGQ8LXb
4 tasks
SylonZero
added this pull request to stack #72
September 12, 2026 23:20
SylonZero
pushed a commit
that referenced
this pull request
Sep 12, 2026
… PR #70 Assets get the same soft-delete tombstone treatment agreed for Product: archivedAt/archivedById/archivedByKind, kept deliberately separate from the existing operational health/status enum. Archiving hides an asset from listing/picker views but never nulls out or unlinks anything that references it — work items, tasks, dependency edges, and plan/release links keep working, matching the "no surprise cascades" rule from the Deletion & Cascade Design spec. - lib/db/authz.ts: canDeleteAsset — org owner/admin, the creator, or a declared asset owner (assetOwners), same shared-policy pattern as the other canDelete* checks. - lib/db/mutations.ts: archiveAsset/restoreAsset, both audit-logged. deleteAsset kept for a possible future admin-only purge, no longer on the normal UI/MCP path. - MCP: archive_asset/restore_asset tools disclose reference counts (work items, tasks, dependency edges, plan targets, release stamps) without claiming anything was touched. - UI: product page's asset editor swaps the delete confirmation for an archive one with accurate, non-destructive copy, plus a collapsible "archived assets" section with a restore action. getProduct now returns archived assets too (previously filtered) so that section has something to show. - Query layer: ~10 listing functions now exclude archived assets (isNull(assets.archivedAt)); detail/history views deliberately don't, so an archived asset is still viewable directly. - Also fixes a real (if inert) type-check regression from PR #70: Release gained required Attribution fields but tests/lib/ai.test.ts's fixture literal wasn't updated. tsc --noEmit is clean of anything this session touched; the two remaining errors (passwordHash, CodePlan.productName) predate this work. Tests: 13 new (6 authz, 7 mutations) — 287/287 passing. tsc --noEmit and pnpm build verified. Migration hand-written for Postgres (drizzle-kit generate needs an interactive TTY not available here) and drizzle-kit generate for SQLite; both verified against a real populated local dev DB. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZM1Fxzj2sqge7EyGQ8LXb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Small follow-up from v0.5.1's post-deploy verification:
created_by_idis correctly backfilled in the database, but nothing ever surfaced it through a GET/LIST query or MCP tool — confirmed live against production, wherelist_code_plans/get_code_plannever showed it despite the column being populated (only raw mutation responses did, since those return the row directly).Attributioninterface (createdById/createdByKind/updatedById/updatedByKind) onCodePlan,Release,Task,WorkItem.getCodePlans/getCodePlan(including the nested task list),getTasks,getReleases/getRelease,getWorkItems/getWorkItem.route.tschanges needed.Deliberately kept to raw IDs (not resolved to display names), matching what was asked.
lib/db/wiki.tsalready has a working precedent (batchuserslookup + fallback to legacycreatorId/reporterId) if name resolution is wanted later.Test plan
queries.test.ts,releases.test.ts,work-items.test.ts— verifying both the null case (unattributed fixture rows) and the populated case (created through the normal mutation path)pnpm exec tsc --noEmit— no new errorspnpm test— 274/274 passingpnpm build— succeeds🤖 Generated with Claude Code
https://claude.ai/code/session_016ZM1Fxzj2sqge7EyGQ8LXb