Project_Journal-Csharp_back.../MIGRATION_ACCEPTANCE_CRITERIA.md
2026-02-23 20:12:10 -06:00

38 KiB

kanban-plugin
kanban-plugin
table

C# Backend Parity Acceptance Criteria (Python Twin)

Goal

Create a C# backend that is behaviorally equivalent to the current Python backend for core journaling workflows, with zero data-loss regressions and compatible vault handling.

Parity Rule

Behavior parity is required. Internal implementation can differ.

Architecture Lock (Decision Record)

  1. Non-AI backend remains C# system-of-record for migration scope:
  • entry I/O, vault crypto/load/save, search, fragments, config surface, and transport layers.
  1. AI inference/execution remains Python:
  • C# AI code is bridge-only (IAiService + Python sidecar adapter), with timeout/error envelope handling.
  • No model inference logic or model runtime will be introduced in C# during this migration plan.
  1. Speech remains intentionally Python-side delegated during hybrid and cutover phases.
  2. Any change to this lock requires a written RFC, benchmark evidence, and explicit maintainer approval.

Source of Truth (Current Python)

  • journal/core/storage.py
  • journal/core/encryption.py
  • journal/core/parser.py
  • journal/core/models.py
  • journal/core/database.py
  • journal/cli/main.py
  • journal/ai/analysis.py
  • journal/ai/chat.py
  • journal/core/speech.py

Definition of Done (Release Gate)

  1. All P0 criteria below are marked Pass.
  2. Existing Python-created vault files load successfully in C# backend.
  3. Side-by-side output comparison on shared fixture corpus shows no functional mismatch for P0 flows.
  4. No plaintext journal data remains after graceful shutdown flow.

Shared Fixture Corpus (Required)

  1. fixtures/vaults/
  • Multiple months (YYYY-MM.vault) generated by Python app.
  • Includes at least one wrong-password test case.
  1. fixtures/entries/
  • Daily, deep, recovery, fragment-heavy entries.
  • Includes multiline fragments, tags, checkboxes, unusual spacing.
  1. fixtures/search/
  • Queries for text, section, tag, type, checked, unchecked, date ranges.
  1. fixtures/ai/
  • Stubbed LLM/embedding responses for deterministic comparison.

Acceptance Matrix

Use status values: Not Started, In Progress, Blocked, Pass, Fail.

