Release 0.3.1 — collections as first-class DB entity#20
Open
tylernash01 wants to merge 15 commits intomasterfrom
Open
Release 0.3.1 — collections as first-class DB entity#20tylernash01 wants to merge 15 commits intomasterfrom
tylernash01 wants to merge 15 commits intomasterfrom
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds CollectionListItem, CollectionCreate, CollectionUpdate, and CollectionDetail schemas, wiring the collection_validator into field_validator for name and description constraints. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends the list_collections endpoint to UNION skill-derived collection names with explicitly-created empty collections from the collections table, and adds a description field to every response item. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds POST /v1/collections to create empty named collections with duplicate detection (409 COLLECTION_EXISTS) and whitespace trimming via Pydantic validator. Fixes error key in duplicate test (detail→error) to match codebase's global exception handler format. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Returns 409 COLLECTION_IN_USE if any skill still references the collection, 404 COLLECTION_NOT_FOUND for missing collections, 204 on success. Includes three new integration tests covering all three branches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace deriveCollections(skills) with deriveCollectionsFromApi(skills, apiCollections) on the /collections page; on first load, migrate any lingering localStorage-meta entries to the API and remove them on success. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace synchronous getAllCollections with async version that fetches from the API (offline fallback: localStorage meta). Creating a new collection via the __create__ sentinel now POSTs to the API first, falling back to persistCollection when offline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
db.refresh(col) after commit was failing intermittently with 'Could not refresh instance' once the API container had been running for a while — a stale-session/connection-pool interaction. Explicit re-query is deterministic and idiomatic. Verified with a 50-cycle POST/PUT/DELETE stress test on a long-running container.
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
skillnote-pick) at session start/collectionsRoot cause
The CLI picker fetches
/v1/collections, which was implemented asSELECT unnest(collections) FROM skills ... GROUP BY name— a collection only surfaced once ≥1 skill referenced it.NewCollectionModalwrote only to browser localStorage, so newly-created empty collections were invisible to the CLI picker. Adding one skill would suddenly make the collection appear.What changed
Backend (9 commits):
0011_collections_table: newcollectionstable keyed byname, withdescription+ timestampsCollectionSQLAlchemy model +CollectionCreate/Update/Detail/ListItemPydantic schemasvalidate_collection_name— free-form text (to preserve"lp assessment"), max 128 chars, non-empty, no newlines/XMLGET /v1/collectionsnow UNIONs skill-derived names with empty rows from the table; response gains an additivedescriptionfield (CLI keeps working)POST /v1/collections(409 on duplicate),PUT /v1/collections/{name}(description-only; no rename in 0.3.1),DELETE /v1/collections/{name}(409 if any skill still references it)db.refresh(col)after commit with explicit re-query —db.refreshfails intermittently under connection-pool reuse (same latent pattern exists inskills.py:318, out of scope)Frontend (4 commits):
src/lib/api/collections.ts— typed API clientNewCollectionModalPOSTs to the API, falling back to localStorage + error toast on network failure/collectionspage reads from the API and auto-migrates staleskillnote:collections-metaentries (POST missing ones, then clear on success; retry next page load on partial failure)CollectionPicker(skill editor) fetches from the API with localStorage fallbackTest plan
pytest tests/unit/test_collection_validator.py— 8/8 passingpytest tests/integration/test_collections_api.py— 11/11 passing (covers shape, POST + dup + validation + whitespace, PUT + 404, DELETE + 404 + 409 skill-ref)db.refreshfixcount: 0, description→ CLI picker'sfetch_collections()sees it → DELETE returns 204npx tsc --noEmit— no new errors in `src/` (pre-existing `cli/` errors unrelated)Notes
🤖 Generated with Claude Code