Skip to content

M2-13 Run context with origin and trust

No Date Ruling Reason
D-M2-13-0 2026-10-24 The ticket was first built on an older integration base together with its dependencies M2-11 and M2-12, then ported onto main after both landed there: a fresh branch from main with the ticket's own commits only, generated files (sqlc, REST objects and clients, the contract copy of the fake, the config schema and the configuration reference) regenerated on main rather than merged, and the test worlds taking the module configs over the schema defaults. It lands by pull request. Dependencies first, one pull request per ticket on main.
D-M2-13-1 2026-10-21 The trust facts come from the kernel port authorize.TriggerHolders (WithTrigger), implemented by the authz Authorizer and handed to runs by internal/wire; runs never derives a level and never imports authz. 02 4.5 names the port. 05 rule 1.1, 02 4.4: no permission logic outside authz.
D-M2-13-2 2026-10-21 WithTrigger judges each person with a snapshot without credentials at the rights version of the request (cached like "view as"): active humans only, grants of the person and its groups, the DM rule and the archive cap. An active owner counts as authorized on every channel that is not a DM; people who are not active, agents, apps and unknown ids never count. Trust asks whether the person may instruct the agent; an owner triggers from any session (05 2.3 point 1), while Authorize grants the owner role only in a session (R-AZ-14).
D-M2-13-3 2026-10-21 Classification: origin decides before the author (system gives other/system; import and app give other/unverified; agent gives assistant/self for the run's agent, otherwise other/unverified; human gives user with trigger, authorized or unverified). An unknown origin is other/unverified. An imported message mapped to a person must not pass as that person's request (T-AI-03); a system line may carry a person as author (03 messages).
D-M2-13-4 2026-10-21 Only own runs in queued, running or waiting_input have a context; any other state answers the same 404 as an unknown run. queued is readable because the adapter reads the context before startRun. 05 4.10 "own active runs"; 04 15.3 point 4; AZ-P4.
D-M2-13-5 2026-10-21 Session mode, floor and own messages: the mode is DecideSession of M2-12 over the session row of the run (runs.agent_session_id, read through agents.RunSessions; zero is no session) when it belongs to the run's agent, so a reset or bind during the run (09 9.4) does not change the mode the invocation announced (red team M1), with "used" meaning a started run of the agent in that session queued before this run. new, bind and guest runs have floor zero, include the agent's own messages and want channel_context; resume leaves the own messages out, has no channel_context, and its floor is the thread_seq of the triggering message of the latest earlier started run that has one, zero when that message lies outside the thread (the parent of an auto thread). Delivery and context use one rule; a thread_seq of the main thread is no floor inside the thread.
D-M2-13-6 2026-10-21 channel_context exists only when the plan wants it, the thread has a parent message the agent may read, and the parent lies in the thread's current channel; the window is the parent's main thread before the parent, without the parent itself. After a move it is absent. Content of a source channel must not reach the readers of the target (T-AI-01, SR9, 07 6).
D-M2-13-7 2026-10-21 Tombstones are not selected into thread_context or channel_context and count towards no limit; the triggering message appears as stored (a deleted one with empty content). The window's limit counts only what the agent can use.
D-M2-13-8 2026-10-21 Byte accounting counts only content_md after the per-element cut at the longest valid UTF-8 prefix within agent.context_message_max_bytes; the budget agent.context_max_bytes keeps a contiguous newest suffix across channel_context then thread_context; the exclusion of tombstones and of the agent's own messages applies before history_backfill_limit. AG-21 "from old to new"; the triggering message is never cut and never counted.
D-M2-13-9 2026-10-21 truncated_before_seq refers to the run's thread: set when the window reported older selectable messages or the budget dropped thread elements, then the thread_seq of the oldest kept thread element, or of the triggering message when none is kept. The adapter loads older messages of the thread with thread.read.
D-M2-13-10 2026-10-21 RunContextMessage.channel_id (required) carries the channel of each element. SEC-AI-1 lists the channel among the marks of every element.
D-M2-13-11 2026-10-21 Optional members appear only when they apply (truncated, already_delivered only when true, reply_to_message_id only when set, truncated_before_seq only when set); channel_context is present, possibly empty, exactly when it is built; attachments is always present and stays empty until M3 fills attachments into messages. ADR 0053; the messaging representation of this build has no attachments.
D-M2-13-12 2026-10-21 A triggering message the agent cannot read, or one that is neither in the thread nor its parent, ends the request with the 404 of an unknown run; a run with trigger_kind other than message is internal_error (logged with run id and trigger kind only) until M2-15 and M2-16 define its context. run_context.v1 has no place for another trigger (spec gap); fail closed.
D-M2-13-13 2026-10-21 A context read opens no unit of work and takes no lock; each request recomputes every part, trust included. Trust at request time (ADR 0054 "Confirmation").
D-M2-13-14 2026-10-21 Names that differ from the brief: the messaging representation is messaging.Message (no MessageView); the run is loaded with the existing Repository.Run instead of a new GetRunForContext; the session facts come from the new port agents.RunSessions (the row of runs.agent_session_id among the existing store read ThreadSessions) and the earlier runs from one query EarlierSessionRun; the channel facts from chat.TriggerChannel (gains HistoryBackfillLimit); domain.FitBudget is generic over the element type; the collaborators of the context are separate runs/app.Deps fields that internal/wire takes from the values it already wires. Follow the merged code (D-W-100); no second query or port for the same fact.
D-M2-13-15 2026-10-21 The integration tests live in test/integration/runcontext over a copy of the world of M2-12 (deliveries through runs.Delivery.Prepare; the world has no poll). The owner of the world stands for the brief's owner Robin, and in the guest test the owner mentions Texter, because Alex may not read the agent of Marketing (agent.read), so her mention stays text. Messages of origin app and import and the line thread.reopened are written by a test helper into messages, because this build has no real path for them. D-M2-11-14; 07 4.6.
D-M2-13-16 2026-10-21 The red team (NEIN) found TestConfigSchemaBuilds without the two new keys and the session plan over the thread's current session. The one fix adds the keys to the test, bases the plan on runs.agent_session_id, and lets internal/wire refuse a collaborator of the run context that does not implement its port. Owner rule: one fix after a NEIN, then one delta red team.