The migration ledger: every applied migration as a row keyed by a time-ordered id, with its label, its bytes and the work item that asked for it
| Tier | — |
| Role | unclassified (baselined) |
| Path | crates/tools/migration-ledger |
| Edition | 2021 |
| Targets | tools-migration-ledger, tools_migration_ledger |
| Public items | 9 across 0 modules |
| Tests | 11 |
What it is for
The migration ledger: what ran, in the order it ran, as rows.
# Why this is not itself a migration
A ledger cannot be repaired by the mechanism it records. If the table that says which migrations ran is created by a numbered migration, then a ledger that is wrong or missing cannot be fixed without the very sequence it is blocking. So the table is created by this tool, idempotently, and stands outside the numbered set on purpose.
# Why the identity is time-ordered rather than a number
The number is a filename convention, and two sessions took the same one within minutes of each other on 2026-09-10 (the second 0124). A number can collide; a time-ordered identifier cannot, and it sorts in the order the rows were written without a second column to sort by. The generator is foundation_uuid7, which knows nothing about migrations.
The number still matters — it is the order the sequence runs in — so it stays as its own field. What changes is that it is no longer the identity.
# Three sources of order, in the order they are trusted
1. The database's own record. When the old ledger recorded a time, that is when the migration actually ran on this database. Nothing beats it. 2. Git. When the file was first committed. Weaker — a file can be committed long before it runs — but it is real evidence, and for everything past 0111 here it is the only evidence there is. 3. The sequence number. Always available, never wrong about ORDER, and silent about when.
Each source only fills what the one above it left empty, and the ordering rule refuses to let any of them reverse the sequence.
Capabilities
crate root
The migration ledger: what ran, in the order it ran, as rows.
| Item |
|---|
fn number_of(filename : & str) -> Option <u32> |
fn label_of(filename : & str) -> String |
fn title_of(filename : & str, keep_number : bool) -> String |
fn digest_of(content : & str) -> String |
fn assign_ids(registered : & (& str, & str), known : & (Option <i64>, OrderSource), floor : i64, keep_number_in_label : bool,) -> Vec <Entry> |
Entry
The migration ledger: what ran, in the order it ran, as rows.
| Item |
|---|
pub struct Entry |
OrderSource
The migration ledger: what ran, in the order it ran, as rows.
| Item |
|---|
pub enum OrderSource |
OrderSource :: fn as_str(self) -> & 'static str |
fn best_known(database : & Option <i64>, git : & Option <i64>,) -> Vec <(Option <i64>, OrderSource)> |
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 struct Entry | One migration, as the ledger holds it. |
pub enum OrderSource | Where a row's position came from, recorded because "we do not know when this ran" and "this ran at 09:41" are different facts and a ledger that blurs them is the thing being repaired. |
OrderSource :: fn as_str(self) -> & 'static str | — |
fn number_of(filename : & str) -> Option <u32> | The sequence number a migration filename carries, if any |
fn label_of(filename : & str) -> String | The words in a migration's filename, as a label a person reads |
fn title_of(filename : & str, keep_number : bool) -> String | The title a row carries, with or without its sequence number |
fn digest_of(content : & str) -> String | sha256 of the bytes that ran, as lowercase hex |
fn best_known(database : & Option <i64>, git : & Option <i64>,) -> Vec <(Option <i64>, OrderSource)> | Combine the database's record with git's, per position |
fn assign_ids(registered : & (& str, & str), known : & (Option <i64>, OrderSource), floor : i64, keep_number_in_label : bool,) -> Vec <Entry> | Build the ledger rows for a registered migration set |
No pub use re-exports: every item above is declared in this crate.
Boundary
Reaches into foundation, operations.
No other crate shares its tier.
_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) | — |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/tools/migration-ledger |
| Vocabulary in force (lexicon) | current |
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `foundation-audit-log` | foundation | no | always |
| `foundation-uuid7` | — | no | always |
| `operations-control-plane` | operations | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
chrono | ^0.4 | serde | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json, runtime-tokio, … (10 total) | no | always |
tokio | ^1 | full, macros, rt-multi-thread | no | always |
uuid | ^1 | v4, v7, serde, js, v7 | no | always |
Development. None.
Build. None.
Depended on by. Nothing in this workspace.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR SELF["tools-migration-ledger"] SELF -->|runtime| n_foundation_audit_log["foundation-audit-log"] SELF -->|runtime| n_foundation_uuid7["foundation-uuid7"] SELF -->|runtime| n_operations_control_plane["operations-control-plane"] 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
| Kind | Name | Source |
|---|---|---|
| bin | tools-migration-ledger | `src/main.rs` |
| lib | tools_migration_ledger | `src/lib.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 | yes |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
| Variable | Read in |
|---|---|
CORPUS_SOURCECODE_APP_DB | src/main.rs |
Related capabilities
No workspace crate depends on this one.
Verification
| Kind | Count |
|---|---|
| Unit tests | 11 |
| Integration tests | 0 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 8 | 0 | 0 |
What the tests establish, by name:
a_file_outside_the_series_reads_the_same_either_way—src/lib.rsa_kept_number_is_padded_so_titles_sort—src/lib.rsa_ledger_row_carries_the_bytes_and_not_a_path_to_them—src/lib.rsgit_evidence_cannot_reverse_the_sequence—src/lib.rsthe_collision_produces_two_rows_that_still_order—src/lib.rsthe_database_outranks_git_and_the_row_says_so—src/lib.rsthe_digest_is_of_the_bytes_that_ran—src/lib.rsthe_flag_decides_whether_the_number_is_inside_the_title—src/lib.rsthe_label_is_the_filename_as_a_sentence—src/lib.rsthe_number_is_the_leading_digits_and_nothing_else—src/lib.rstwo_files_may_share_a_number—src/lib.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 8 | 9 |
Public modules with a //! block | 0 | 0 |
pie showData
title Public items with rustdoc
"Documented" : 8
"No rustdoc detected" : 1
Metrics
| Metric | Value |
|---|---|
| Rust source files | 2 |
| Source lines | 644 |
| Code lines | 416 |
| Public API items | 9 |
| Public modules | 0 |
| Tests | 11 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 7 |
| Workspace reverse dependencies | 0 |
pie showData
title Public API by kind
"enum" : 1
"function" : 6
"method" : 1
"struct" : 1
pie showData
title Rust source composition
"Code" : 416
"Blank or comment" : 228
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.