ID Priority Feature Acceptance Criteria Status Owner Evidence
DOM-001 P0 Fragment model parity Fragment has type, description, time, tags; rejects empty type/description; trims values. Pass Stan44/Codex/J. Schmidt Journal.Core/Models/Fragment.cs, Journal.Core/Services/FragmentService.cs, smoke test CreateAsync trims fields + UpdateAsync rejects whitespace type
DOM-002 P0 Journal entry domain parity Entry model supports date, raw_content, sections, fragments equivalent to Python semantics. Pass Stan44/Gemini Journal.Core/Models/JournalEntry.cs, Journal.Core/Models/ParsedSection.cs, Journal.Core/Entry.cs, smoke tests JournalEntry model stores parity fields + Entry entries.save writes and merges content + Entry entries.load returns raw content payload
PAR-001 P0 Date extraction parity Parser reads **Date:** or Date:; falls back to filename stem when missing. Pass Stan44/Gemini Journal.Core/Services/JournalParser.cs, smoke tests Parser extracts date from **Date:** marker + Parser falls back to file stem when date missing
PAR-002 P0 Section parsing parity Recognizes canonical section titles and captures section content lines. Pass Stan44/Codex Journal.Core/Services/JournalParser.cs, smoke tests Parser captures canonical sections and content + Parser ignores non-canonical section headers
PAR-003 P0 Checkbox parsing parity Parses markdown checkboxes (- [ ], - [x]) and preserves checked state by checkbox text. Pass Stan44/Codex Journal.Core/Services/JournalParser.cs, smoke test Parser captures checkbox states per section
PAR-004 P0 Fragment parsing parity Parses !TYPE @time #tags plus multiline description blocks with same boundary behavior as Python regex parser. Pass Stan44 Journal.Core/Services/JournalParser.cs, smoke tests Parser captures multiline fragment blocks + Parser fragment boundary follows header lines
MRG-001 P0 Merge behavior parity Saving existing entry merges non-empty section updates and appends only non-duplicate fragments by description. Pass Stan44/Codex Journal.Core/Models/JournalEntry.cs, smoke tests MergeWith overwrites section when new content is meaningful + MergeWith appends non-duplicate fragments by description
MRG-002 P0 Markdown reconstruction parity Entry serialization writes canonical section order and fragment block formatting equivalent to Python to_markdown(). Pass Stan44 Journal.Core/Models/JournalEntry.cs, smoke tests ToMarkdown writes canonical section order + ToMarkdown writes fragment blocks
VLT-001 P0 Vault crypto format compatibility Uses AES-256-GCM with payload layout compatible with Python (salt + nonce + tag + ciphertext). Pass Stan44/Codex Journal.Core/Services/VaultCryptoService.cs, smoke tests Vault crypto roundtrip preserves data and layout + Vault crypto decrypts Python payload fixture
VLT-002 P0 KDF compatibility Uses PBKDF2-HMAC-SHA256 with matching salt/key sizes and iteration count for Python vault compatibility. Pass Stan44/Codex Journal.Core/Services/VaultCryptoService.cs, smoke test Vault key derivation matches Python fixture
VLT-003 P0 Monthly vault naming parity Vault filename format exactly YYYY-MM.vault. Pass Stan44/Codex Journal.Core/Services/VaultStorageService.cs, smoke test Vault monthly filename matches parity format
VLT-004 P0 Load workflow parity load all vaults clears decrypted workspace first, then decrypts/extracts monthly vaults. Pass Stan44/Codex Journal.Core/Services/VaultStorageService.cs, smoke test Vault load clears workspace and extracts decrypted files
VLT-005 P0 Wrong password behavior Wrong password returns explicit failure and does not corrupt existing vault files. Pass Stan44/Codex Journal.Core/Services/VaultStorageService.cs, smoke test Vault load wrong password does not modify vault files
VLT-006 P1 Legacy vault handling Legacy _init_vault.vault handling behavior is preserved or intentionally migrated with backward-compat note. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/VaultStorageService.cs, smoke test Vault load ignores and removes legacy _init_vault.vault; migration note: file is ignored+deleted on load
VLT-007 P0 Current-month optimized save Supports current-month save path equivalent to Python optimization. Pass Stan44 journal-master/journal/Journal.Core/Services/VaultStorageService.cs, smoke test Vault current-month save writes only current month and skips unchanged state
VLT-008 P0 Full rebuild save Supports full monthly regroup/rebuild save flow from decrypted .md files. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/VaultStorageService.cs, smoke test Vault rebuild saves grouped monthly archives from decrypted files
DAT-001 P0 Decrypted data cleanup Graceful shutdown removes decrypted workspace artifacts. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/VaultStorageService.cs, smoke test Vault clear data directory removes decrypted workspace artifacts
DB-001 P1 SQLCipher compatibility Database key derivation and SQLCipher connection behavior are compatible with Python expectations. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/JournalDatabaseService.cs, journal-master/journal/Journal.Core/Services/IJournalDatabaseService.cs, smoke tests Database key derivation matches Python fixture + Entry db.status returns database compatibility payload + Entry db.hydrate_workspace returns hydration metadata
DB-002 P1 Schema parity entries, sections, fragments, tags, fragment_tags schema exists with compatible constraints. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/JournalDatabaseService.cs, smoke tests Database schema parity tables are created + Entry db.initialize_schema creates schema in data directory + Entry db.hydrate_workspace returns hydration metadata
SCH-001 P0 Search parity (content) Search supports text query over full entry content. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/EntrySearchService.cs, journal-master/journal/Journal.Core/Entry.cs, smoke tests Entry search.entries matches query against full raw content + Entry search.entries without query returns all markdown entries
SCH-002 P0 Search parity (filters) Search supports date range, section filter, tag filter, fragment type filter, checked/unchecked filters. Pass Stan44 journal-master/journal/Journal.Core/Services/EntrySearchService.cs, journal-master/journal/Journal.Core/Entry.cs, smoke tests for date/section/tag+type/checked+unchecked filters + invalid date handling
CLI-001 P0 Vault CLI parity CLI supports vault load/save with password prompt semantics matching Python UX. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/SidecarCli.cs, journal-master/journal/Journal.Sidecar/App.cs, smoke tests Sidecar vault CLI load succeeds with --password + Sidecar vault CLI save writes monthly vault with --password
CLI-002 P0 Search CLI parity CLI options match existing Python capabilities sufficiently for drop-in replacement. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/SidecarCli.cs, smoke tests Sidecar search CLI returns matching entries with filters + Sidecar search CLI warns when no decrypted entries exist
API-001 P0 Sidecar protocol stability Stdin/stdout contract is line-delimited JSON with {ok,data} or {ok:false,error} and strict action routing. Pass Stan44/Codex Journal.Core/Entry.cs, Journal.SmokeTests/Program.cs, Journal.SmokeTests/Fixtures/transport_cases.json
API-002 P1 HTTP API parity API exposes endpoints equivalent to supported sidecar actions; no template-only endpoints in parity mode. Pass Stan44/Codex journal-master/journal/Journal.Api/Program.cs, journal-master/journal/Journal.Api/Journal.Api.http, tests/test_api_contract.py, scripts/migration-gate.ps1
AI-001 P1 LLM summarize parity Entry/all-entry summarize workflow callable with equivalent behavior and timeout controls. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal-master/journal/Journal.Core/Entry.cs, smoke tests for ai.health + summarize bridge/error handling
AI-002 P2 Embedding parity Embedding endpoint integration available with equivalent request/response contract. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal-master/journal/Journal.Core/Entry.cs, smoke tests for ai.embed bridge/disabled parsing
AI-003 P1 Cloud chat parity Cloud chat request/response flow available and configurable. Pass Stan44 journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal/ai/chat.py, journal-master/journal/Journal.Core/Entry.cs, smoke tests for ai.chat bridge/disabled/error handling
SPC-001 P2 Speech parity Engine-selectable speech flow (whisper/google/sphinx-like modes) retained or intentionally delegated. Pass Stan44/Codex journal-master/journal/Journal.Core/Services/ISpeechBridgeService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarSpeechService.cs, journal-master/journal/Journal.Core/Entry.cs, journal/ai/sidecar.py, smoke tests for speech bridge empty-device/error/timeout paths
CFG-001 P0 Config parity Equivalent configuration keys exist for paths, vault format, AI endpoints, and speech settings. Pass Stan44 journal-master/journal/Journal.Core/Services/JournalConfigService.cs, journal-master/journal/Journal.Core/Models/JournalConfig.cs, smoke tests Config service exposes parity path, vault, AI, and speech settings + Entry config.get returns config payload
OBS-001 P1 Logging/error parity Failures return actionable messages without leaking secrets or plaintext journal data. Pass Stan44/Codex journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.Core/Services/LogRedactor.cs, smoke tests Log redactor scrubs sensitive payload fields + Log redactor preserves non-sensitive payload fields

