viewer: journal text for asset.acquisition_linked; a test that every event type the store writes has plain-language journal text
check / check (push) Waiting to run
check / check (push) Waiting to run
The acquisition link was added after the viewer's asset work and showed its raw event name in recent activity. The new test reads the event types from the store's replay arms, so the next new event without text fails it (checked: it fails without this fix). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
ee7e205f5c
commit
2e14c702c0
3 files changed
+55
-9
No files matched your search
@@ -267,6 +267,18 @@ pub fn describe(b: &Books, line: &JournalLine) -> Option<Event> {
|
||||
};
|
||||
ev(icon::BARCODE, text, asset_id.map(Route::Asset))
|
||||
}
|
||||
"asset.acquisition_linked" => {
|
||||
let entry = p.get("entry_id").and_then(|v| v.as_u64()).unwrap_or(0);
|
||||
Some(Event {
|
||||
icon: icon::LINK,
|
||||
text: format!(
|
||||
"Linked {} to the entry that acquired it, #{entry}",
|
||||
asset(asset_id)
|
||||
),
|
||||
route: asset_id.map(Route::Asset),
|
||||
also: Some(Route::Entry(entry)),
|
||||
})
|
||||
}
|
||||
"asset.depreciation_posted" => with_asset(
|
||||
icon::TREND_DOWN,
|
||||
format!(
|
||||
|
||||
@@ -612,3 +612,42 @@ proptest! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Every event the store can journal reads as a sentence in the journal
|
||||
/// and recent activity, never as its raw type: the event types come from
|
||||
/// the store's own source (its replay arms), so a new event without
|
||||
/// journal text fails here. (asset.acquisition_linked showed raw,
|
||||
/// 2026-10-15.)
|
||||
#[test]
|
||||
fn every_journal_event_has_plain_language_text() {
|
||||
let src = include_str!("../../ledger-store/src/store.rs");
|
||||
let mut kinds: Vec<&str> = src
|
||||
.lines()
|
||||
.flat_map(|l| l.split('"').skip(1).step_by(2))
|
||||
.filter(|t| {
|
||||
let mut parts = t.split('.');
|
||||
matches!(
|
||||
(parts.next(), parts.next(), parts.next()),
|
||||
(Some(a), Some(b), None)
|
||||
if !a.is_empty() && !b.is_empty()
|
||||
&& a.chars().chain(b.chars()).all(|c| c.is_ascii_lowercase() || c == '_')
|
||||
)
|
||||
})
|
||||
.filter(|t| src.contains(&format!("\"{t}\" =>")) || src.contains(&format!("\"{t}\" |")))
|
||||
.collect();
|
||||
kinds.sort_unstable();
|
||||
kinds.dedup();
|
||||
assert!(kinds.len() > 30, "found only {kinds:?}");
|
||||
let f = fixture("every-event");
|
||||
for kind in kinds {
|
||||
let line = ledger_store::JournalLine {
|
||||
seq: 1,
|
||||
ts: "2026-10-15T00:00:00Z".into(),
|
||||
line_type: kind.to_string(),
|
||||
payload: serde_json::json!({}),
|
||||
prev: String::new(),
|
||||
};
|
||||
let e = ledger_gui::pages::journal::describe_any(&f.books, &line);
|
||||
assert_ne!(e.text, kind, "{kind} has no journal text");
|
||||
}
|
||||
}
|
||||
@@ -27,15 +27,10 @@ pub struct JournalLine {
|
||||
pub seq: u64,
|
||||
/// UTC timestamp, RFC 3339. Recorded, never trusted for ordering.
|
||||
pub ts: String,
|
||||
/// Event type: `account.added`, `entry.created`, `entry.line_added`,
|
||||
/// `entry.posted`, `entry.reversed`, `entry.line_class_set`,
|
||||
/// `receipt.attached`, `receipt.linked`, `receipt.unlinked`,
|
||||
/// `document.filed`, `attachment.withdrawn`,
|
||||
/// `asset.registered`, `asset.depreciation_posted`, `asset.disposed`,
|
||||
/// `period.created`, `period.closed`, `line.cleared`, `customer.added`,
|
||||
/// `vendor.added`, `invoice.created`, `bill.created`,
|
||||
/// `invoice.payment_received`, `bill.paid`, `fx.rate_set`,
|
||||
/// `payroll.run`, `class.added`, `store.created`.
|
||||
/// Event type, e.g. `account.added`, `entry.posted`, `asset.tagged`:
|
||||
/// every type the store writes has a replay arm in
|
||||
/// `replay_line_into_ledger` (an unknown type is refused as corrupt),
|
||||
/// and journal text in the viewer (`ledger-gui` tests check both).
|
||||
#[serde(rename = "type")]
|
||||
pub line_type: String,
|
||||
/// The full domain facts. Everything a replay needs.
|
||||
|
||||
Reference in new issue
Block a user