feat(import): csv type column and artist-less rows - #443
Conversation
CSV imports accept an optional Type column (blank keeps the stored type, invalid values fail parsing) and keep named artist-less rows, matching them by name + date/stage against 0-artist sets only so workshops survive re-imports. The diff review lists type chips for verification before commit. Closes #433 Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
Review follow-ups: both edge functions validate against a shared _shared/setTypes.ts vocabulary, the client payload schema uses the SET_TYPES enum instead of raw strings, and update rows in the diff review show stored → incoming type chips so type changes are verifiable. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Deploy →
|
There was a problem hiding this comment.
🟡 Changes recommended
It includes an unrelated handoff doc and a few type/contract narrowings should be fixed to keep the schedule diff/commit pipeline consistently typed.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds support for importing and committing non-music “set types” and artist-less schedule rows (e.g. workshops) across the CSV parse → diff preview → commit pipeline, including UI diff chips to verify type changes before committing.
Changes:
- Accepts optional
TypeCSV column (validated against known set types) and carries it through to the commit payload with “blank preserves stored / explicit overwrites” semantics. - Allows importing and re-matching named artist-less rows by name + date/stage against existing 0-artist sets only (avoiding roster/artist-less cross-matches).
- Enhances diff review UI to show stored → incoming type chips for explicit type rows.
File summaries
| File | Description |
|---|---|
| supabase/migrations/20260827210000_commit_schedule_set_type.sql | Updates commit RPC helpers to support writing sets.set_type and syncing empty artist rosters safely. |
| supabase/functions/diff-schedule/types.ts | Extends diff function types to include set_type and track previousSetType for review UI. |
| supabase/functions/diff-schedule/resolvers.ts | Adds separate indexing for artist-less sets to ensure correct matching behavior. |
| supabase/functions/diff-schedule/resolvers.test.ts | Updates test fixtures to include set_type on sets. |
| supabase/functions/diff-schedule/index.ts | Validates incoming CSV rows for optional setType and selects set_type from DB. |
| supabase/functions/diff-schedule/computeDiff.ts | Computes payload name + setType, and switches matching logic for artist-less rows. |
| supabase/functions/diff-schedule/computeDiff.test.ts | Adds unit tests covering type payload behavior + artist-less matching semantics. |
| supabase/functions/commit-schedule/index.ts | Validates commit payloads for setType and allows empty artistSlugs. |
| supabase/functions/commit-schedule/commit-schedule.test.ts | Adds integration tests for artist-less typed set creation and overwrite/preserve semantics. |
| supabase/functions/_shared/setTypes.ts | Introduces shared SET_TYPES/SetType for edge functions. |
| src/services/scheduleImport/types.ts | Extends client schemas/types for setType and previousSetType in diff results. |
| src/services/scheduleImport/parseCsv.ts | Parses Type column, retains named artist-less rows, and validates sluggability of set names. |
| src/services/scheduleImport/parseCsv.test.ts | Adds tests for type parsing, artist-less row retention, and invalid inputs. |
| src/services/scheduleImport/buildCommitPayload.test.ts | Ensures setType + empty rosters flow through to commit payloads. |
| src/components/Admin/ScheduleImport/TypedSetsPanel.tsx | Adds a diff-review panel rendering type chips (stored → incoming) for typed rows. |
| src/components/Admin/ScheduleImport/DiffReviewStep.tsx | Wires the typed-sets panel into the diff review step. |
| src/components/Admin/ScheduleImport/CsvDropZone.tsx | Updates CSV instructions to mention Type and artist-less row handling. |
| docs/handoffs/link-wizard-376.md | Adds a Link Wizard handoff doc (appears unrelated to this PR’s scope). |
Review details
Suppressed comments (1)
src/components/Admin/ScheduleImport/TypedSetsPanel.tsx:71
- Using
<typeLabel.icon />is inconsistent with the established pattern elsewhere in the codebase (e.g.src/components/SetTypePlaceholder.tsx:15-25destructuresiconintoIconand renders<Icon />). Switching to the same pattern improves readability and avoids any JSX member-expression edge cases.
function SetTypeChip({ setType }: { setType: string | null }) {
const typeLabel = getSetTypeLabel(setType);
return (
<Badge variant="secondary" className="gap-1 shrink-0">
<typeLabel.icon className={`h-3 w-3 ${typeLabel.color}`} />
- Files reviewed: 18/18 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Playwright test resultsDetails
|
There was a problem hiding this comment.
🟡 Changes recommended
Artist-less matching can select the wrong dated set, ignored rows can fail type validation, and an unrelated handoff is included.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
docs/handoffs/link-wizard-376.md:5
- This handoff documents issue #376's Link Wizard work and is unrelated to this PR's #433 schedule-import scope. It also contains stale branch, path, and session instructions; remove this file from the PR.
# Handoff: Link Wizard Enhancements (Issue #376)
## Focus for next session
Run the `prototype` skill to settle the one open structural question (Q13 below: desktop layout with artist list moved to the left side), then continue/finish the `grilling` design session and move into `domain-modeling` if needed. This is a **continuation of an in-progress `/grill-with-docs 376` session** — the grilling interview is functionally done (all decisions settled except the prototype), do not restart it from scratch.
- Files reviewed: 18/18 changed files
- Comments generated: 3
- Review effort level: Balanced
Drop the unrelated link-wizard handoff doc, validate the Type column only on rows the import keeps, narrow set-matching by stage and date together so same-name artist-less sets on different dates update the right row, and type setType/previousSetType as SetType | null across the diff contract. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
There was a problem hiding this comment.
🟡 Changes recommended
Artist-less matching can select and update the wrong existing set when date or stage discriminators do not resolve exactly.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
supabase/functions/diff-schedule/computeDiff.ts:47
- Artist-less identity now depends on stage, but stage mismatches reach
findMatchingSetwith anullid (applyStageResolutionreturnsnullfor mismatches). If two zero-artist sets share a name/date on different stages, a CSV value such asMainstagecan therefore select an arbitrary set before the user maps it toMain Stage; the later commit-payload mapping only changesstageNameand cannot correct the chosen set id. Stage-sensitive matching must incorporate the user's mismatch resolution (or defer selecting the set until that resolution is known).
row.artists.length === 0
? (indexes.artistlessSetsByNameLower.get(name.toLowerCase()) ?? [])
: (indexes.setsByArtistKey.get(artistKey(artistSlugs)) ?? []);
- Files reviewed: 17/17 changed files
- Comments generated: 1
- Review effort level: Balanced
An artist-less row's supplied date or stage now excludes stored sets that contradict it, so a same-name set on another day becomes a create instead of overwriting the wrong set. Roster-based matching keeps its fuzzy narrowing; stored sets without a time or stage still match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
Function- and type-level explanations become JSDoc so they surface on hover; the collectNewArtists comment restated its name and is removed. Mid-function constraint notes stay as line comments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
The panel only reads setsToCreate/setsToUpdate, so it takes those instead of the whole diff result. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
Comments that predate this branch go back to line comments (and the removed collectNewArtists one returns), so the PR diff only touches comments it introduced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
…urpose-first resolver docs computeDiff.test.ts had grown past 700 lines; the artist-less matching tests now live in computeDiff.artistless.test.ts with shared fixtures in fixtures.ts. Resolver JSDoc rewritten to state what each function is for rather than how it works. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved fuzzy-stage selection can update the wrong artist-less set after the reviewer chooses a different stage resolution.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
CONTEXT.md:44
CONTEXT.mdis the domain glossary, but these definitions embed the schedule-import matching algorithm and duplicate ADR-0008. Keeping implementation rules here makes the glossary definitions long and creates another source that can drift; leave the terms domain-only and keep matching behavior in the ADR/import documentation.
The artists on a single **set** — one, or several for a B2B. Per-set, where **lineup** is per-edition. A set's roster is its import identity: schedule re-imports match a roster set by its artists (order-insensitive), not by its name. See ADR-0008.
_Avoid_: Lineup (that's the whole edition), billing
**Artist-less set**:
A **set** with an empty **roster** (e.g. a fire show or an unhosted workshop). Its import identity is its name plus date/stage, unlike a roster set, which is identified by its artists — so adding an artist to a set changes how re-imports match it. See ADR-0008.
supabase/functions/diff-schedule/resolvers.ts:162
- Artist-less matching selects a set using the fuzzy match's closest stage before the user resolves that mismatch. If the reviewer maps the CSV stage to another existing stage—or chooses to create it—the commit still updates the set chosen for the closest stage and only rewrites
stageName, so the wrong set can be moved/overwritten while the intended set remains orphaned. Defer artist-less selection until the stage resolution is known, or carry enough candidate information to recompute the match from the chosen resolution.
const stageSupplied = context.stage.kind !== "none";
const stageId = provisionalStageId(context.stage);
const pool = candidates.filter((s) => {
- Files reviewed: 23/23 changed files
- Comments generated: 1
- Review effort level: Balanced
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Playwright test resultsDetails
Failed testsMobile Chrome › set-form-type.spec.ts › Admin set form: set types › creates a workshop with no artists via the form |
Schedule import handles typed lineups (#433): an optional
TypeCSV column is validated, named artist-less rows import and re-match by name + date/stage against 0-artist sets only, an explicit type overwrites while a blank preserves, and the diff review shows stored → incoming type chips.Closes #433
Verification
Typecolumn (e.g.workshop); the diff review lists the set with a type chip, and after commit the set carries that type.Set Namebut no artists; it imports, and re-importing the same CSV updates it instead of duplicating it.Typecell blank; the stored type is kept. Re-import with a different type; the chips show stored → incoming and commit overwrites it.concert); parsing fails with an error naming the value.🤖 Generated with Claude Code
https://claude.ai/code/session_01TL2F1n6R7dmSfQiMbornRG
Generated by Claude Code