Cold-storage audit: eight projects (net10.0), dual-database, streaming playback. DOC_PLAN.md briefs doc-keeper on eight folder-level CLAUDE.mds to write or rewrite; Services libraries are the biggest gap.
26 KiB
DOC_PLAN.md — Folder-level CLAUDE.md plan
Brief for doc-keeper. Specifies, folder by folder, what each CLAUDE.md should cover and the conventions/patterns to surface. Authored on a cold-storage read of the current code state on 2026-05-16. See CONTEXT.md for the full architecture orientation.
Ground rules for every folder-level CLAUDE.md
These apply across the whole sweep — do not restate them inside each file unless the local context genuinely differs.
- Target framework is
net10.0for every project. Do not write ".NET 9" anywhere. Package versions are10.0.1family across EF Core, ASP.NET, and Extensions; MudBlazor is8.15.0; NUnit is4.4.0. - Lead with what's true now, not what's aspirational. Folder CLAUDE.md files are operational guidance for an agent walking into that directory cold. If something is "potential future usage", omit it.
- Cross-reference the root. Root
CLAUDE.mdalready explains the solution shape, dual-database model, and high-level patterns. Folder CLAUDE.mds should pick up from there and document what makes that folder specific. No re-running the full architecture overview in every file. - No CLAUDE.md in build output / migrations / leaf static-asset folders. This plan is deliberately scoped to the subfolders below; do not add files for
obj/,bin/,Migrations/,wwwroot/,environment/,Properties/. Migrations are EF-generated and not interesting for agent guidance. - Reference paths, not contents, for code. If the CLAUDE.md needs to show how something is used, prefer a one-line "see
path/file.cs" over a copied 30-line snippet. The code is the source of truth — folder CLAUDE.mds drift the moment they replicate it. Small inline examples (a 3–5 line signature or call) are fine when the call shape itself is the convention being documented. - The eight existing folder CLAUDE.mds need rewrites, not patches. All eight contain framework-version drift and most contain structural drift (see CONTEXT.md §7). Treat the existing files as raw material, not as a baseline to incrementally edit.
Files to write / rewrite
There are eight folder CLAUDE.mds in scope. Five already exist and need rewrites; three are new (the two *.Services libraries and a recommendation about the FileDatabase README being either retired or replaced with a CLAUDE.md).
| Folder | Status | Priority |
|---|---|---|
DeepDrftWeb/ |
Rewrite — structural drift | high |
DeepDrftWeb.Client/ |
Rewrite — major drift (page list, player stack) | high |
DeepDrftWeb.Services/ |
New — no CLAUDE.md exists; domain logic lives here | high |
DeepDrftContent/ |
Rewrite — FileDatabase tree has moved out | high |
DeepDrftContent.Services/ |
New — no CLAUDE.md; FileDatabase + processors live here | high |
DeepDrftModels/ |
Rewrite — MediaPath→EntryKey rename, framework version |
medium |
DeepDrftCli/ |
Rewrite — config file name, GUI/CLI dual mode is mostly accurate | medium |
DeepDrftTests/ |
Rewrite — framework version, otherwise mostly accurate | low |
Plus one judgement call:
DeepDrftContent.Services/FileDatabase/README.mdis an in-tree developer README, not a CLAUDE.md. It is stale (ImageDirectoryVaultisImageVault; the.csproj (.NET 9.0)line is wrong since FileDatabase no longer has its own csproj). Recommendation: doc-keeper should ask Daniel whether to retire it in favour of aDeepDrftContent.Services/FileDatabase/CLAUDE.mdor leave it as a long-form README and just refresh the inaccuracies. Default to leaving the README and not adding a separate CLAUDE.md inside the FileDatabase subtree — the parentDeepDrftContent.Services/CLAUDE.mdshould cover what an agent needs to know to operate insideFileDatabase/.
Per-folder briefs
DeepDrftWeb/CLAUDE.md
One-line purpose: The Blazor Web App host. Owns HTTP surface (one controller + render-mode wiring), MudBlazor theme prerender, TypeScript→JS audio interop, and the SQL-side api/track/page endpoint. Domain logic lives elsewhere (DeepDrftWeb.Services).
Cover:
- What lives here now (only):
Program.cs,Startup.cs,Controllers/TrackController.cs,Services/DarkModeService.cs,Components/App.razor+Components/Pages/Error.razor,Interop/(TypeScript sources),wwwroot/(compiled JS, CSS, fonts, images). - What does not live here anymore:
DeepDrftContext,TrackRepository,TrackService,Configurations/,Migrations/. All moved toDeepDrftWeb.Services. Don't write new repositories or EF code in this project. - The render-mode model: Blazor Web App with
AddInteractiveServerComponents()+AddInteractiveWebAssemblyComponents(). The root component is<Routes @rendermode="InteractiveAuto" />fromComponents/App.razor, and the WASM render-mode loadsDeepDrftWeb.Client._Importsas an additional assembly. New routable pages should land inDeepDrftWeb.Client/Pages, not here. - The dark-mode prerender bridge:
DarkModeServicereads thedarkModecookie viaIHttpContextAccessorinApp.razor'sOnInitializedand seedsDarkModeSettings.IsDarkMode(registered inDeepDrftWeb.Client.Startup.ConfigureDomainServices). The setting carries over to WASM viaPersistentComponentState(MainLayout.razor). - The TypeScript interop pipeline: sources live in
Interop/audio/(one module per responsibility —AudioContextManager,StreamDecoder,PlaybackScheduler,SpectrumAnalyzer,AudioPlayer, plusindex.tsthat exposeswindow.DeepDrftAudio). They compile towwwroot/js/viaMicrosoft.TypeScript.MSBuild.tsconfig.jsonmust not be copied to output. In development, raw.tsis served from/Interop/for source-map debugging. - HTTP client wiring lives mostly in
DeepDrftWeb.Client.Startup. Server-sideProgram.csonly adds MudBlazor, controllers, render-mode components, SignalR tuning, forwarded-headers config, and calls the client'sStartup.ConfigureApiHttpClient/ConfigureContentServices/ConfigureDomainServices. - Reverse-proxy support:
UseForwardedHeadersruns first; HTTPS redirect is conditionally disabled viaForwardedHeaders:DisableHttpsRedirectionso the app can sit behind nginx. - The one controller (
TrackController) is a thin wrapper:GET api/track/page?pageNumber&pageSize&sortColumn&sortDescending→DeepDrftWeb.Services.TrackService.GetPaged→ApiResultDto<PagedResult<TrackEntity>>. If you're adding new SQL endpoints, this is the file; if you're adding new logic, that goes inDeepDrftWeb.Services.
Do NOT include:
- Generic Blazor / EF Core tutorials.
- Anything implying repositories or DbContext belong in this project.
- Build/run commands for the whole solution — keep those at the root.
DeepDrftWeb.Client/CLAUDE.md
One-line purpose: All interactive UI for the site. Blazor WebAssembly. Pages, controls, the streaming audio player stack, theme/dark-mode plumbing, HTTP clients for both backends.
Cover:
- Actual structure:
Pages/(Home.razor,TracksView.razor),Layout/(MainLayout.razor,DeepDrftMenu.razor,NavMenu.razor,Pages.cs),Controls/(TrackCard,TracksGallery,AppNavLink,AudioPlayerProvider,AudioPlayerBar/cluster),Services/(audio player services + dark-mode services + streaming error handler),Clients/(TrackClientfor SQL API,TrackMediaClientfor content API),ViewModels/(TracksViewModel),Common/(DarkModeSettings,DDIcons). - The "old demo pages" (
Counter.razor,Weather.razor) do not exist. The site has exactly two routable pages today:/and/tracks. Nav is centralised inLayout/Pages.cs(MenuPages+AllPages). - The two HTTP clients pattern:
TrackClientuses namedIHttpClientFactoryclient"DeepDrft.API",TrackMediaClientuses"DeepDrft.Content". The clients are configured inStartup.ConfigureApiHttpClientandStartup.ConfigureContentServices— both static methods called from BOTH the serverProgram.csand the WASMProgram.csso prerender and runtime see the same DI. - The audio player stack (this is the deepest part of the project and most likely to be edited):
IPlayerService/IStreamingPlayerService(the contracts exposed to UI).AudioPlayerService(abstract base: lifecycle, initialise, select track, play/pause/stop/seek/volume).StreamingAudioPlayerService(the production implementation: chunked stream fromTrackMediaClient, adaptive 16–64 KB buffer, early-playback, seek-beyond-buffer via a new offset request).AudioInteropService(JS interop wrapper overwindow.DeepDrftAudio; managesDotNetObjectReferencelifetimes for progress, end-of-playback, and spectrum callbacks).AudioPlayerProvider.razoris the cascading host; everything inside it gets the player via[CascadingParameter].AudioPlayerBar.razoris the dock UI;SpectrumVisualizer.razoris the bar-graph driven bygetSpectrumData.MainLayout.razorwraps the layout inAudioPlayerProvider, so the player survives navigation.
- Dark mode plumbing:
DarkModeSettings(inCommon/) is[PersistentState]-annotated and registered scoped — it is the single source of truth in the client.DarkModeServiceBaseholds the cookie name constant.DarkModeCookieServicewrites the cookie via JSdocument.cookieand readsDarkModeSettings.- The server-side
DarkModeService(inDeepDrftWeb, NOT here) reads the cookie during prerender. The settings instance round-trips viaPersistentComponentState.
TracksView.razorflow: injectsTracksViewModel+ cascadedIPlayerService.SetPagecallsTrackClient.GetPageand updates the VM.PlayTrackcallsPlayerService.SelectTrack(track)— which under the hood resolves toStreamingAudioPlayerService.SelectTrackStreaming(track)and starts the chunked stream.- MVVM convention: page state lives in a
ViewModel(scoped DI), components only render and dispatch.TracksViewModelholds the current page, page size, sort. Add new VMs inViewModels/and register inStartup.ConfigureDomainServices. - Theming convention: bespoke
PaletteLight/PaletteDarklive inline inMainLayout.razor. CSS classes prefixeddeepdrft-live inDeepDrftWeb/wwwroot/styles/deepdrft-styles.css. Custom SVG icons live inCommon/DDIcons.cs.
Do NOT include:
Counter.razor/Weather.razorreferences.- "ASP.NET Core 9.0".
- Any claim that this project hosts a server or controllers — it is a class-libraryish WASM assembly consumed by
DeepDrftWeb.
DeepDrftWeb.Services/CLAUDE.md (new)
One-line purpose: SQL-side domain logic for tracks. EF Core context, configurations, migrations, repository, service, design-time factory. Consumed by both DeepDrftWeb and DeepDrftCli.
Cover:
- Why this project exists: separating domain from host so the CLI can reuse
TrackService/TrackRepository/DeepDrftContextwithout referencing the ASP.NET host. New SQL-side domain code goes here, not inDeepDrftWeb. - Layout:
Data/DeepDrftContext.cs,Data/DeepDrftContextFactory.cs(design-time, hard-codes../Database/deepdrft.dbfordotnet ef),Data/Configurations/TrackConfiguration.cs,Migrations/,Repositories/TrackRepository.cs,TrackService.cs. - The Controller → Service → Repository → DbContext shape. Services return
Result/ResultContainer<T>from NetBlocks; repositories throw / return raw types. Exceptions are caught at the service boundary. TrackEntityfield reality:Id,EntryKey(required, max 100, the FileDatabase entry id),TrackName(max 200),Artist(max 200),Album?(max 200),Genre?(max 100),ReleaseDate?(DateOnly),ImagePath?(max 500). Column names are snake_case. Table istrack(singular).- Pagination convention:
TrackService.GetPagedbuilds aPagingParameters<TrackEntity>with anOrderByExpression<Func<T, object>>. Switch inGetPagedmaps a string sort column to the expression. New sort columns extend this switch. Nulls sort to the end (via padded sentinel strings /DateOnly.MaxValue). - EF migration commands (run from solution root):
dotnet ef migrations add <Name> --project DeepDrftWeb.Services --startup-project DeepDrftWebanddotnet ef database update --project DeepDrftWeb.Services --startup-project DeepDrftWeb. The design-time factory means you can also rundotnet ef ... --project DeepDrftWeb.Servicesstandalone for local development. - The migrations namespace is
DeepDrftWeb.Migrations(a legacy name, retained for migration history continuity). - Connection string source:
appsettings.json→ConnectionStrings:DefaultConnectionon the web side;environment/connections.json→CliSettings:ConnectionStringon the CLI side. Both point at../Database/deepdrft.db.
Do NOT include:
- ASP.NET Core lifecycle, controllers, middleware — those are not in scope here.
- HTTP client setup or theming.
DeepDrftContent/CLAUDE.md
One-line purpose: The binary content API host. ApiKey middleware, CORS, forwarded headers. Returns audio bytes (with optional WAV-aware offset) and accepts authenticated PUTs. FileDatabase implementation lives in DeepDrftContent.Services, not here.
Cover:
- What lives here now (only):
Program.cs,Startup.cs,Controllers/TrackController.cs,Middleware/ApiKeyAuthenticationMiddleware.cs,Middleware/ApiKeyAuthorizeAttribute.cs,Models/(settings POCOs:ApiKeySettings,CorsSettings,FileDatabaseSettings),environment/filedatabase.json,environment/apikey.json(not in repo). - What does not live here anymore: any
FileDatabase/,Services/,Processors/, or media model code. All moved toDeepDrftContent.Services. Don't add new domain code in this project. - The endpoint surface (exactly two, do not add a third without product approval):
GET api/track/{trackId}?offset=0— unauthenticated, returns the WAV bytes from thetracksvault. Ifoffset > 0,WavOffsetService.CreateOffsetStreamblock-aligns the offset and synthesises a fresh 44-byte WAV header so the response is a valid standalone WAV starting from that byte position.PUT api/track/{trackId}—[ApiKeyAuthorize], acceptsAudioBinaryDto(base64 buffer + size + mime + duration + bitrate), writes viaFileDatabase.RegisterResourceAsyncinto thetracksvault.
- ApiKey middleware behaviour: only enforces on endpoints with
[ApiKeyAuthorize]metadata. Reads headerApiKey. Returns 401 with body"API Key was not provided"or"Unauthorized client". Configured viaenvironment/apikey.json(ApiKeySettings.ApiKey). - CORS:
CorsSettings.AllowedOriginsis required (the app throws on startup if missing). Policy is namedContentApiPolicy. AllowCredentials + AllowAnyMethod + AllowAnyHeader. - Forwarded headers are enabled only in
Production(this differs fromDeepDrftWebwhich enables them always — be aware when debugging proxy issues). - Startup wiring (
Startup.ConfigureDomainServices): adds singletonWavOffsetService, loadsenvironment/filedatabase.json, awaitsFileDatabase.FromAsync(VaultPath), registers it as singleton, and ensures thetracksvault exists (MediaVaultType.Audio). The vault is created on first boot, then reused. - OpenAPI is only mapped in
Development.
Do NOT include:
- The internals of how
FileDatabaseworks — that's the job ofDeepDrftContent.Services/CLAUDE.md. - A directory tree showing
FileDatabase/Services/inside this project; it is not there.
DeepDrftContent.Services/CLAUDE.md (new)
One-line purpose: Binary-content domain logic. The FileDatabase implementation, audio processing, WAV stream-with-offset, and the content-side track service. Consumed by DeepDrftContent (the host) and DeepDrftCli.
Cover:
- Layout:
FileDatabase/(the subsystem —Abstractions/,Models/,Services/,Utils/),Audio/WavOffsetService.cs,Processors/AudioProcessor.cs,Constants/VaultConstants.cs,TrackService.cs. - FileDatabase model (refer to
DeepDrftContent.Services/FileDatabase/README.mdfor the long-form rationale — it's a port of a TypeScript system):FileDatabaseis the root. Created viaFileDatabase.FromAsync(rootPath). Holds aStructuralMap<string, MediaVault>and anIndexWatcher. ImplementsIDisposable.- Each
MediaVaultis a subdirectory with its own JSONindexfile. Types:Media | Image | Audio. Concrete subclasses areImageVaultandAudioVault(the README's mention ofImageDirectoryVaultis stale — the type isImageVault). - Entry filenames:
{sanitized-key}{extension}, where sanitisation isRegex.Replace(entryKey, @"[^a-zA-Z0-9]", "-"). - Binary hierarchy:
FileBinary → MediaBinary (+ Extension, MIME viaMimeTypeExtensions) → AudioBinary (+ Duration, Bitrate) | ImageBinary (+ AspectRatio). Each has a matching*Dtofor base64 JSON transport. - Index lifecycle:
IndexFactoryServiceloads-or-createsDirectoryIndex(the root index) andVaultIndex(per-vault, recordsMediaVaultType). Saved as JSON viaFileUtils.PutObjectAsync. IndexWatcherusesFileSystemWatcherto detect external writes to a vault'sindexfile (the CLI is the typical writer) and triggersMediaVault.ReloadIndexAsyncso a long-running web host stays consistent.- Error-handling philosophy (load-bearing): public
Load*/Register*operations swallow exceptions and returnnull/falseto match the TypeScript original. Callers must check return values. Do not change this without a deliberate design pass.
- WAV offset service:
WavOffsetService.CreateOffsetStream(buffer, byteOffset)parses the WAV header, block-aligns the offset, synthesises a new 44-byte header for the remaining data, and returns[new header][data from offset]as aMemoryStream. Used by the content API to serve seek-beyond-buffer requests. Block alignment is required for clean audio — do not bypass it. - Audio processor:
AudioProcessor.ProcessWavFileAsync(filePath)validates the RIFF/WAVE/PCM structure, parses fmt and data chunks, computes duration + bitrate, falls back to defaults (180s / 1411 kbps / 44.1 kHz / 16-bit stereo) on parse failure with aConsole.WriteLinewarning. PCM-only today; other formats are unsupported. - Content-side
TrackService(orchestrator):AddTrackFromWavAsyncreads a WAV from disk, generates a GUID entry key, ensures thetracksvault exists, stores the audio, and returns a populatedTrackEntity(without saving it to SQL — caller does that).GetAudioBinaryAsyncreads it back.InitializeTracksVaultAsyncis a safety call. VaultConstants.Tracks = "tracks"— the one vault name in production use. New vault names go here.
Do NOT include:
- The HTTP surface of
DeepDrftContent— that belongs inDeepDrftContent/CLAUDE.md. - A reproduction of the FileDatabase README's full design discussion — link to it instead.
DeepDrftModels/CLAUDE.md
One-line purpose: Shared contracts. Entities, DTOs, pagination types. Every project references this; nothing else references the projects that reference this.
Cover:
- Layout:
Entities/TrackEntity.cs,DTOs/TrackDto.cs,Models/PagingParameters.cs,Models/PagedResult.cs. TrackEntityfields (verbatim from current code — replace any older field list):Id(long PK),EntryKey(required string, FileDatabase entry id),TrackName(required),Artist(required),Album?,Genre?,ReleaseDate?(DateOnly),ImagePath?. NoMediaPathfield exists.TrackDtomirrorsTrackEntity. Used only where DTO/entity separation is needed for serialisation; in practice both flow over the wire today.PagingParameters(base):Page(1-based, default 1),PageSize(default 20, capped at 100). The cap is a hard ceiling.PagingParameters<T>: addsOrderBy: Expression<Func<T, object>>?andIsDescending.Skipis computed(Page - 1) * PageSize. Type-safe sort expressions — strings only at the API boundary.PagedResult<T>:Items,TotalCount,Page,PageSize. Derived:TotalPages,HasNextPage,HasPreviousPage. IncludesPagedResult<T>.From<TOther>for cross-type mapping.- Convention: required reference fields use
requiredmodifier; optional reference fields are?. Don't relaxrequired— it's the compile-time guarantee that prevents half-built entities reaching the database. - This project also references
NetBlocksonly transitively (the actual NetBlocks types —Result,ResultContainer<T>,ApiResult<T>,ApiResultDto<T>— come into the services and clients directly).
Do NOT include:
- "Potential future usage in DeepDrftContent" — content already uses these.
- Generic C# tutorials on
requiredorExpression<T>.
DeepDrftCli/CLAUDE.md
One-line purpose: Local admin tool. Adds and lists tracks. Two modes: classic CLI (add / list / help) and a Terminal.Gui interactive interface (gui). Has direct access to both the SQL DB and the FileDatabase (it's not a network client).
Cover:
- Why this is allowed to bypass the API: it is a local single-user admin tool, run on the same machine as the databases. Browsers never get to bypass — the API is for them. Don't extend this pattern to network clients.
- Layout:
Program.cs,Services/CliService.cs,Services/GuiService.cs,Models/CliSettings.cs,environment/connections.json(the actual config file — notappsettings.json). CliSettings:ConnectionString(SQLite path) +VaultPath(FileDatabase root). Loaded fromenvironment/connections.jsonresolved againstAppDomain.CurrentDomain.BaseDirectory.environment/config.jsonis also copied to output but currently unused — leave it as a placeholder.- DI wiring (
Program.cs):DeepDrftContext(SQLite),FileDatabase(singleton viaFromAsync, blocking on init),TrackRepository,DeepDrftWeb.Services.TrackService,AudioProcessor,DeepDrftContent.Services.TrackService,CliService,GuiService. Logging is console-only. - Mode dispatch:
gui/--guirunsGuiService.RunAsync; everything else runsCliService.RunAsync(args). - CLI commands:
add <wav-file> <track-name> <artist> [album] [genre] [release-date]— classic positional.add <wav-file> -i|--interactive [...defaults]— interactive prompts, command-line args become defaults.list— formatted table.help/--help/-h.
- GUI mode: Terminal.Gui application with a custom dark/brand colour scheme, list of tracks, status pane, persistent hotkey legend, and an add-track dialog.
- Dual-database flow for
add(this is the critical contract — do not skip):DeepDrftContent.Services.TrackService.AddTrackFromWavAsyncprocesses the WAV, generates an entry GUID, stores audio in thetracksvault, returns a populatedTrackEntity(not yet saved to SQL).DeepDrftWeb.Services.TrackService.Createsaves the entity to SQLite and returns the persisted version withIdassigned.- If step 1 succeeds and step 2 fails, the audio is orphaned in the vault. There is no compensating rollback today — flag this if it comes up in planning.
- Publishing:
PublishSingleFile=true.SelfContainedandIncludeNativeLibrariesForSelfExtractare commented out — current publish is framework-dependent single file. - Release date format is
YYYY-MM-DD. Only.wavis accepted.
Do NOT include:
- Any claim that
appsettings.jsonis the config file. - Coverage of all GuiService implementation details — just the entry point and that it exists.
DeepDrftTests/CLAUDE.md
One-line purpose: NUnit test project. Covers the FileDatabase subsystem end-to-end (the only piece of the codebase with non-trivial test coverage). References DeepDrftContent.Services.
Cover:
- Layout: one test class per subsystem area —
FileDatabaseTests,MediaVaultTests,MediaVaultFactoryTests,IndexSystemTests,SimpleMediaTypeRegistryTests,UtilityTests,ModelTests.TestData.csholds shared fixtures (a real 16x16 PNG byte buffer; factory helpers forImageBinary/AudioBinary; named constants underTestKeys/TestFiles).environment/filedatabase.jsonis a test-config file copied at build. - Test isolation pattern (used by
FileDatabaseTestsand others): each test creates a unique directory underPath.GetTempPath() + "DeepDrftTests/{Guid}"in[SetUp]and best-effort deletes it in[TearDown]. New tests touching the filesystem must follow this pattern — do not write into the realDatabase/Vaultspath. - The tests are the load-bearing documentation of the FileDatabase's behaviour. When changing FileDatabase semantics (especially the swallow-and-return-null contract, the entry-key sanitisation regex, the vault-type round-trip on index, or the index-watcher reload), the tests are where intent is anchored. Update them in the same change.
TestData.CreateTestAudioBinarydeliberately reuses PNG bytes as a mock audio buffer — the FileDatabase does not parse audio content, so any byte buffer with valid metadata round-trips correctly. Real WAV parsing is exercised by the CLI / content host, not the FileDatabase tests.- Run commands:
- All:
dotnet test DeepDrftTests/. - One class:
dotnet test DeepDrftTests/ --filter "ClassName=FileDatabaseTests". - One method:
dotnet test DeepDrftTests/ --filter "Name=FileDatabase_CanBeCreatedAtSpecifiedLocation".
- All:
- What is NOT tested (be honest):
TrackService(Web or Content),TrackController(Web or Content),TrackClient/TrackMediaClient, the audio player services, the dark-mode round-trip, the WAV offset service, the audio processor. Any planned work in those areas should consider whether tests need to land alongside.
Do NOT include:
- A claim that the test suite has "comprehensive coverage". It is comprehensive for FileDatabase and not present elsewhere.
- Code coverage instructions if they are not in active use — only document the commands actually run.
Order of operations for doc-keeper
- Rewrite
DeepDrftWeb/CLAUDE.mdandDeepDrftWeb.Client/CLAUDE.mdfirst — they are the most-touched directories during ongoing UI work and have the highest drift. - Create
DeepDrftWeb.Services/CLAUDE.mdandDeepDrftContent.Services/CLAUDE.md— these are the biggest content gaps (no docs exist; most domain logic lives there). - Rewrite
DeepDrftContent/CLAUDE.md— high drift, but the surface is small. - Rewrite
DeepDrftModels/CLAUDE.md— small file, but theMediaPath→EntryKeycorrection matters everywhere it's wrong. - Rewrite
DeepDrftCli/CLAUDE.mdandDeepDrftTests/CLAUDE.md— lower priority; mostly polish + framework version. - Pause and check in with Daniel about
DeepDrftContent.Services/FileDatabase/README.md— retire, keep, or replace.