feat(drafts): the drafts tools, the preview digest on every confirm, the digest tool (P4)
Accounting reason: a confirm must act on the thing that was previewed. Every tool with confirmed (post_entry, reverse_entry, run_schedules, dispose_asset, reconcile, close_period, create_invoice, create_bill, write_off_invoice, purge_tin, consolidate_duplicates, and the S6 settlement tools receive_payment and pay_bill, which gain confirmed and preview on a clone of the ledger) returns preview (SHA-256 of the canonical preview) and refuses a confirm whose preview is missing or stale (stale_preview, before anything is written). A draft's digest is its own state and the settings seq; an operation's is the tool, its arguments as sent, the settings seq and the journal head seq, so another session's write forces a re-preview (D-50). New tools books.list_drafts, books.set_draft_state, books.discard_draft, books.preview_entry; reports carry as_of_status (drafts open on or before their end, unreconciled accounts, settings problems) and take strict; the CPA package is refused while a draft dated in it is open unless allow_open_drafts gives a reason, journaled as a decision; books.digest takes since_seq (what was posted since a journal line, backdated entries included: defect 6) and lists zero_net_accounts, drafts_by_state and the reconciliation split. Needs attention gains 'draft awaiting receipt' beside 'draft not posted'; the drafts handbook is rewritten. Every over-the-wire harness confirms the way an agent does. Docs: mcp-interface, rules B-43, parity, testing (with the For-P12 paragraph), architecture, and the unit's As-built block. Tests: drafts.rs (a_draft_waits_for_its_receipt_and_posts, the_gate_moved_and_the_mcp_error_is_unchanged, a_reversal_needs_no_receipt_of_its_own, discard_unblocks_the_close_over_the_wire, report_warns_on_draft_before_as_of, cpa_package_refuses_open_draft, stale_preview_refused, every_confirm_tool_takes_a_preview, digest_since_seq_is_posting_time, legacy_reversed_replays_identically, gui_and_server_gate_agree), attention_parity.rs, format_upgrade.rs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
7299cf90f2
commit
6a66a2855b
49 files changed
+2526
-202
No files matched your search
@@ -20,6 +20,8 @@
|
||||
//! ```
|
||||
#![cfg(target_os = "linux")]
|
||||
|
||||
mod common;
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -332,7 +334,7 @@ impl Agent {
|
||||
|
||||
/// Call a tool: Ok(its structured result) or Err(the error's text).
|
||||
fn call(&mut self, tool: &str, args: Value) -> Result<Value, String> {
|
||||
let r = self.request("tools/call", json!({"name": tool, "arguments": args}), 60);
|
||||
let r = common::tools_call(|m, p| self.request(m, p, 60), tool, args.clone());
|
||||
if let Some(e) = r.get("error") {
|
||||
return Err(e["message"].as_str().unwrap_or_default().to_string());
|
||||
}
|
||||
@@ -792,8 +794,38 @@ fn books_p2_served_cut_over_whole() {
|
||||
)
|
||||
.unwrap()["id"]
|
||||
.clone();
|
||||
// A draft P2 reads (the old shape): its state and its discard are
|
||||
// drafts_v2's, and wait.
|
||||
let waiting_draft = a
|
||||
.call(
|
||||
"books.draft_entry",
|
||||
json!({"date": "2026-02-12", "description": "Waiting for a receipt",
|
||||
"no_party_reason": "test"}),
|
||||
)
|
||||
.unwrap()["entry_id"]
|
||||
.clone();
|
||||
for (account, side) in [("6600", "debit"), ("1000", "credit")] {
|
||||
a.call(
|
||||
"books.add_line",
|
||||
json!({"entry_id": waiting_draft, "account": account, "side": side,
|
||||
"amount": "10.00"}),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let waiting = journal(&dir);
|
||||
let refused: Vec<(&str, Value)> = vec![
|
||||
// A draft's state and its discard (drafts_v2, P4): an older
|
||||
// version refuses the types.
|
||||
(
|
||||
"books.set_draft_state",
|
||||
json!({"entry_id": waiting_draft, "state": "awaiting_evidence",
|
||||
"note": "the travel receipt"}),
|
||||
),
|
||||
(
|
||||
"books.discard_draft",
|
||||
json!({"entry_id": waiting_draft, "reason": "entered twice",
|
||||
"confirmed": true}),
|
||||
),
|
||||
// An invoice carrying documents_v2's fields (terms: P4b S4.4) and
|
||||
// its line naming its project (document_line_projects, rules.md
|
||||
// B-37 item 8).
|
||||
|
||||
Reference in new issue
Block a user