Skip to content

Technical article

Approved at 5:05: When Time Becomes Part of an Agent Policy

Follow one vendor transfer from a simple business-hours rule through live revalidation, a shared 24-hour budget, reservations, and auditable time evidence.

  • Time-aware policy
  • Delayed approval
  • Shared state

01 · One transfer, several clocks

A $50 transfer is approved at 5:05. Should it run?

At 4:55 p.m., an agent asks to send $50 to a vendor. Transfers above $40 require a person to review them, so the operation waits. The reviewer approves at 5:05. The organization’s operating window closed at 5:00. Is the transfer still allowed?

The answer depends on what “during business hours” means. It might mean the request reached the service before closing. It might mean MasuGate admitted the operation into its protected decision path before closing. It might require the approval evaluation, the database commit, or even a remote provider’s completion to happen before closing. Those are five different rules.[1]

4:55 · Admitted

The governed operation starts in-window

MasuGate has protected the shared state needed for the decision and certified the admission-time fact.

4:55–5:05 · Waiting

Pending is not permission

A human can review the intent, but the transfer cannot bypass the governed resolution path.

5:05 · Re-evaluated

The live window is now closed

Approval is one input; fresh policy state still decides whether the effect may proceed.

02 · Make the business meaning explicit

The request can be on time while authorization is too late.

MasuGate uses certified inputs for small trusted facts. One fact records whether protected admission occurred inside the configured operating window. Another is refreshed for the protected authorization evaluation. The first is historical; the second can change while a request waits.[1][2]

A provider is the trusted component that owns an authoritative fact, resource, or effect boundary. A logical scope is the shared slice—such as one team’s budget—that related operations must coordinate over.

Admission time and live authorization time
MasuGate PVL
policy transfer_live_window on transfer {
  deny admitted_outside_window when
    certified.request_time_window_open == false;
  deny authorization_window_closed when
    certified.live_resolution_window_open == false;
  escalate high_value_review when args.amount_cents > 4000;
  allow otherwise;
}

Amounts use cents, so 4000 means $40. The clock and timezone come from the provider contract, not from the agent.

Read the complete time-aware policy guide

Read the policy from top to bottom. A transfer admitted outside the window is denied. An operation whose live authorization evaluation occurs after closing is also denied. Only after those checks does a high-value request enter review. When the reviewer responds, resolution returns through MasuGate and refreshes the live fact.

Protected admission is not network arrival. In the reference path, MasuGate establishes the admission-time anchor after protecting the shared state needed for the decision. Queue or lock wait can move that anchor past closing. This keeps the clock meaning honest instead of letting a client-supplied timestamp control the outcome.[1]

03 · Time can also describe shared history

“The last 24 hours” is policy state, not just clock arithmetic.

Now give the team a $1,000 limit over committed transfers in the provider’s rolling 24-hour window. The policy needs the current account balance, the team’s retained transfer history, a trusted evaluation anchor, and a clear definition of which events count.

Current balance plus rolling team spend
MasuGate PVL
policy transfer_rolling_budget on transfer {
  deny insufficient_funds when
    accounts.balance(principal.id) < args.amount_cents;
  deny daily_team_budget when
    ledger.sum_sent_by_team(principal.team, 24h)
      + args.amount_cents > 100000;
  allow otherwise;
}

The 24h token is a typed Duration. This reference view counts committed provider effects, not every attempted request.

Inspect the PostgreSQL provider

Suppose the team has already spent $990. Two agents concurrently request different $10 vendor transfers. Each fits if it reads the same old total. Together they would exceed the rule. MasuGate makes the team budget a shared logical scope, so both operations cannot spend the same last $10: one can commit at the limit, and the other must observe the updated state and deny.[4][1]

04 · Delayed decisions

Human review forces a choice: revalidate current truth or reserve capacity.

A reviewer needs time. During that interval, the business window can close, the account balance can change, and another agent can consume the remaining team budget. MasuGate therefore treats pending as durable state, not as an allow token waiting to be redeemed.[4]

Revalidate

Ask whether the action is still allowed

Reacquire the relevant scopes, refresh volatile facts, and evaluate current balance and budget. Approval can still end in denial.

Reserve

Preserve one narrow resource

Hold scarce capacity while review waits, like holding a seat. The reservation is visible to competing operations but is not blanket permission.

Revalidation favors current truth and leaves capacity available to other work. Reservation gives the reviewer a stronger expectation about one admitted capacity predicate. Approved transfer resolution must validate and consume the live entitlement before applying the database transfer in the same locked transaction. Rejection releases it; provider expiry processing releases stale capacity; and late resolution fails closed.[1][2]

05 · Provider-owned event history

Freshness, cooldowns, and request-bound approval can share the same policy story.

The policy language does not need to hand every rule an unrestricted clock. A provider can expose bounded temporal views with typed duration arguments. In the vendor-transfer story, a deployment could require a fresh vendor assessment, reject a recent duplicate to the same vendor, and require a still-valid approval bound to the exact high-value request.[1]

