Class SchemaChangeLogStore
- Namespace
- Kuestenlogik.Bowire
- Assembly
- Kuestenlogik.Bowire.dll
Disk-backed store for a workspace's schema-change log (#185). The schema watch (#48) diffs two discovery results in the browser; this store is what makes the result durable — the client posts each poll's delta here so "what changed while I was at lunch" survives a reload, a browser reset, and other clients of the same workspace. Entries older than RetentionDays are pruned on every write and filtered on every read.
public sealed class SchemaChangeLogStore
- Inheritance
-
SchemaChangeLogStore
- Inherited Members
Remarks
Layout: one file per workspace at
workspaces/<wsId>/schema-changes/log.json, resolved
through GetWorkspacePath(string, string?, string) so the
per-identity / per-storage-root seams (#28, #212) keep working.
Registered as a DI singleton (not a static class like the older
stores) — the instance owns its file lock and test-path override.
Constructors
SchemaChangeLogStore()
public SchemaChangeLogStore()
Fields
DedupWindow
Two clients watching the same workspace both observe — and both post — the same schema transition. An incoming entry that matches an existing one (type + service + method + detail) stamped within this window is dropped as a duplicate observation, not a second change.
public static readonly TimeSpan DedupWindow
Field Value
MaxDetailLength
See MaxNameLength.
public const int MaxDetailLength = 500
Field Value
MaxEntries
Hard cap on retained entries, newest win. A watch polling a schema under heavy churn every 5 s could otherwise grow the file without bound inside the retention window.
public const int MaxEntries = 500
Field Value
MaxNameLength
Per-string byte diet. A Detail is a one-line human summary and service/method names are identifiers — anything longer is truncated so a single client can't balloon the log file (which is re-read and re-written under the lock on every append, and shipped to every client on boot).
public const int MaxNameLength = 300
Field Value
RetentionDays
How long a change entry is retained.
public const int RetentionDays = 7
Field Value
Methods
Append(string, string?, IReadOnlyList<SchemaChangeEntry?>)
Append a batch of change entries (one schema-watch poll's delta), prune the retention window, and persist. Returns the resulting envelope. Throws ArgumentException on a null entry, an unknown change type or a missing service so a malformed POST can't corrupt the on-disk log.
public SchemaChangeLogEnvelope Append(string workspaceId, string? storageRoot, IReadOnlyList<SchemaChangeEntry?> entries)
Parameters
workspaceIdstringstorageRootstringentriesIReadOnlyList<SchemaChangeEntry>
Returns
Remarks
The server stamps At on every entry, ignoring whatever the client sent. One clock authority keeps the retention window, the entry cap and the unread-vs-LastReadAt compare consistent — a browser clock ahead of the server would otherwise produce entries that can never be marked read, and one behind would produce entries born read.
Load(string, string?)
Load the change log, dropping entries outside the retention window. Returns the empty envelope when the file is missing or corrupt — never throws so the UI keeps working.
public SchemaChangeLogEnvelope Load(string workspaceId, string? storageRoot)
Parameters
Returns
MarkRead(string, string?)
Move the read watermark to now — every current entry becomes "read". Returns the resulting envelope.
public SchemaChangeLogEnvelope MarkRead(string workspaceId, string? storageRoot)
Parameters
Returns
OverrideStorePathForTesting(string?)
Pin the store to a fixed file for tests, bypassing the workspace-path resolution. Pass null to restore.
public void OverrideStorePathForTesting(string? path)
Parameters
pathstring