internal static partial class Program { private static async Task Main() { var tests = new List<(string Name, Func Run)> { ("CreateAsync trims fields", TestCreateTrimsAsync), ("UpdateAsync accepts valid type updates", TestUpdateAcceptsTypeAsync), ("UpdateAsync rejects whitespace type", TestUpdateRejectsWhitespaceTypeAsync), ("JournalEntry model stores parity fields", TestJournalEntryModelAsync), ("MergeWith overwrites section when new content is meaningful", TestMergeOverwritesMeaningfulSectionAsync), ("MergeWith ignores whitespace-only section updates", TestMergeIgnoresWhitespaceOnlySectionAsync), ("MergeWith appends non-duplicate fragments by description", TestMergeAppendsNonDuplicateFragmentsAsync), ("ToMarkdown writes canonical section order", TestToMarkdownCanonicalSectionOrderAsync), ("ToMarkdown writes fragment blocks", TestToMarkdownFragmentFormattingAsync), ("Vault crypto roundtrip preserves data and layout", TestVaultCryptoRoundtripAsync), ("Vault crypto decrypts Python payload fixture", TestVaultCryptoDecryptsPythonFixtureAsync), ("Vault key derivation matches Python fixture", TestVaultKeyDerivationMatchesPythonAsync), ("Vault monthly filename matches parity format", TestVaultMonthlyFilenameParityAsync), ("Vault load clears workspace and extracts decrypted files", TestVaultLoadClearsAndExtractsAsync), ("Vault load wrong password does not modify vault files", TestVaultLoadWrongPasswordPreservesVaultAsync), ("Vault load ignores and removes legacy _init_vault.vault", TestVaultLoadLegacyInitVaultHandlingAsync), ("Vault current-month save writes only current month and skips unchanged state", TestVaultCurrentMonthSaveOptimizedAsync), ("Vault rebuild saves grouped monthly archives from decrypted files", TestVaultRebuildAllVaultsAsync), ("Vault clear data directory removes decrypted workspace artifacts", TestVaultClearDataDirectoryAsync), ("Parser extracts date from **Date:** marker", TestParserExtractsBoldDateAsync), ("Parser extracts date from Date: marker", TestParserExtractsPlainDateAsync), ("Parser falls back to file stem when date missing", TestParserFallsBackToFileStemAsync), ("Parser captures canonical sections and content", TestParserCapturesSectionsAsync), ("Parser ignores non-canonical section headers", TestParserIgnoresNonCanonicalHeadersAsync), ("Parser captures checkbox states per section", TestParserCapturesCheckboxStatesAsync), ("Parser captures multiline fragment blocks", TestParserCapturesMultilineFragmentsAsync), ("Parser fragment boundary follows header lines", TestParserFragmentBoundaryBehaviorAsync), ("File repository persists fragments", TestFileRepositoryPersistsAsync), ("Entry invalid JSON returns error envelope", TestEntryInvalidJsonAsync), ("Entry unknown action returns error envelope", TestEntryUnknownActionAsync), ("Entry get missing id returns ok with null data", TestEntryGetMissingReturnsNullDataAsync), ("Entry create without payload returns error envelope", TestEntryCreateMissingPayloadAsync), ("Entry entries.save writes and merges content", TestEntryEntriesSaveMergeAsync), ("Entry entries.load returns raw content payload", TestEntryEntriesLoadAsync), ("Entry entries.list returns markdown files", TestEntryEntriesListAsync), ("Entry templates CRUD stores .template.md and entries.list excludes templates", TestEntryTemplatesCrudExcludesFromEntriesListAsync), ("Entry search.entries matches query against full raw content", TestEntrySearchEntriesMatchesRawContentAsync), ("Entry search.entries without query returns all markdown entries", TestEntrySearchEntriesWithoutQueryReturnsAllAsync), ("Entry search.entries applies date range filter", TestEntrySearchEntriesDateRangeFilterAsync), ("Entry search.entries applies section-scoped query filter", TestEntrySearchEntriesSectionFilterAsync), ("Entry search.entries applies fragment tag and type filters", TestEntrySearchEntriesTagTypeFilterAsync), ("Entry search.entries applies checkbox checked and unchecked filters", TestEntrySearchEntriesCheckboxFilterAsync), ("Entry search.entries rejects invalid date filter format", TestEntrySearchEntriesRejectsInvalidDateAsync), ("Database key derivation matches Python fixture", TestDatabaseKeyDerivationMatchesPythonAsync), ("Database schema parity tables are created", TestDatabaseSchemaParityAsync), ("Entry db.status returns database compatibility payload", TestEntryDatabaseStatusAsync), ("Entry db.initialize_schema creates schema in data directory", TestEntryDatabaseInitializeSchemaAsync), ("Entry db.hydrate_workspace returns hydration metadata", TestEntryDatabaseHydrateWorkspaceAsync), ("Config service exposes parity path, vault, AI, and speech settings", TestConfigServiceParityKeysAsync), ("Entry config.get returns config payload", TestEntryConfigGetAsync), ("Log redactor scrubs sensitive payload fields", TestLogRedactorScrubsSensitiveFieldsAsync), ("Log redactor preserves non-sensitive payload fields", TestLogRedactorPreservesNonSensitiveFieldsAsync), ("Entry ai.health returns disabled by default", TestEntryAiHealthDefaultAsync), ("Entry ai.summarize_entry succeeds when disabled", TestEntryAiSummarizeEntryDisabledAsync), ("Entry ai.summarize_all succeeds when disabled", TestEntryAiSummarizeAllDisabledAsync), ("Entry ai.chat succeeds when disabled", TestEntryAiChatDisabledAsync), ("Entry ai.embed returns empty vector when disabled", TestEntryAiEmbedDisabledAsync), ("Entry speech.devices.list returns envelope when disabled", TestEntrySpeechDevicesListDisabledAsync), ("Entry speech.transcribe returns envelope when disabled", TestEntrySpeechTranscribeDisabledAsync), ("Python sidecar AI service parses last JSON line", TestPythonSidecarAiServiceJsonLineAsync), ("Python sidecar AI service surfaces sidecar errors", TestPythonSidecarAiServiceErrorAsync), ("Python sidecar speech service handles empty devices payload", TestPythonSidecarSpeechServiceNoDevicesAsync), ("Python sidecar speech service surfaces unavailable engine errors", TestPythonSidecarSpeechServiceErrorAsync), ("Python sidecar speech service times out deterministically", TestPythonSidecarSpeechServiceTimeoutAsync), ("Entry vault.load_all succeeds for empty vault directory", TestEntryVaultLoadAllEmptyAsync), ("Entry vault.load_all wrong password keeps database session locked", TestEntryVaultLoadWrongPasswordKeepsSessionLockedAsync), ("Entry vault.clear_data_directory removes files", TestEntryVaultClearDataDirectoryAsync), ("Entry templates.save auto-syncs vault and survives reload", TestEntryTemplateSaveAutoSyncsVaultAsync), ("Sidecar vault CLI load succeeds with --password", TestSidecarVaultCliLoadAsync), ("Sidecar vault CLI save writes monthly vault with --password", TestSidecarVaultCliSaveAsync), ("Sidecar search CLI returns matching entries with filters", TestSidecarSearchCliFilteredAsync), ("Sidecar search CLI warns when no decrypted entries exist", TestSidecarSearchCliEmptyDataAsync), ("Transport fixtures produce stable envelopes", TestTransportFixturesAsync), ("EntrySavePayload deserializes camelCase fileName from JsonElement", TestEntrySavePayloadFileNameDeserializationAsync), ("entries.save with fileName creates custom-named file", TestEntrySaveWithFileNameAsync), ("Vault rebuild and load preserves custom-named entries", TestVaultCustomEntryRoundtripAsync), }; var passed = 0; foreach (var (name, run) in tests) { try { await run(); Console.WriteLine($"PASS {name}"); passed++; } catch (Exception ex) { Console.WriteLine($"FAIL {name}: {ex.Message}"); } } Console.WriteLine($"Summary: {passed}/{tests.Count} passed."); return passed == tests.Count ? 0 : 1; } }