operations tier

operations-decision-ledger

Append-only decision/session/lesson ledger — the queryable form of the Gate 1.5 consensus log: decisions with alternatives-rejected/rationale/tiebreaker, supersession chains (cycle-refusing, no deletes, historical fields immutable), session and lesson records.

Append-only decision/session/lesson ledger — the queryable form of the Gate 1.5 consensus log: decisions with alternatives-rejected/rationale/tiebreaker, supersession chains (cycle-refusing, no deletes, historical fields immutable), session and lesson records.

Tieroperations
Roleunclassified (baselined)
Pathcrates/operations/decision-ledger
Edition2021
Targetsoperations_decision_ledger
Public items34 across 5 modules
Tests12

What it is for

operations-decision-ledger — append-only decision/session/lesson ledger (Sprint 3.4 T4). The queryable form of the Gate 1.5 consensus log.

Invariants (enforced in code, proven by tests):

mutation — DecisionLedger::supersede's one-shot activesuperseded status transition. No updates to historical fields, no deletes.

UPDATE ... WHERE status = 'active' inside a transaction holding row locks on both decisions.

transaction and the transition refused if it leads back (supersede::detect_cycle).

Standalone: does NOT depend on infrastructure-knowledge-index; federation of ledger rows into the search index is the CLI's job (Sprint 3.4 T6).

Capabilities

crate root

operations-decision-ledger — append-only decision/session/lesson ledger

Item
async fn ensure_schema(pool : & sqlx::PgPool) -> Result <(), LedgerError>

LedgerError

Structured errors for the decision ledger.

Item
pub enum LedgerError

models (other)

Row models + new-record inputs + boundary validation.

Item
pub const NIL_TENANT: Uuid
fn validate_alternatives(value : & serde_json::Value) -> Result <(), LedgerError>

Decision

Row models + new-record inputs + boundary validation.

Item
pub struct Decision
Decision :: fn status_enum(& self) -> Result <DecisionStatus, LedgerError>

DecisionFilter

Row models + new-record inputs + boundary validation.

Item
pub struct DecisionFilter

DecisionStatus

Row models + new-record inputs + boundary validation.

Item
pub enum DecisionStatus
DecisionStatus :: fn as_str(self) -> & 'static str
DecisionStatus :: fn parse(s : & str) -> Result <Self, LedgerError>

Lesson

Row models + new-record inputs + boundary validation.

Item
pub struct Lesson

LessonKind

Row models + new-record inputs + boundary validation.

Item
pub enum LessonKind
LessonKind :: fn as_str(self) -> & 'static str
LessonKind :: fn parse(s : & str) -> Result <Self, LedgerError>

NewDecision

Row models + new-record inputs + boundary validation.

Item
pub struct NewDecision
NewDecision :: fn new(title : & str, context : & str, chosen : & str, rationale : & str) -> Self
NewDecision :: fn validate(& self) -> Result <(), LedgerError>

NewLesson

Row models + new-record inputs + boundary validation.

Item
pub struct NewLesson
NewLesson :: fn validate(& self) -> Result <(), LedgerError>

NewSession

Row models + new-record inputs + boundary validation.

Item
pub struct NewSession
NewSession :: fn validate(& self) -> Result <(), LedgerError>

SessionRecord

Row models + new-record inputs + boundary validation.

Item
pub struct SessionRecord

DecisionLedger

Public ledger API. Static async fns over a pool, matching the

Item
pub struct DecisionLedger
DecisionLedger :: async fn record_decision(pool : & PgPool, input : & NewDecision,) -> Result <Decision, LedgerError>
DecisionLedger :: async fn supersede(pool : & PgPool, tenant : Uuid, old_id : Uuid, new_id : Uuid,) -> Result <Decision, LedgerError>
DecisionLedger :: async fn record_session(pool : & PgPool, input : & NewSession,) -> Result <SessionRecord, LedgerError>
DecisionLedger :: async fn record_lesson(pool : & PgPool, input : & NewLesson) -> Result <Lesson, LedgerError>
DecisionLedger :: async fn get_decision(pool : & PgPool, tenant : Uuid, id : Uuid,) -> Result <Option <Decision>, LedgerError>
DecisionLedger :: async fn list_decisions(pool : & PgPool, tenant : Uuid, filter : & DecisionFilter,) -> Result <Vec <Decision>, LedgerError>
DecisionLedger :: async fn list_sessions(pool : & PgPool, tenant : Uuid, project : Option <& str>,) -> Result <Vec <SessionRecord>, LedgerError>
DecisionLedger :: async fn list_lessons(pool : & PgPool, tenant : Uuid, project : Option <& str>, kind : Option <LessonKind>,) -> Result <Vec <Lesson>, LedgerError>

