DB-persisted reviewer-gated proposal state machine with one-pending-per-track invariant
| Tier | operations |
| Role | unclassified (baselined) |
| Path | crates/operations/approval-workflow |
| Edition | 2021 |
| Targets | operations_approval_workflow, pg_approval_workflow, pg_service_audit |
| Public items | 1 across 0 modules |
| Tests | 22 |
What it is for
# operations-approval-workflow
DB-persisted state machine for reviewer-gated proposals: proposed → {accepted, rejected, superseded}.
The invariant "at most one pending proposal per (tenant_id, entity_type, entity_id, workflow_kind)" is enforced by a partial unique index at the database, not by application-layer locks. Racing workers cannot both insert a pending proposal for the same track.
See docs/userstories/sprint-0.3-approval-workflow.md for the full Gate 1.5 consensus that shaped the v0.1 contract.
Capabilities
crate root
# operations-approval-workflow
| Item |
|---|
pub const APPROVAL_WORKFLOW_SCHEMA_VERSION: u32 |
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
No public modules: the crate root is its whole surface.
Public surface
`crate root`
| Item | What it is |
|---|---|
pub const APPROVAL_WORKFLOW_SCHEMA_VERSION: u32 | Schema version this code expects |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
ApprovalError | errors::ApprovalError |
ApprovalRepository | repository::ApprovalRepository |
PostgresApprovalRepository | postgres::PostgresApprovalRepository |
{ApprovalProposal,ProposalState,ProposeInput,ReviewerDecision} | models::{ApprovalProposal,ProposalState,ProposeInput,ReviewerDecision} |
{actions,ApprovalService} | service::{actions,ApprovalService} |
Boundary
Reaches into foundation.
Shares tier operations with 40 other crates: operations-assessments, operations-block-imaging, operations-boot-media, operations-browser-agent-worker, operations-camera-discovery, operations-camera-liveview, operations-camera-registry, operations-compliance, … (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) |
| Location | crates/operations/approval-workflow |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_operations["operations"] --> n_foundation["foundation"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-audit-log` | foundation | no | always |
| `foundation-basemodels` | foundation | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
async-trait | ^0.1 | — | no | always |
chrono | ^0.4 | serde | no | always |
serde | ^1 | derive | no | always |
serde_json | ^1 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full | no | always |
tracing | ^0.1 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
tokio-test | ^0.4 | — | no | always |
Build. None.
Depended on by. 1 workspace crate.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_approvals["application-approvals"] -->|uses| SELF SELF["operations-approval-workflow"] SELF -->|runtime| n_foundation_audit_log["foundation-audit-log"] SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
default | postgres | yes |
postgres | — | yes |
flowchart LR n_default["default"] --> n_postgres["postgres"] n_postgres["postgres"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | operations_approval_workflow | `src/lib.rs` |
| test | pg_approval_workflow | `tests/pg_approval_workflow.rs` |
| test | pg_service_audit | `tests/pg_service_audit.rs` |
Error model
No public error type was detected: no public item declares a type named *Error, and no public signature returns one.
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | yes |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
1 workspace crate depends on this one: application-approvals.
Verification
| Kind | Count |
|---|---|
| Unit tests | 4 |
| Integration tests | 18 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 1 | 0 | 0 |
What the tests establish, by name:
accept_on_already_accepted_returns_invalid_transition—tests/pg_approval_workflow.rsaccept_transitions_proposed_to_accepted—tests/pg_approval_workflow.rsconcurrent_propose_race_exactly_one_succeeds—tests/pg_approval_workflow.rsget_current_proposed_returns_only_pending_row—tests/pg_approval_workflow.rslatest_accepted_returns_most_recent_accepted_row—tests/pg_approval_workflow.rspropose_creates_proposed_row_with_version_one—tests/pg_approval_workflow.rspropose_different_workflow_kind_same_entity_is_allowed—tests/pg_approval_workflow.rspropose_second_for_same_track_returns_pending_conflict—tests/pg_approval_workflow.rsreject_transitions_proposed_to_rejected—tests/pg_approval_workflow.rsreviewer_queue_filters_by_tenant_and_pending_state—tests/pg_approval_workflow.rssupersede_atomically_marks_old_and_creates_new_proposed—tests/pg_approval_workflow.rssupersede_on_stale_head_returns_stale_head—tests/pg_approval_workflow.rssupersede_on_terminally_decided_proposal_returns_invalid_transition—tests/pg_approval_workflow.rsaccept_writes_audit_row—tests/pg_service_audit.rsaudit_metadata_carries_track_identifiers—tests/pg_service_audit.rspropose_writes_audit_row—tests/pg_service_audit.rsreject_writes_audit_row—tests/pg_service_audit.rssupersede_writes_audit_row_for_successor—tests/pg_service_audit.rsproposal_state_is_terminal—src/models.rsproposal_state_roundtrip—src/models.rsproposal_state_serde_is_lowercase_string—src/models.rsreviewer_decision_roundtrip—src/models.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 1 | 1 |
Public modules with a //! block | 0 | 0 |
pie showData
title Public items with rustdoc
"Documented" : 1
"No rustdoc detected" : 0
Metrics
| Metric | Value |
|---|---|
| Rust source files | 6 |
| Source lines | 1041 |
| Code lines | 789 |
| Public API items | 1 |
| Public modules | 0 |
| Tests | 22 |
| Examples | 0 |
| Cargo features | 2 |
| Direct runtime dependencies | 11 |
| Workspace reverse dependencies | 1 |
pie showData
title Public API by kind
"constant" : 1
pie showData
title Rust source composition
"Code" : 789
"Blank or comment" : 252
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.