Projects: classes as entities, and the sidebar fits short windows
check / check (push) Canceled after 0s

A project is a class with facts (description, status, kind, party,
dates, links, notes) in one project.set event behind the format
feature projects. Four tools (books.add_project, update_project,
projects, project); documents and decisions link to projects; B-37:
on-spec costs are expensed as incurred, repayment is revenue, and the
unrecovered cost is never below zero (Kani). Viewer: a Projects list
and a project page with its figures, by month and by account. The
sidebar measures its footer instead of reserving a fixed 172 px.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-22 03:50:52 -06:00
1 parent 0495726001
commit 321b94562a
71 files changed
+7446 -217

No files matched your search

+21
View File
@@ -1491,6 +1491,27 @@ pub fn basis_figures<T: Amount>(
})
}
/// A project's unrecovered cost from its tagged revenue and expenses to
/// date: what it would take to be repaid in full (rules.md B-37 item 4).
///
/// ```text
/// GOAL: the "if repaid" figure of work done on spec, from one function
/// the tools, the viewer and bookspec share.
/// SOURCE: docs/spec/rules.md B-37 item 4 (ASC 450-30-25-1: a hoped-for
/// payment is a gain contingency, never recorded before it is
/// received; so this is a figure, never a receivable).
/// INVARIANTS:
/// 1. Never below zero.
/// 2. expenses - revenue when expenses >= revenue; zero otherwise.
/// 3. Never above max(expenses, 0) when revenue >= 0 (expenses can be
/// negative: a reimbursement credited to the expense above its cost).
/// 4. NEVER wraps: None when the difference can't be represented.
/// ```
pub fn unrecovered_cost<T: Amount>(revenue: T, expenses: T) -> Option<T> {
let gap = expenses.checked_sub(revenue)?;
Some(if gap > T::ZERO { gap } else { T::ZERO })
}
#[cfg(test)]
mod tests {
use super::*;