VS Code Copilot and Visual Studio Copilot both needed concrete providers because their source identity is richer than a plain parser callback. VS Code needs workspace and global chat discovery with .jsonl preference, while Visual Studio needs virtual per-conversation trace sources with sibling-aware freshness.
The providers preserve raw and full ID lookup, watch classification, source hashing, VS Code project hints, Visual Studio physical trace fan-out, strict composite trace fingerprints, force-replace parse semantics, and parser output normalization.
fix(parser): classify copilot ide source changes
The Copilot IDE providers advertised changed-path classification, but the initial migration only accepted source paths that still existed. That dropped deletion and metadata-only events before the sync layer could make a refresh or removal decision.
Classify syntactically valid removed VS Code chat files and Visual Studio trace files, fan workspace.json changes out to current workspace chat sessions, and cover Visual Studio physical trace fan-out with multiple conversations.
fix(parser): include vscode workspace metadata freshness
VS Code Copilot project names come from workspace.json, so classifying manifest writes is not enough if the source fingerprint still only reflects the chat transcript. An unchanged chat file could skip the parse that refreshes Session.Project.
Fold workspace.json size, mtime, and content hash into workspace chat fingerprints while leaving global chat fingerprints unchanged, and cover metadata-only freshness in the provider tests.
fix(sync): refresh vscode copilot workspace metadata
VS Code Copilot was provider-aware for workspace.json freshness, but this stack still runs legacy sync writes. Without mirroring that freshness in the legacy process path, metadata-only workspace renames could be classified but then skipped against the unchanged chat transcript.
Move the Copilot IDE providers into shadow compare on their migration branch, preserve .jsonl priority during provider changed-path classification, and store composite workspace freshness for VS Code Copilot sessions while both shapes run.
Validation: go test -tags "fts5" ./internal/sync -run 'TestSyncPathsVSCodeCopilot(JSONLPriority|WorkspaceMetadataRefreshesProject)' -count=1; go test -tags "fts5" ./internal/parser -run 'Test(VSCodeCopilotProvider|VisualStudioCopilotProvider|ProviderMigrationModes)' -count=1; go test -tags "fts5" ./internal/sync -count=1; go test -tags "fts5" ./internal/parser -count=1; go vet ./...; git diff --check
test(sync): compare copilot ide shadow parity
VS Code Copilot and Visual Studio Copilot are already opted into shadow comparison on this branch, but provider method tests alone do not prove the migration path still matches the legacy parser output consumed by sync.
Cover the workspace-backed VS Code JSONL source and Visual Studio virtual trace source through ObserveProviderSource so reviewers can see provider observation, data-version planning, and legacy parser parity in one place.
Validation: go test -tags "fts5" ./internal/parser ./internal/sync -run 'TestObserveProviderSourceMatches(VSCodeCopilot|VisualStudioCopilot)LegacyParser|TestCopilotIDEProvider|Test(VSCodeCopilotProvider|VisualStudioCopilotProvider)' -count=1; go test -tags "fts5" ./internal/parser ./internal/sync -count=1; go fmt ./...; go vet ./...; ./custom-gcl run --config .golangci.nilaway.yml ./internal/parser/... ./internal/sync/...; git diff --check
refactor(parser): fold copilot IDE providers
Move VSCode Copilot and Visual Studio Copilot source discovery, lookup, and
parse ownership onto their concrete providers and delete the seven legacy
package-level free functions: DiscoverVSCodeCopilotSessions,
FindVSCodeCopilotSourceFile, ParseVSCodeCopilotSession,
DiscoverVisualStudioCopilotSessions, FindVisualStudioCopilotSourceFile,
ParseVisualStudioCopilotConversation, and ParseVisualStudioCopilotVirtualPath.
VSCode Copilot: discoverSessionFiles and findSourceFile become source-set
helpers, parseSession becomes a provider method, and the shared
discoverVSCodeSessionFiles helper stays in discovery.go.
Visual Studio Copilot: discoverSessionFiles and findSourceFile become
source-set helpers (over the retained findVisualStudioCopilotTraceSourceFile
and discoverVisualStudioCopilotSessionFiles helpers), and parseConversation
becomes a provider method. The virtual-path resolution is reproduced on the
provider via the provider-neutral ParseVirtualSourcePath helper plus the
trace-file and conversation-ID predicates (splitVisualStudioCopilotVirtualPath),
replacing the deleted ParseVisualStudioCopilotVirtualPath. External callers
(session export, direct service, parsediff, engine skip-path checks) use the
new exported SplitVisualStudioCopilotVirtualPath, which wraps the same neutral
splitter. The provider's discovery now surfaces an unreadable physical trace
file as a source so the read failure is reported instead of being dropped.
Make both providers provider-authoritative and drop their legacy sync dispatch:
the classifyOnePath VSCode block, classifyVisualStudioCopilotPath and its call,
the processFile case arms, processVSCodeCopilot and its vscodeCopilot* helpers,
processVisualStudioCopilot, the vscodeJSONLSiblingExists helper, and the
now-dead legacy-preamble references to these agents.
Drop the AgentDef DiscoverFunc/FindSourceFunc hooks for both, remove both
provider files from the pending shim scan list, and replace the shadow-baseline
test with provider API coverage plus a guard asserting the legacy entrypoints
stay gone. Re-home the shared writeProviderShadowSourceFile test helper into
provider_shadow_test.go so the sync test package builds.
fix(parser): preserve copilot provider metadata
Provider-authoritative Copilot sync consumes ParseResult side channels, not only fields stored on ParsedSession. VS Code Copilot was parsing aggregate token usage but returning an empty ParseResult.UsageEvents slice, so a provider resync could erase usage rows.
Visual Studio Copilot single-session resyncs carry the stored project through Source.ProjectHint. Honoring that hint prevents the provider default from overwriting preserved project metadata, while VS Code now also carries the composite fingerprint size and mtime alongside the hash.
Validation: go test -tags "fts5" ./internal/parser -run 'Test(VSCodeCopilotProviderSourceMethods|VisualStudioCopilotProviderSourceMethods)' -count=1; go test -tags "fts5" ./internal/sync -run 'TestSyncPathsVSCodeCopilotPersistsUsageEvents|TestSyncSingleSessionContextVisualStudioCopilotPreservesProject' -count=1; go test -tags "fts5" ./internal/parser -run 'Test.*Copilot.*Provider|TestParseVSCodeCopilotSession_TokenUsage|TestParseVisualStudioCopilot' -count=1; go test -tags "fts5" ./internal/sync -run 'Test.*(VSCodeCopilot|VisualStudioCopilot).*' -count=1; go vet ./...; git diff --check
test(parser): guard visual studio copilot session fold
The Copilot IDE fold deleted ParseVisualStudioCopilotSession along with the other Visual Studio Copilot legacy entrypoints, but the regression guard did not name that symbol. Adding it prevents a future shim from reappearing unnoticed.
Validation: go test -tags "fts5" ./internal/parser -run 'TestCopilotIDEProvidersOwnLegacyEntrypoints|Test(VSCodeCopilotProviderSourceMethods|VisualStudioCopilotProviderSourceMethods)' -count=1; git diff --check
VS Code Copilot and Visual Studio Copilot now have concrete parser providers. VS Code owns workspaceStorage and globalStorage chat discovery, .jsonl-over-.json source selection, lookup, watch classification, hashing, project hints, and parse output through the existing VS Code parser. Visual Studio owns top-level trace discovery, virtual per-conversation source paths, physical trace fan-out for watcher events, strict sibling-aware trace fingerprints, lookup, hashing, force-replace parse output, and the existing Visual Studio trace parser.
This keeps both Copilot IDE formats on the shared provider interface while preserving their existing parser normalization and freshness behavior.