Mandatory Gate Tests (P0)

  1. Vault Compatibility
  • Given existing Python vault fixtures, C# load succeeds with correct password.
  • Wrong password consistently fails without partial corruption.
  1. Parser + Merge
  • Given fixture entries, C# parser output matches Python parser output for sections/fragments/checkboxes.
  • Saving edited entry preserves merge semantics.
  1. Search
  • For shared corpus, C# and Python return the same entry set for all P0 search filters.
  1. Transport
  • Sidecar commands for core actions produce stable JSON success/error envelopes.
  1. Cleanup
  • After graceful shutdown sequence, decrypted workspace is empty.
  1. Phase 1: Fragment Vertical Slice
  • Complete DOM-001, API-001, persistence beyond in-memory.
  1. Phase 2: Entry/Parser/Merge Twin
  • Complete DOM-002, PAR-*, MRG-*.
  1. Phase 3: Vault/Crypto Twin
  • Complete VLT-*, DAT-001.
  1. Phase 4: Search + CLI Twin
  • Complete SCH-*, CLI-*, CFG-001.
  1. Phase 5: AI/Speech
  • Complete AI-* as Python-bridge parity (not C# model parity), plus SPC-001.
  1. Phase 6: Frontend Cutover
  • Tauri frontend switches to C# backend only after all P0 criteria pass.

Rules for Change Requests

  1. Any intentional divergence from Python behavior requires:
  • Written rationale.
  • New acceptance criterion replacing old one.
  • Migration note describing user-visible impact.
  1. No removal of a P0 criterion without both maintainers approving in writing.

Status Snapshot (2026-02-24, Phase 5 Complete / Phase 6 Ready)

This section is a proposed status/evidence snapshot based on current code in:

  • Python source: Project_Journal/
  • C# migration: Project_Journal/journal-master/journal/

It does not change release gates or acceptance definitions.

Phase Summary

Phase Current State Evidence
Phase 1: Fragment Vertical Slice Pass (complete) Fragment model/service/sidecar + persisted repository + fixture-backed transport smoke tests: journal-master/journal/Journal.Core/Models/Fragment.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.Core/Repositories/FileFragmentRepository.cs, journal-master/journal/Journal.SmokeTests/Program.cs, journal-master/journal/Journal.SmokeTests/Fixtures/transport_cases.json
Phase 2: Entry/Parser/Merge Twin Pass C# JournalEntry domain, parser slices (PAR-001..004), and merge/reconstruction slices (MRG-001..002) are implemented with smoke evidence.
Phase 3: Vault/Crypto Twin Pass Vault parity slices (VLT-001..008) and decrypted cleanup (DAT-001) are implemented with smoke evidence.
Phase 4: Search + CLI Twin Pass Search parity (SCH-001, SCH-002), CLI parity (CLI-001, CLI-002), and config parity (CFG-001) are implemented with smoke evidence.
Phase 5: AI/Speech Pass AI-001/AI-002/AI-003 bridge parity implemented and SPC-001 completed with Python-side speech execution + C# orchestration contract (speech.devices.list, speech.transcribe).
Phase 6: Frontend Cutover Ready Release-gate fixture corpus, parity harness, and API contract tests are implemented and callable through scripts/migration-gate.ps1.

Acceptance Status Snapshot

ID Proposed Status Evidence Notes
DOM-001 Pass journal-master/journal/Journal.Core/Models/Fragment.cs, journal-master/journal/Journal.Core/Services/FragmentService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Fields/validation/trim behavior implemented and smoke-tested.
DOM-002 Pass journal-master/journal/Journal.Core/Models/JournalEntry.cs, journal-master/journal/Journal.Core/Models/ParsedSection.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs Entry parity is implemented for model and runtime save/load/list flows with smoke coverage (entries.save/entries.load/entries.list).
PAR-001 Pass journal-master/journal/Journal.Core/Services/JournalParser.cs, journal-master/journal/Journal.SmokeTests/Program.cs Date extraction supports **Date:** and Date: with file-stem fallback and smoke coverage.
PAR-002 Pass journal-master/journal/Journal.Core/Services/JournalParser.cs, journal-master/journal/Journal.SmokeTests/Program.cs Canonical section headers are recognized and section content lines are captured with smoke coverage.
PAR-003 Pass journal-master/journal/Journal.Core/Services/JournalParser.cs, journal-master/journal/Journal.SmokeTests/Program.cs Checkbox state extraction for - [ ]/- [x] is implemented with per-section lookup coverage.
PAR-004 Pass journal-master/journal/Journal.Core/Services/JournalParser.cs, journal-master/journal/Journal.SmokeTests/Program.cs Fragment header metadata and multiline description boundaries are parsed with smoke coverage.
MRG-001 Pass journal-master/journal/Journal.Core/Models/JournalEntry.cs, journal-master/journal/Journal.SmokeTests/Program.cs Merge overwrites only meaningful section updates and appends non-duplicate fragments by description.
MRG-002 Pass journal-master/journal/Journal.Core/Models/JournalEntry.cs, journal-master/journal/Journal.SmokeTests/Program.cs Markdown reconstruction emits canonical section order and fragment blocks with smoke coverage.
VLT-001 Pass journal-master/journal/Journal.Core/Services/VaultCryptoService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Payload layout (salt+nonce+tag+ciphertext) is validated and can decrypt Python-generated fixture data.
VLT-002 Pass journal-master/journal/Journal.Core/Services/VaultCryptoService.cs, journal-master/journal/Journal.SmokeTests/Program.cs PBKDF2-HMAC-SHA256 derivation matches Python fixture output and parameterization.
VLT-003 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Monthly vault filename format is emitted as YYYY-MM.vault.
VLT-004 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Load workflow clears decrypted workspace before decrypting and extracting vault files.
VLT-005 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Wrong password returns failure and leaves existing vault bytes unchanged.
VLT-006 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Legacy _init_vault.vault is treated as obsolete, ignored for decryption, and deleted during load for compatibility.
VLT-007 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Current-month optimized save path is implemented with fingerprint-based skip behavior and smoke coverage.
VLT-008 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Full monthly rebuild flow from decrypted .md files is implemented with smoke coverage.
DAT-001 Pass journal-master/journal/Journal.Core/Services/VaultStorageService.cs, journal-master/journal/Journal.SmokeTests/Program.cs Decrypted workspace cleanup path removes artifacts and recreates an empty data directory with smoke coverage.
DB-001 Pass journal-master/journal/Journal.Core/Services/JournalDatabaseService.cs, journal-master/journal/Journal.Core/Services/IJournalDatabaseService.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs PBKDF2-HMAC-SHA256 key derivation parity plus runtime SQLCipher connection/key validation are implemented and surfaced by db.status (RuntimeReady=true) and db.hydrate_workspace.
DB-002 Pass journal-master/journal/Journal.Core/Services/JournalDatabaseService.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs Schema parity DDL for entries/sections/fragments/tags/fragment_tags is implemented and validated through runtime schema creation and table checks in db.hydrate_workspace.
SCH-001 Pass journal-master/journal/Journal.Core/Services/EntrySearchService.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs search.entries performs case-insensitive full raw-content query across decrypted .md entries with smoke coverage.
SCH-002 Pass journal-master/journal/Journal.Core/Services/EntrySearchService.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs Date range, section-scoped query, tag/type, and checked/unchecked filters are implemented for search.entries.
CLI-001 Pass journal-master/journal/Journal.Core/Services/SidecarCli.cs, journal-master/journal/Journal.Sidecar/App.cs, journal-master/journal/Journal.SmokeTests/Program.cs Sidecar supports vault load/save CLI mode with password prompt semantics and non-interactive --password support.
CLI-002 Pass journal-master/journal/Journal.Core/Services/SidecarCli.cs, journal-master/journal/Journal.SmokeTests/Program.cs Sidecar supports search CLI flags (query/date/section/tag/type/checked/unchecked) and parity-style output messaging.
API-001 Pass journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs, journal-master/journal/Journal.SmokeTests/Fixtures/transport_cases.json Line-delimited JSON envelope behavior and strict action routing are covered by smoke tests and transport fixtures.
API-002 Pass journal-master/journal/Journal.Api/Program.cs, journal-master/journal/Journal.Api/Journal.Api.http, tests/test_api_contract.py, scripts/migration-gate.ps1 HTTP parity contract is locked (POST /api/command, GET /health, GET /healthz) with malformed/missing/unknown action coverage.
AI-001 Pass journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs ai.health + summarize bridge parity implemented with provider modes (none, python-sidecar) and timeout/error envelopes.
AI-002 Pass journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs ai.embed bridge parity is implemented with provider-mode fallback (none/python-sidecar) and smoke coverage.
AI-003 Pass journal-master/journal/Journal.Core/Services/IAiService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarAiService.cs, journal/ai/sidecar.py, journal/ai/chat.py, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs ai.chat bridge parity is implemented with provider-mode fallback (none/python-sidecar) and smoke coverage.
SPC-001 Pass journal-master/journal/Journal.Core/Services/ISpeechBridgeService.cs, journal-master/journal/Journal.Core/Services/PythonSidecarSpeechService.cs, journal-master/journal/Journal.Core/Entry.cs, journal/ai/sidecar.py, journal-master/journal/Journal.SmokeTests/Program.cs Speech delegation is locked as Python execution + C# orchestration (speech.devices.list, speech.transcribe) with timeout/error/empty-device coverage.
CFG-001 Pass journal-master/journal/Journal.Core/Services/JournalConfigService.cs, journal-master/journal/Journal.Core/Models/JournalConfig.cs, journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.SmokeTests/Program.cs C# config surface now includes parity keys for paths, vault format, AI endpoints, and speech settings via config.get.
OBS-001 Pass journal-master/journal/Journal.Core/Entry.cs, journal-master/journal/Journal.Core/Services/LogRedactor.cs, journal-master/journal/Journal.SmokeTests/Program.cs Structured logging envelope and secret redaction are implemented and covered by smoke tests.

Snapshot Risks/Blockers

  1. Remaining migration risk is operational only: maintain parity by running scripts/migration-gate.ps1 before cutover merges.
  2. DB runtime parity is active in C# with SQLCipher via NuGet packages (Microsoft.Data.Sqlite.Core + SQLitePCLRaw.bundle_e_sqlcipher) and smoke validation.
  3. Hybrid DB hydration handoff remains routed through C# sidecar (db.hydrate_workspace) from journal/core/storage.py; Python-side post-load DB hydration remains disabled in hybrid mode.

%% kanban:settings

{"kanban-plugin":"board","list-collapse":[false]}

%%