Some policies need to ask what happened before this request: Was this exact transfer approved recently? How many protected attempts came from this team? How much money actually settled? The repository now includes an experimental, opt-in event-history provider that authenticates and retains protected lifecycle events, then exposes three fixed, typed, scoped, and versioned answers: transfer-attempt count, distinct transfer receivers, and recent approval bound to the exact request. It is disabled by default and remains outside the 0.1.1 release boundary.[1][3]

  • Freshness — vendor.assessment_fresh(receiver, 5m): is the authoritative vendor assessment recent enough?
  • Matching prerequisite — history.recent_bound_approval(principal.id, request.digest, 30m): did approval for this exact transfer occur recently enough?
  • Recent count — history.transfer_attempt_count(team, 10m): how many protected attempts occurred in the window?
  • Distinct count — history.distinct_transfer_receivers(team, 24h): how many different vendors were involved?
  • Rolling sum — ledger.sum_sent_by_team(team, 24h): how much actually committed?
  • Sequence condition — history.vendor_reviewed_since_change(receiver, 30d): did the required review happen after the vendor record last changed within the retained window?

These views turn a potentially large event log into small policy questions. Their names alone do not define the answer: the provider must say whether denied attempts count, whether the current event is included, how retries are deduplicated, which clock and scope apply, and which lifecycle transition updates the history. One-use approval must be consumed from the same approval scope in the protected transaction that relies on it, or through a provider-bound entitlement protocol. The three named history views above are implemented as an experimental opt-in provider, not as part of 0.1.1, and remain disabled by default. vendor.assessment_fresh(...), arbitrary history.* contracts, a temporal-query language, automatic request/response ingestion, and the sequence view remain future extensions; ledger.sum_sent_by_team(team, 24h) remains the separate current reference view.[3][1]

06 · Be precise about deadlines

A fact observed before closing is not proof that every later step finished before closing.

The live-window fact answers whether the window was open at a protected authorization evaluation. A slow database transaction might commit later. A remote API might accept a request now and complete it minutes afterward. If the policy truly requires commit or remote completion before a deadline, the provider or connector must define and authoritatively observe that event.[1]

  • Admission deadline: bind the rule to protected admission, not network arrival.
  • Authorization deadline: refresh a certified fact for the protected evaluation.
  • Serialization or handoff deadline: bind the check and authority consumption at the named provider boundary.
  • Completion deadline: require authoritative completion evidence from the system that performs the work.

The same care applies to expiry. Generic transfer revalidation has no automatic approval timeout. The transfer reservation has its own fixed one-hour entitlement. A separate spend.purchase profile defaults to a 600-second deadline for durably recording initial human approval. None of these statements means a remote purchase must finish inside the same interval.[1][2]

07 · Evidence after the decision

A time-aware decision should carry its clock and history forward.

An operation record should preserve the protected admission and evaluation anchors, certified-input source and freshness, duration arguments, values and versions read, policy revision, decision, effect, and the causal links among reservation and settlement. Otherwise a later reviewer sees a timestamp without knowing which question it answered.[1]

Policy-State Serializability, or PSS, checks whether terminal decisions and visible coordination transitions fit a real-time-respecting serial explanation over the declared policy state. The structural checker does not interpret an evaluation timestamp or prove a wall-clock deadline. A provider-aware validator must replay what each recorded time predicate meant.[4][1]

That brings us back to 5:05. The reviewer’s approval matters, but it does not erase the closing time, preserve an old balance, or mint reusable permission. MasuGate lets the policy say which temporal facts are historical, which must be refreshed, which capacity can be held, and what evidence must survive the outcome.

Publication boundary

Evidence and limitations

Evidence · Reference

MasuGate 0.1.1 research-preview source tree and docs/time-aware-policies.md

This article explains current policy syntax, shipped provider contracts, tested transfer policy shapes, and clearly labeled extension designs. It does not promote the combined clocked-transfer composition or illustrative temporal views to a turnkey release claim.

Limitations
  • The shipped certified-time contracts and asynchronous PostgreSQL transfer path still require a compatible adapter and deployment composition before the combined examples become a turnkey reference profile.
  • The repository now contains an experimental, opt-in event-history provider with three fixed transfer views: protected-attempt count, distinct receivers, and recent request-bound approval. It remains outside 0.1.1 and disabled by default; vendor freshness, arbitrary history.* views, a temporal-query language, automatic request/response ingestion, and sequence views remain future extensions.
  • A live-window fact establishes truth at a protected evaluation point; it does not by itself prove that a database commit or remote completion occurred before closing.
  • The current transfer reservation has a fixed one-hour entitlement and a proof bound to the configured 24-hour argument; its escrow counter requires a sound reset or rebase before claiming continuously sliding reservation semantics.

Primary sources

Sources and further reading

  1. Time-Aware Policies in MasuGateMasuGate repository documentation

    The detailed guide behind this article, including policy examples, provider obligations, implementation status, and exact temporal boundaries.

  2. MasuGate public source repositoryGitHub

    Source for the policy language, certified-context contracts, PostgreSQL rolling-budget views, reservation path, tests, and PSS checker.

  3. Bounded Event History for PolicyMasuGate repository documentation

    The exact experimental provider contracts, opt-in activation path, evidence model, and current limitations.

  4. Stateful Governance for Concurrent Agentic SystemsarXiv:2608.02764

    The in-depth model behind MasuGate’s treatment of mutable policy state, concurrent effects, delayed decisions, and policy-state serializability.

Continue exploring

Related paths