refactor(mcp): the party_id, document_id and cash_account aliases are removed (P5)

Agent reason: one name for one thing. S4 and S6 kept the old spellings "until
P5" so an agent that learned them did not break; P5 removes them, so the
schema an agent reads has one parameter for each fact and a call cannot name
the same thing twice with different answers.

books.create_invoice takes customer and books.create_bill vendor (a record's
id, its party's id or its name; required), no party_id.
books.receive_payment and books.pay_bill take invoice or bill and
deposit_to or paid_from, no document_id or cash_account; a payment names its
document and its account or is refused saying which to pass. A number that is
one record's id and another's name is still refused, never guessed (INVARIANT
6).

The over-the-wire tests that used the old spellings now use the new
(document_id becomes invoice or bill, cash_account becomes deposit_to or
paid_from, party_id becomes customer or vendor given as the id's text); the
one test that named the alias, party_id_alias_still_works, is now
a_customer_by_id_and_by_name_is_one_record and checks the same two spellings
of a customer, by id and by name, name one record.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
swaitsandClaude Fable 5.1 committed 2026-10-29 15:48:27 -06:00
1 parent 70a3f795f4
commit a319a64c3a
13 files changed
+81 -135

No files matched your search

+2 -22
View File
@@ -455,17 +455,7 @@ impl BooksServer {
) -> Result<Json<InvoiceOut>, String> {
let p = params.0;
let mut store = self.lock()?;
let customer = match (&p.customer, p.party_id) {
(Some(c), None) => c.trim().to_string(),
(None, Some(id)) => id.to_string(),
(Some(c), Some(id)) if c.trim() == id.to_string() => c.trim().to_string(),
(Some(_), Some(_)) => {
return Err("give the customer once: customer or party_id, not both".into());
}
(None, None) => {
return Err("give customer: a customer id, a party id or a name".into());
}
};
let customer = p.customer.trim().to_string();
let customer_id = resolve_customer(&store, &customer)?;
let date = parse_date(&p.date)?;
let lines = document_lines(&store, p.lines)?;
@@ -606,17 +596,7 @@ impl BooksServer {
) -> Result<Json<BillOut>, String> {
let p = params.0;
let mut store = self.lock()?;
let vendor = match (&p.vendor, p.party_id) {
(Some(v), None) => v.trim().to_string(),
(None, Some(id)) => id.to_string(),
(Some(v), Some(id)) if v.trim() == id.to_string() => v.trim().to_string(),
(Some(_), Some(_)) => {
return Err("give the vendor once: vendor or party_id, not both".into());
}
(None, None) => {
return Err("give vendor: a vendor id, a party id or a name".into());
}
};
let vendor = p.vendor.trim().to_string();
let vendor_id = resolve_vendor_arg(&store, &vendor)?;
let date = parse_date(&p.date)?;
let received_on = p.received_on.as_deref().map(parse_date).transpose()?;
+9 -29
View File
@@ -39,35 +39,17 @@ fn doc_party(ledger: &Ledger, doc: ledger_core::DocRef) -> Result<u64, String> {
}
}
/// The one id a payment tool's single form names: `invoice`/`bill`, or
/// the older `document_id`. Both at once is refused unless they agree.
fn single_document(primary: Option<u64>, alias: Option<u64>, what: &str) -> Result<u64, String> {
match (primary, alias) {
(Some(a), Some(b)) if a != b => Err(format!(
"pass {what} or document_id, not both: {} and {b} differ",
a
)),
(Some(id), _) | (None, Some(id)) => Ok(id),
(None, None) => Err(format!(
"pass {what} (or an applications list): see books.documents"
)),
}
/// The one id a payment tool's single form names: `invoice` or `bill`.
fn single_document(primary: Option<u64>, what: &str) -> Result<u64, String> {
primary.ok_or_else(|| format!("pass {what} (or an applications list): see books.documents"))
}
/// The one account a payment tool's single form names: `deposit_to`/
/// `paid_from`, or the older `cash_account`.
fn single_account(
primary: &Option<String>,
alias: &Option<String>,
what: &str,
) -> Result<String, String> {
match (primary, alias) {
(Some(a), Some(b)) if a != b => Err(format!(
"pass {what} or cash_account, not both: {a:?} and {b:?} differ"
)),
(Some(a), _) | (None, Some(a)) => Ok(a.clone()),
(None, None) => Err(format!("pass {what} (or cash_account)")),
}
/// The one account a payment tool's single form names: `deposit_to` or
/// `paid_from`.
fn single_account(primary: &Option<String>, what: &str) -> Result<String, String> {
primary
.clone()
.ok_or_else(|| format!("pass {what}: the account the cash moves through"))
}
/// Every document a payment tool's parameters name, as the core takes
@@ -128,7 +110,6 @@ fn applications(
}
let id = single_document(
if invoices { p.invoice } else { p.bill },
p.document_id,
if invoices { "invoice" } else { "bill" },
)?;
let amount = p
@@ -178,7 +159,6 @@ fn settlement(
} else {
&p.paid_from
},
&p.cash_account,
if invoices { "deposit_to" } else { "paid_from" },
)?,
)?;
+2 -16
View File
@@ -3265,10 +3265,7 @@ pub struct CreateInvoiceParams {
pub preview: Option<String>,
/// The customer: a customer id, its party's id, or its name. A name
/// that two customers answer to is refused.
pub customer: Option<String>,
/// The old spelling of `customer` (accepted until P5): a customer id.
#[serde(default)]
pub party_id: Option<u64>,
pub customer: String,
/// The invoice date, YYYY-MM-DD.
pub date: String,
/// Its payment terms ("Net 30", "Net 15 EOM", "2/10 net 30", "Due on
@@ -3300,10 +3297,7 @@ pub struct CreateBillParams {
pub preview: Option<String>,
/// The vendor: a vendor id, its party's id, or its name. A name that
/// two vendors answer to is refused.
pub vendor: Option<String>,
/// The old spelling of `vendor` (accepted until P5): a vendor id.
#[serde(default)]
pub party_id: Option<u64>,
pub vendor: String,
/// The bill's date, YYYY-MM-DD.
pub date: String,
/// The day the bill was received, when it differs from its date.
@@ -3383,10 +3377,6 @@ pub struct PaymentParams {
/// preview: nothing posts.
#[serde(default)]
pub confirmed: Option<bool>,
/// Invoice id (receive_payment) or bill id (pay_bill); the older name
/// of `invoice` / `bill`.
#[serde(default)]
pub document_id: Option<u64>,
/// The invoice, by id (books.receive_payment).
#[serde(default)]
pub invoice: Option<u64>,
@@ -3399,10 +3389,6 @@ pub struct PaymentParams {
/// applications' amounts are the cash; a discount is beside it.
#[serde(default)]
pub amount: Option<String>,
/// Cash account id or code; the older name of `deposit_to` /
/// `paid_from`.
#[serde(default)]
pub cash_account: Option<String>,
/// The account the cash reaches (receive_payment): a bank or card that
/// holds no role.
#[serde(default)]