Skip to content

Project & Story context assets — slice 1: schema, models, uploader, writers#110

Merged
datashaman merged 3 commits into
mainfrom
feature/context-assets-slice-1
May 10, 2026
Merged

Project & Story context assets — slice 1: schema, models, uploader, writers#110
datashaman merged 3 commits into
mainfrom
feature/context-assets-slice-1

Conversation

@datashaman
Copy link
Copy Markdown
Owner

Summary

Lays the schema, models, storage uploader, and approval-aware writers for project- and story-scoped AI context assets. First of 5 stacked PRs implementing the project-and-story context-assets feature (plan → ADR-0015 lands in slice 7-docs).

  • context_items + context_item_story migrations (id, project/story FKs, type/title/description/metadata/summary*, soft deletes, indexes).
  • ContextItem model with bodyForContext() (summary → truncated raw fallback), Project::contextItems(), Story::ownedContextItems() / includedContextItems() / availableContextItems(). Enums + factory states (forFile/forLink/forText).
  • private disk in config/filesystems.php + context.assets.* config keys.
  • AssetUploader (ULID paths, MIME/size validation, cross-project guard).
  • ContextItemWriter and ContextItemSelector (story-scoped CRUD reopens approval, project-scoped does not, bulk-aware to avoid storms).

Slice 2 (summarisation), 3 (TasksGenerator injection), 4 (subtask context builder, opt-in), and 7-docs (ADR + AGENTS.md + CONTEXT.md) stack on top.

Test plan

  • 31 new Pest tests under tests/Feature/ContextItem/ — all green
  • Pint clean across new files
  • No regressions in pre-existing suite (16 unrelated UI/auth failures already present on main)
  • Reviewer: cross-check ADR-0015 (lands in slice 7-docs) for consistency

🤖 Generated with Claude Code

Lays the schema, models, storage uploader, and approval-aware writers for
project- and story-scoped AI context assets. Story-scoped CRUD reopens the
owning Story for approval; project-scoped CRUD does not. Selection toggling
is bulk-aware to avoid approval-reopen storms. File uploads land on a new
`private` disk; summarisation is intentionally deferred to a later slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces the first slice of “project & story context assets” by adding the underlying schema, Eloquent models/relations, and service-layer write/select/upload primitives needed to store and manage AI context items (text/link/file) at both project and story scope.

Changes:

  • Adds context_items and context_item_story tables (with soft deletes, FKs, and indexes) plus schema verification tests.
  • Adds ContextItem model + enums, and extends Project/Story with context-item relationships and query helpers.
  • Adds storage configuration (private disk + specify.context.assets.*) and service classes for uploading assets and approval-aware CRUD/selection.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Feature/ContextItem/SchemaTest.php Verifies new tables/columns exist.
tests/Feature/ContextItem/ContextItemWriterTest.php Covers writer behavior (approval reopen rules, create/update/delete semantics).
tests/Feature/ContextItem/ContextItemSelectorTest.php Covers selection toggling/bulk replacement and validation rules.
tests/Feature/ContextItem/ContextItemModelTest.php Covers scoping helpers, bodyForContext(), and relationships.
tests/Feature/ContextItem/AssetUploaderTest.php Covers upload persistence, cross-project guard, size/MIME validation.
database/migrations/2026_05_10_000001_create_context_items_table.php Creates context_items schema (scoping columns, summary fields, soft deletes, indexes).
database/migrations/2026_05_10_000002_create_context_item_story_table.php Creates pivot table for story inclusion with audit fields.
database/factories/ContextItemFactory.php Adds factory + states for text/link/file items.
config/specify.php Adds specify.context.assets.* configuration (disk, size cap, MIME allow-list, threshold).
config/filesystems.php Adds private local disk for storing context assets.
app/Services/Context/AssetUploader.php Implements file storage + ContextItem row creation.
app/Services/Context/ContextItemWriter.php Implements approval-aware create/update/delete for non-file items (and file deletion on soft delete).
app/Services/Context/ContextItemSelector.php Implements story inclusion toggling and bulk replacement behavior.
app/Models/Story.php Adds context-item relationships + available-items query helper.
app/Models/Project.php Adds project context-items relationship.
app/Models/ContextItem.php Adds the ContextItem model, casts, relationships, and prompt-body rendering logic.
app/Enums/ContextItemType.php Adds enum for context item types.
app/Enums/ContextItemSummaryStatus.php Adds enum for summary lifecycle state.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/Services/Context/AssetUploader.php
Comment thread app/Services/Context/ContextItemWriter.php
Comment thread app/Services/Context/ContextItemWriter.php
Comment thread app/Services/Context/ContextItemSelector.php
datashaman and others added 2 commits May 10, 2026 10:33
- AssetUploader records server-detected MIME (getMimeType()) instead of
  the spoofable client MIME header.
- ContextItemWriter::update refuses to mutate metadata on file-typed
  items so callers cannot retarget the underlying file via the writer.
- Defense-in-depth in deleteUnderlyingFile(): only deletes when the
  metadata-claimed disk is both registered and equals the configured
  assets disk; otherwise refuses the delete.
- ContextItemSelector::bulkSet now rejects all story-scoped IDs (not
  just cross-story ones) since the picker only owns project-scoped
  selections; story-scoped items are managed by ContextItemWriter.
  Docblock updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
"cannot be project-scoped after creation" was confusing two distinct
constraints. Spell out the actual behaviour: story-scoped items are
auto-attached at create time and ContextItemSelector refuses to
detach them via the picker; they leave the selection only on delete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@datashaman datashaman marked this pull request as ready for review May 10, 2026 08:59
@datashaman datashaman merged commit 9dd5947 into main May 10, 2026
3 checks passed
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.

2 participants