Skip to content

Expose createdById/updatedById in the query layer - #70

Merged
SylonZero merged 1 commit into
masterfrom
feat/expose-attribution-query-layer
Sep 12, 2026
Merged

SylonZero merged 1 commit into
masterfrom
feat/expose-attribution-query-layer

Conversation

@SylonZero

Copy link
Copy Markdown
Owner

Summary

Small follow-up from v0.5.1's post-deploy verification: created_by_id is correctly backfilled in the database, but nothing ever surfaced it through a GET/LIST query or MCP tool — confirmed live against production, where list_code_plans/get_code_plan never showed it despite the column being populated (only raw mutation responses did, since those return the row directly).

  • New shared Attribution interface (createdById/createdByKind/updatedById/updatedByKind) on CodePlan, Release, Task, WorkItem.
  • Threaded through the query projections: getCodePlans/getCodePlan (including the nested task list), getTasks, getReleases/getRelease, getWorkItems/getWorkItem.
  • Since MCP tools return these same query-layer objects directly, this fixes both surfaces at once — no route.ts changes needed.

Deliberately kept to raw IDs (not resolved to display names), matching what was asked. lib/db/wiki.ts already has a working precedent (batch users lookup + fallback to legacy creatorId/reporterId) if name resolution is wanted later.

Test plan

  • New tests in 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 errors
  • pnpm test — 274/274 passing
  • pnpm build — succeeds

🤖 Generated with Claude Code

https://claude.ai/code/session_016ZM1Fxzj2sqge7EyGQ8LXb

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
@SylonZero SylonZero mentioned this pull request Sep 12, 2026
4 tasks
@SylonZero
SylonZero added this pull request to stack #72 September 12, 2026 23:20
@SylonZero
SylonZero merged commit ba294f1 into master Sep 12, 2026
1 check passed
@SylonZero
SylonZero deleted the feat/expose-attribution-query-layer branch September 12, 2026 23:21
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
@SylonZero SylonZero mentioned this pull request Sep 12, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant