84 lines
2.5 KiB
Rego
84 lines
2.5 KiB
Rego
|
|
# METADATA
|
||
|
|
# title: Transformation policy for per-diem compute
|
||
|
|
# description: |
|
||
|
|
# Only agent-per-diem-calculator may run expense.compute_per_diem.
|
||
|
|
# Output must consist exclusively of items whose type is PER_DIEM_*,
|
||
|
|
# each with a computed_from.transform_attestation_ref back-reference
|
||
|
|
# and a positive amount. Enforces separation between LLM agents (free-form)
|
||
|
|
# and deterministic compute agents (strict shape, no free-form fields).
|
||
|
|
# authors:
|
||
|
|
# - CTO Agent <cto@basicstack.de>
|
||
|
|
# related_resources:
|
||
|
|
# - ref: docs/architecture/v1.1.md#user-content-62-deterministische-regelwerke-am-beispiel-spesensätze-verpflegungsmehraufwand
|
||
|
|
# - ref: schemas/expense/canonical/v1.2.0.json
|
||
|
|
package proofedmesh.transformations.per_diem
|
||
|
|
|
||
|
|
import rego.v1
|
||
|
|
|
||
|
|
default allow := false
|
||
|
|
|
||
|
|
allow if {
|
||
|
|
input.agent_id == "agent-per-diem-calculator"
|
||
|
|
input.operation == "expense.compute_per_diem"
|
||
|
|
input.output_schema.name == "expense.canonical"
|
||
|
|
input.output_schema.version == "1.2.0"
|
||
|
|
all_items_are_per_diem
|
||
|
|
all_items_have_computed_from
|
||
|
|
all_amounts_positive
|
||
|
|
}
|
||
|
|
|
||
|
|
per_diem_types := {"PER_DIEM_FULL", "PER_DIEM_PARTIAL", "PER_DIEM_ARRIVAL", "PER_DIEM_DEPARTURE"}
|
||
|
|
|
||
|
|
all_items_are_per_diem if {
|
||
|
|
every item in input.output_payload.expense_items {
|
||
|
|
item.type in per_diem_types
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
all_items_have_computed_from if {
|
||
|
|
every item in input.output_payload.expense_items {
|
||
|
|
item.computed_from.transform_attestation_ref != ""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
to_cents(s) := n if {
|
||
|
|
n := round(to_number(s) * 100)
|
||
|
|
}
|
||
|
|
|
||
|
|
all_amounts_positive if {
|
||
|
|
every item in input.output_payload.expense_items {
|
||
|
|
to_cents(item.amount) > 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
deny_reason contains msg if {
|
||
|
|
input.agent_id != "agent-per-diem-calculator"
|
||
|
|
msg := sprintf("agent %s not allowed to compute per_diem", [input.agent_id])
|
||
|
|
}
|
||
|
|
|
||
|
|
deny_reason contains msg if {
|
||
|
|
input.operation != "expense.compute_per_diem"
|
||
|
|
msg := sprintf("operation %s not allowed", [input.operation])
|
||
|
|
}
|
||
|
|
|
||
|
|
deny_reason contains msg if {
|
||
|
|
input.agent_id == "agent-per-diem-calculator"
|
||
|
|
input.operation == "expense.compute_per_diem"
|
||
|
|
not all_items_are_per_diem
|
||
|
|
msg := "compute output must contain only PER_DIEM_* typed items"
|
||
|
|
}
|
||
|
|
|
||
|
|
deny_reason contains msg if {
|
||
|
|
input.agent_id == "agent-per-diem-calculator"
|
||
|
|
input.operation == "expense.compute_per_diem"
|
||
|
|
not all_items_have_computed_from
|
||
|
|
msg := "every computed item must carry computed_from.transform_attestation_ref"
|
||
|
|
}
|
||
|
|
|
||
|
|
deny_reason contains msg if {
|
||
|
|
input.agent_id == "agent-per-diem-calculator"
|
||
|
|
input.operation == "expense.compute_per_diem"
|
||
|
|
not all_amounts_positive
|
||
|
|
msg := "all computed per-diem amounts must be strictly positive"
|
||
|
|
}
|