supersede (other)

Supersession-chain cycle detection — the pure, DB-free core of the

Item
pub const MAX_CHAIN_DEPTH: usize
fn detect_cycle(old : Uuid, new : Uuid, chain_from_new : & Uuid) -> Result <(), LedgerError>
fn walk_chain <F>(start : Uuid, mut next : F) -> Vec <Uuid> where F : FnMut(Uuid) -> Option <Uuid>,

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

operations_decision_ledger

flowchart TD
  n_operations_decision_ledger["operations_decision_ledger"]
  n_operations_decision_ledger --> n_error["error"]
  n_operations_decision_ledger --> n_models["models"]
  n_operations_decision_ledger --> n_repo["repo"]
  n_operations_decision_ledger --> n_service["service"]
  n_operations_decision_ledger --> n_supersede["supersede"]

Public surface

`crate root`

ItemWhat it is
async fn ensure_schema(pool : & sqlx::PgPool) -> Result <(), LedgerError>Apply the crate's schema (idempotent IF NOT EXISTS migration) to pool

`error`

ItemWhat it is
pub enum LedgerErrorEverything the ledger can refuse to do, and why.

`models`

ItemWhat it is
pub const NIL_TENANT: UuidThe nil tenant used by embedded/single-tenant deployments (schema default).
pub enum DecisionStatusLifecycle status of a decision
DecisionStatus :: fn as_str(self) -> & 'static strThe exact string stored in the status column.
DecisionStatus :: fn parse(s : & str) -> Result <Self, LedgerError>Parse the column string back into the enum.
pub enum LessonKindCategory of a lesson row (mirrors the migration CHECK).
LessonKind :: fn as_str(self) -> & 'static strThe exact string stored in the kind column.
LessonKind :: fn parse(s : & str) -> Result <Self, LedgerError>Parse the column string back into the enum.
pub struct DecisionA decision row as stored
Decision :: fn status_enum(& self) -> Result <DecisionStatus, LedgerError>Typed view of the status column.
pub struct SessionRecordA session row as stored (summary of one working session).
pub struct LessonA lesson row as stored.
pub struct NewDecisionInput for crate::DecisionLedger::record_decision.
NewDecision :: fn new(title : & str, context : & str, chosen : & str, rationale : & str) -> SelfMinimal constructor with the four required fields; everything else defaults (nil tenant, 'default' project, empty alternatives).
NewDecision :: fn validate(& self) -> Result <(), LedgerError>Boundary validation (pure, no DB): required text fields non-blank, alternatives_rejected a JSON array of {"option","reason"} objects with non-blank string values.
pub struct NewSessionInput for crate::DecisionLedger::record_session.
NewSession :: fn validate(& self) -> Result <(), LedgerError>Boundary validation (pure, no DB).
pub struct NewLessonInput for crate::DecisionLedger::record_lesson.
NewLesson :: fn validate(& self) -> Result <(), LedgerError>Boundary validation (pure, no DB).
pub struct DecisionFilterFilter for crate::DecisionLedger::list_decisions
fn validate_alternatives(value : & serde_json::Value) -> Result <(), LedgerError>Validate the alternatives_rejected shape: {"option": <non-blank string>, "reason": <non-blank string>}, ....

`service`

