internal static partial class Program { static Task TestDatabaseKeyDerivationMatchesPythonAsync() { var service = NewDatabaseService(); var keyHex = Convert.ToHexString(service.DeriveDatabaseKey("vault-pass-123")).ToLowerInvariant(); var expected = "6a9de08e13357aa8f14e7eb0ccde119e7b4d277c60aaaca6493d9a1e1eaa5b04"; Assert(keyHex == expected, "Database key derivation should match Python PBKDF2 fixture."); return Task.CompletedTask; } static Task TestDatabaseSchemaParityAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-db-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { var service = NewDatabaseService(); var schemaPath = service.WriteSchemaBootstrap(root); var statements = service.GetSchemaStatements(); var tableNames = new HashSet(statements.Keys, StringComparer.OrdinalIgnoreCase); Assert(tableNames.Contains("entries"), "Schema should contain entries table."); Assert(tableNames.Contains("sections"), "Schema should contain sections table."); Assert(tableNames.Contains("fragments"), "Schema should contain fragments table."); Assert(tableNames.Contains("tags"), "Schema should contain tags table."); Assert(tableNames.Contains("fragment_tags"), "Schema should contain fragment_tags table."); Assert(File.Exists(schemaPath), "Schema bootstrap file should be written."); var fragmentTagsSql = statements["fragment_tags"]; Assert(fragmentTagsSql.Contains("PRIMARY KEY (fragment_id, tag_id)", StringComparison.OrdinalIgnoreCase), "fragment_tags should enforce composite primary key parity."); Assert(fragmentTagsSql.Contains("FOREIGN KEY (fragment_id) REFERENCES fragments (id)", StringComparison.OrdinalIgnoreCase), "fragment_tags should contain fragment foreign key parity."); Assert(fragmentTagsSql.Contains("FOREIGN KEY (tag_id) REFERENCES tags (id)", StringComparison.OrdinalIgnoreCase), "fragment_tags should contain tag foreign key parity."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } return Task.CompletedTask; } static async Task TestEntryDatabaseStatusAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-db-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "db.status", payload = new { password = "vault-pass-123", dataDirectory = root } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for db.status."); var data = doc.RootElement.GetProperty("data"); Assert(data.TryGetProperty("DatabasePath", out var databasePath), "Expected DatabasePath in db.status payload."); Assert(databasePath.ValueKind == JsonValueKind.String && !string.IsNullOrWhiteSpace(databasePath.GetString()), "Expected non-empty DatabasePath."); Assert(data.TryGetProperty("KeyDerivation", out var keyDerivation), "Expected KeyDerivation in db.status payload."); Assert(string.Equals(keyDerivation.GetString(), "PBKDF2-HMAC-SHA256", StringComparison.Ordinal), "Expected PBKDF2-HMAC-SHA256 key derivation."); Assert(data.TryGetProperty("SchemaTables", out var schemaTables), "Expected SchemaTables list in db.status payload."); Assert(schemaTables.ValueKind == JsonValueKind.Array && schemaTables.GetArrayLength() >= 5, "Expected schema table list in db.status payload."); Assert(data.TryGetProperty("SchemaBootstrapPath", out var schemaBootstrapPath), "Expected SchemaBootstrapPath in db.status payload."); Assert(schemaBootstrapPath.ValueKind == JsonValueKind.String && File.Exists(schemaBootstrapPath.GetString()), "Expected db.status to emit existing schema bootstrap file path."); Assert(data.TryGetProperty("RuntimeReady", out var runtimeReady), "Expected RuntimeReady in db.status payload."); Assert(runtimeReady.ValueKind == JsonValueKind.True, "Expected SQLCipher runtime-ready status in db.status payload."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntryDatabaseInitializeSchemaAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-db-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "db.initialize_schema", payload = new { password = "vault-pass-123", dataDirectory = root } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for db.initialize_schema."); var data = doc.RootElement.GetProperty("data"); Assert(data.TryGetProperty("schemaPath", out var schemaPath), "Expected schemaPath in db.initialize_schema response."); Assert(schemaPath.ValueKind == JsonValueKind.String, "Expected string schemaPath value."); var resolvedPath = schemaPath.GetString() ?? ""; Assert(File.Exists(resolvedPath), "db.initialize_schema should write schema bootstrap file."); var schemaText = File.ReadAllText(resolvedPath); Assert(schemaText.Contains("CREATE TABLE IF NOT EXISTS entries", StringComparison.OrdinalIgnoreCase), "schema bootstrap should include entries table."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static async Task TestEntryDatabaseHydrateWorkspaceAsync() { var root = Path.Combine(Path.GetTempPath(), "journal-db-smoke", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); try { File.WriteAllText(Path.Combine(root, "2026-02-20.md"), "one"); File.WriteAllText(Path.Combine(root, "2026-02-21.md"), "two"); var entry = NewEntry(); var request = JsonSerializer.Serialize(new { action = "db.hydrate_workspace", payload = new { password = "vault-pass-123", dataDirectory = root } }); var response = await entry.HandleCommandAsync(request); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for db.hydrate_workspace."); var data = doc.RootElement.GetProperty("data"); Assert(data.TryGetProperty("DatabasePath", out var databasePath), "Expected DatabasePath in hydrate payload."); Assert(databasePath.ValueKind == JsonValueKind.String && !string.IsNullOrWhiteSpace(databasePath.GetString()), "Expected non-empty DatabasePath."); Assert(data.TryGetProperty("SchemaBootstrapPath", out var schemaPath), "Expected SchemaBootstrapPath in hydrate payload."); Assert(schemaPath.ValueKind == JsonValueKind.String && File.Exists(schemaPath.GetString()), "Expected hydrate to write schema bootstrap file."); Assert(data.TryGetProperty("EntryFilesProcessed", out var filesProcessed), "Expected EntryFilesProcessed in hydrate payload."); Assert(filesProcessed.ValueKind == JsonValueKind.Number && filesProcessed.GetInt32() == 2, "Expected hydrate to count markdown files in workspace."); Assert(data.TryGetProperty("RuntimeReady", out var runtimeReady), "Expected RuntimeReady in hydrate payload."); Assert(runtimeReady.ValueKind == JsonValueKind.True, "Expected RuntimeReady=true when SQLCipher runtime hydration succeeds."); } finally { if (Directory.Exists(root)) Directory.Delete(root, recursive: true); } } static Task TestConfigServiceParityKeysAsync() { IJournalConfigService config = new JournalConfigService(); var current = config.Current; Assert(!string.IsNullOrWhiteSpace(current.ProjectRoot), "Config ProjectRoot should not be empty."); Assert(!string.IsNullOrWhiteSpace(current.AppDirectory), "Config AppDirectory should not be empty."); Assert(!string.IsNullOrWhiteSpace(current.DataDirectory), "Config DataDirectory should not be empty."); Assert(!string.IsNullOrWhiteSpace(current.VaultDirectory), "Config VaultDirectory should not be empty."); Assert(current.MonthlyVaultFormat == "%Y-%m.vault", "Config MonthlyVaultFormat should match Python format token."); Assert(current.LlamaCppUrl == "http://127.0.0.1:8085/v1/completions", "Config LlamaCppUrl default mismatch."); Assert(current.LlamaCppModel == "qwen/qwen3-4b", "Config LlamaCppModel default mismatch."); Assert(current.EmbeddingApiUrl == "http://127.0.0.1:8086/v1/embeddings", "Config EmbeddingApiUrl default mismatch."); Assert(current.SpeechRecognitionEngine == "whisper", "Config SpeechRecognitionEngine default mismatch."); Assert(current.WhisperModelSize == "base", "Config WhisperModelSize default mismatch."); Assert(current.AiProvider == "none", "Config AiProvider default mismatch."); Assert(current.PythonExecutable == "python", "Config PythonExecutable default mismatch."); Assert(current.AiSidecarTimeoutMs == 45000, "Config AiSidecarTimeoutMs default mismatch."); Assert(current.PythonAiSidecarPath.EndsWith(Path.Combine("journal", "ai", "sidecar.py"), StringComparison.OrdinalIgnoreCase), "Config PythonAiSidecarPath default mismatch."); return Task.CompletedTask; } static async Task TestEntryConfigGetAsync() { var entry = NewEntry(); var response = await entry.HandleCommandAsync("""{"action":"config.get"}"""); using var doc = JsonDocument.Parse(response); Assert(doc.RootElement.GetProperty("ok").GetBoolean(), "Expected ok=true for config.get."); var data = doc.RootElement.GetProperty("data"); Assert(data.ValueKind == JsonValueKind.Object, "Expected object payload for config.get."); Assert(data.TryGetProperty("DataDirectory", out var dataDirectory), "Expected DataDirectory in config payload."); Assert(dataDirectory.ValueKind == JsonValueKind.String && !string.IsNullOrWhiteSpace(dataDirectory.GetString()), "Expected non-empty DataDirectory value."); Assert(data.TryGetProperty("MonthlyVaultFormat", out var monthlyVaultFormat), "Expected MonthlyVaultFormat in config payload."); Assert(monthlyVaultFormat.GetString() == "%Y-%m.vault", "Expected Python-compatible MonthlyVaultFormat value."); Assert(data.TryGetProperty("LlamaCppUrl", out _), "Expected LlamaCppUrl in config payload."); Assert(data.TryGetProperty("SpeechRecognitionEngine", out _), "Expected SpeechRecognitionEngine in config payload."); } static Task TestLogRedactorScrubsSensitiveFieldsAsync() { var payload = JsonSerializer.SerializeToElement(new { password = "vault-pass-123", content = "private journal body", prompt = "private ai prompt", nested = new { token = "abc123" } }); var redacted = LogRedactor.RedactPayload(payload); var serialized = JsonSerializer.Serialize(redacted); Assert(!serialized.Contains("vault-pass-123", StringComparison.Ordinal), "Password should be redacted."); Assert(!serialized.Contains("private journal body", StringComparison.Ordinal), "Entry content should be redacted."); Assert(!serialized.Contains("private ai prompt", StringComparison.Ordinal), "Prompt should be redacted."); Assert(!serialized.Contains("abc123", StringComparison.Ordinal), "Nested token should be redacted."); Assert(serialized.Contains("[REDACTED]", StringComparison.Ordinal), "Redacted marker should be present."); return Task.CompletedTask; } static Task TestLogRedactorPreservesNonSensitiveFieldsAsync() { var payload = JsonSerializer.SerializeToElement(new { action = "entries.save", mode = "Daily", filePath = "E:/journal/2026-02-24.md" }); var redacted = LogRedactor.RedactPayload(payload); var serialized = JsonSerializer.Serialize(redacted); Assert(serialized.Contains("entries.save", StringComparison.Ordinal), "Non-sensitive action field should be preserved."); Assert(serialized.Contains("Daily", StringComparison.Ordinal), "Non-sensitive mode field should be preserved."); Assert(serialized.Contains("2026-02-24.md", StringComparison.Ordinal), "Non-sensitive path field should be preserved."); return Task.CompletedTask; } }