Files
MetaCrate/docs/grid-agent-policy.md
Chili Palmer e3b9d575f9
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m44s
CI / required (push) Failing after 2m42s
feat(grid-agent): enforce central action policy (#120)
2026-08-17 21:18:52 +00:00

4.3 KiB

Grid-agent authorization and safety policy

Every production tool action crosses PolicyGateway and then PolicyToolExecutor. The gateway is deny-by-default: a tool must be registered with its typed argument schema, capability, read/write risk, allowed origins, maximum resource cost, deterministic cost estimator, idempotency, approval rule, and scheduler eligibility. A tool description is model context, not authority, and is never consulted by policy.

Identity and origin matrix

Grid authority comes only from the sender UUID carried by the grid event. Names, message bodies, UUID text embedded in messages, and tool arguments cannot select an origin. Local-operator principals can only be constructed by the crate's authenticated control-plane boundary. Scheduler contexts require an opaque grant previously issued from an authorized IM or operator action.

Origin Informational read Public LSL delivery capability Allow-listed mutation Scheduled action
Public chat, including an authorized avatar yes yes no no
Unprivileged IM yes no no no
Authorized IM when registered when registered when registered may create an exact grant
Authenticated local operator when registered when registered when registered may create an exact grant
Internal scheduler exact grant only no exact grant only bounded runs and expiry

The public LSL capability is a narrow inventory-mutation marker for the later script-delivery workflow; it does not permit executing generated code or any other public command. Tool names are exact ASCII identifiers, so case changes, newlines, smuggled names, and Unicode confusables do not resolve to registered tools.

Approvals and budgets

Arguments are parsed again at the gateway and must equal the arguments bound to the proposed call. Canonical JSON is SHA-256 hashed. An approval binds that hash, exact tool, requesting principal, expiry, and one execution. Changed arguments, another principal, an ungranted/expired approval, or a replay is a stable denial. Authorization is represented by non-cloneable AuthorizedAction, whose fields have no public constructor; action backends cannot accept a raw call plus a caller-created decision.

Each authorized attempt atomically charges a configured time-window budget for both the originating principal and the whole agent. The resource vector covers tool-call rate, L$, upload bytes, inventory operations, movement millimetres, and build prims. Hard ceilings validate configured budgets and per-tool maximum costs. This milestone fixes every L$ budget at zero and refuses registration or execution for currency spend, estate/parcel changes, permanent deletion, arbitrary inventory acceptance, and generated-code execution.

Scheduler grants preserve the originating principal and bind one tool and argument hash. Run count and lifetime are bounded; every run is charged again. The opaque PolicySnapshot preserves budgets, approvals (including consumed replay state), and scheduler grants when a trusted persistence integration reconstructs the gateway. No durable policy store is enabled by the current offline service; a future store must protect snapshot integrity rather than accept caller-authored approval data.

Prompt and audit boundaries

Chat, IM, inventory metadata, object text, parcel data, web/LLM output, and generated scripts use UntrustedData. It emits a bounded labelled JSON data record and never contributes system instructions or tool availability. This is defence in depth: authorization is still enforced after inference at the exact gateway.

Every decision emits a bounded structured PolicyAuditRecord before an action is authorized. It contains origin class and UUID where applicable, principal, session/correlation IDs, exact tool, disposition, stable reason code, applied budget, an argument hash, and outcome. The executor emits the completed, rejected, failed, or ambiguous final outcome. Raw/secret arguments and hidden reasoning are never stored. Audit backpressure fails closed before issuing a new authorization.

Focused verification:

cargo test --locked -p metacrate-grid-agent --lib policy_tests
cargo test --locked -p metacrate-grid-agent --test policy_gateway
cargo clippy --locked -p metacrate-grid-agent --all-targets -- -D warnings