ItemWhat it is
pub struct DecisionLedgerAppend-only decision/session/lesson ledger operations
DecisionLedger :: async fn record_decision(pool : & PgPool, input : & NewDecision,) -> Result <Decision, LedgerError>Validate and append a decision row.
DecisionLedger :: async fn supersede(pool : & PgPool, tenant : Uuid, old_id : Uuid, new_id : Uuid,) -> Result <Decision, LedgerError>Atomically mark old_id superseded by new_id (both must exist for tenant; old_id must be active; the supersession chain from new_id must not lead back to old_id)
DecisionLedger :: async fn record_session(pool : & PgPool, input : & NewSession,) -> Result <SessionRecord, LedgerError>Validate and append a session row.
DecisionLedger :: async fn record_lesson(pool : & PgPool, input : & NewLesson) -> Result <Lesson, LedgerError>Validate and append a lesson row (FK links checked by the DB).
DecisionLedger :: async fn get_decision(pool : & PgPool, tenant : Uuid, id : Uuid,) -> Result <Option <Decision>, LedgerError>Fetch one decision by id (tenant-scoped).
DecisionLedger :: async fn list_decisions(pool : & PgPool, tenant : Uuid, filter : & DecisionFilter,) -> Result <Vec <Decision>, LedgerError>List decisions newest-first, filtered by project / sprint / status.
DecisionLedger :: async fn list_sessions(pool : & PgPool, tenant : Uuid, project : Option <& str>,) -> Result <Vec <SessionRecord>, LedgerError>List sessions newest-first, optionally scoped to a project.
DecisionLedger :: async fn list_lessons(pool : & PgPool, tenant : Uuid, project : Option <& str>, kind : Option <LessonKind>,) -> Result <Vec <Lesson>, LedgerError>List lessons newest-first, optionally scoped to project and/or kind.

`supersede`

ItemWhat it is
pub const MAX_CHAIN_DEPTH: usizeSanity bound on supersession-chain length
fn detect_cycle(old : Uuid, new : Uuid, chain_from_new : & Uuid) -> Result <(), LedgerError>Decide whether superseding old by new is acyclic
fn walk_chain <F>(start : Uuid, mut next : F) -> Vec <Uuid> where F : FnMut(Uuid) -> Option <Uuid>,Walk a supersession chain from start using next (superseded_by lookup), returning the visited ids start, ... in order

Re-exports. Exported here, defined elsewhere.

ExportDefined in
DecisionLedgerservice::DecisionLedger
LedgerErrorerror::LedgerError
{detect_cycle,walk_chain,MAX_CHAIN_DEPTH}supersede::{detect_cycle,walk_chain,MAX_CHAIN_DEPTH}
{validate_alternatives,Decision,DecisionFilter,DecisionStatus,Lesson,LessonKind,NewDecision,NewLesson,NewSession,SessionRecord,NIL_TENANT,}models::{validate_alternatives,Decision,DecisionFilter,DecisionStatus,Lesson,LessonKind,NewDecision,NewLesson,NewSession,SessionRecord,NIL_TENANT,}

Boundary

Depends on no other workspace tier.

Shares tier operations with 40 other crates: operations-approval-workflow, operations-assessments, operations-block-imaging, operations-boot-media, operations-browser-agent-worker, operations-camera-discovery, operations-camera-liveview, operations-camera-registry, … (40 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)operations
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/operations/decision-ledger
Vocabulary in force (lexicon)current

Dependencies

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
chrono^0.4serdenoalways
serde^1derive, derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
uuid^1v4, v7, serde, js, v4, serdenoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tokio^1full, macros, rt-multi-threadnoalways

Build. None.

Depended on by. 2 workspace crates.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  n_application_wiki["application-wiki"] -->|uses| SELF
  n_tools_corpus["tools-corpus"] -->|uses| SELF
  SELF["operations-decision-ledger"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
liboperations_decision_ledger`src/lib.rs`

Error model

Error typeNamed by
LedgerErrordetect_cycle, ensure_schema, validate_alternatives

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimenone detected
database accessyes
network I/Onone detected
unsafe codenone detected
environment variablesyes

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

VariableRead in
DECISION_LEDGER_TEST_DBsrc/lib.rs

2 workspace crates depend on this one: application-wiki, tools-corpus.

Verification

KindCount
Unit tests12
Integration tests0
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root101
error101
models11012
service101
supersede300

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc3434
Public modules with a //! block55
pie showData
    title Public items with rustdoc
    "Documented" : 34
    "No rustdoc detected" : 0

Metrics

MetricValue
Rust source files6
Source lines1434
Code lines1087
Public API items34
Public modules5
Tests12
Examples0
Cargo features0
Direct runtime dependencies6
Workspace reverse dependencies2
pie showData
    title Public API by kind
    "constant" : 2
    "enum" : 3
    "function" : 4
    "method" : 17
    "struct" : 8
pie showData
    title Rust source composition
    "Code" : 1087
    "Blank or comment" : 347

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All operations · Manual