| D-M2-08-0 |
2026-10-22 |
Built on the old integration line (base int/m1-wave50 with M2-05 and M2-06 merged in) and ported to main after M2-05, M2-06 and M2-07 landed: only the ticket's own commits were brought over. The spec commit that copied R-AZ-29 into the old base and the commit that took the Go test time limit from main are dropped, because main already carries both; the additions to the German chapter files of the old base go to their English files on main. The delivery suite of internal/wire waits with testkit.Patience only and proves a refused delivery by order (a later trigger must be the next invocation) instead of a fixed window. The ticket adds no migration. |
The rules of the landing replace the integration branches; main is the reference, and tests must not depend on wall-clock windows. |
| D-M2-08-1 |
2026-10-20 |
Code of the re-check principal (R-AZ-29): kernel/actor.Actor.RecheckPrincipal with the constructor actor.Recheck, read by authz through authorize.IsRecheckPrincipal. authz refuses the marker with an internal error for every action but agent.invoke and with a session, device, token, installation, "view as" or acting-for binding; liveness only from the principal status; owner status from the owner list without a session; own cache key cacheKey.recheck; the pinned version also in delivery mode. |
A delivery has no request of the person; without the marker no owner trigger (AZ-M19, every personal or host agent) would pass, and a shared key would give a personal token the owner snapshot. |
| D-M2-08-2 |
2026-10-20 |
The delivery decides agent.invoke in filter mode and writes exactly one own audit entry per denial with auditing.Recorder.Record in its unit of work (stage delivery, run, agent, event type, trigger kind, the exact authorize reason, the re-check principal as actor). |
Request mode would add a second, aggregated entry from authz for the same denial; the unit commits, so RecordDenial does not apply. |
| D-M2-08-3 |
2026-10-20 |
Delivery matrix: terminal runs are skipped without a check; agent.invocation records its jti only while queued; agent.followup and interaction.created only in waiting_input; command.invoked never. |
Only a delivery that may start or resume the run replaces runs.invocation_jti (09 5.1, D-W-44); nothing can start an ended run. |
| D-M2-08-4 |
2026-10-20 |
Reason mapping at delivery (domain.DeliveryReason): I2, SR2, project and read-only keep their codes (channel_archived is channel_read_only), principal_inactive is user_disabled, agent_not_reachable of an inactive agent is agent_disabled, every other reason access_revoked. access_revoked, agent_disabled, channel_read_only and user_disabled are also reasons of failed (09 5.2 "failed on denial before delivery"). |
The audit keeps the exact reason; the run and the person see a code of 09 5.2 (AZ-M51). |
| D-M2-08-5 |
2026-10-20 |
A denied agent.followup fails the follow-up message (trigger_state = failed) and leaves the run unchanged; M2-11 adds the state of the run_followups row. |
The run's own trigger was checked for its own invocation; another person's follow-up must not end it (09 7). |
| D-M2-08-6 |
2026-10-20 |
Skip versus error in the transports: Send = false counts as checked (the WebSocket covers it with cursor and the later ack, the REST poll with next_cursor); an error of Prepare keeps the event unsent and in flight: the consumer engine of M2-07 closes the connection with 4000 or fails the poll, and the next delivery prepares it again. |
A policy result must not stall the stream; a database or signing failure must not lose an invocation. |
| D-M2-08-7 |
2026-10-20 |
The auto thread is written only after the allow of the acceptance (the existing order of M2-05, D-M2-05-2); the delivery check decides it with InvokeFacts.NewThread, which applies the main-thread mention rule. |
A denial creates no empty thread; 05 section 5 point 3 names the main-thread rule "for new threads". |
| D-M2-08-8 |
2026-10-20 |
The acceptance keeps the audit of its denials as M2-05 built it: agent.invoke in request mode, so authz audits the denial (aggregated), without the attributes stage = acceptance and message_id of design note 10 d; silent cases and decision-function rejections write none. |
Do not change the merged acceptance of M2-05 in this ticket; the attributes are a Minor and go with the next change of the acceptance. |
| D-M2-08-9 |
2026-10-20 |
runs.invocation_jti at creation is a fresh UUIDv7 that no token carries until the first delivery replaces it (kept from D-M2-05-4). |
The column is NOT NULL; a start with any token before the first delivery fails. |
| D-M2-08-10 |
2026-10-20 |
Job runs.queued_expiry (module runs, queue default, args the run only): inserted with InsertTx at queued_at + run.queued_max_age by Open; the handler fails a due queued run with agent_unavailable, reschedules a run not yet due and does nothing otherwise; Prepare fails a too old run itself when the worker has not run the job yet. New key run.queued_max_age (default 48h). |
09 5.5 and D-AG-16; the job and the delivery serialize on the run's row lock. |
| D-M2-08-11 |
2026-10-20 |
trigger_state = queued is set by Prepare in the transaction that records the first token of an agent.invocation of a queued run whose message is still received; later deliveries do not touch it. |
Handing the event to the transport is the delivery the server can observe; a lost frame comes again after agent.ack_timeout. |
| D-M2-08-12 |
2026-10-20 |
runs.version rises by one only when Prepare stores a change (invocation_jti recorded or billing_mode_expected changed). |
03 runs.version counts changes of the row. |
| D-M2-08-13 |
2026-10-20 |
No source port DeliverySource: the REST poll of agents reads through agents.ConsumerFeed, which the consumer engine of gateway implements, and the engine calls runs.Delivery through its hook (gateway/adapters/rundelivery, replacing passdelivery). |
One engine serves the WebSocket and REST (M2-07); gateway may use runs (02 4.4), agents never imports it. |
| D-M2-08-14 |
2026-10-20 |
A personal event whose receive action takes the principal kind agent (agent.events.consume of agent.invocation, 05 section 6) is decided on its audience only in the page reads of the agent consumer engine (sync.PageInput.AgentConsumer), which pass every invocation-bearing event through runs.Delivery: there sync sets authorize.EventScope.AudienceID after it matched the audience with the receiver, and authz adds the agent of the audience as the last candidate of eventTarget. Every other path, the generic catch-up listEvents included, keeps such events filtered. |
Without it the receive action found no object on a run event and filtered every invocation (not_found); limited to the consumer engine, no path hands an agent an invocation without the delivery check (review finding M1). |
| D-M2-08-15 |
2026-10-20 |
messaging.Messages.TriggerMessageOf (trigger facts of one message without content and without authorization) and chat.TriggerChannel.SettingsVersion are added for the delivery and the payload of agent.invocation. |
The brief names the reads through the messaging port and settings_version; the merged ports lacked them. |