// std/agent/obligations — the one derivation of what a run is currently
// obligated to deliver.
//
// A run's completion target is the task it started with, amended by every
// mid-run user directive the model actually saw. Exit authorities (the
// completion judge, the `verify_completion` closure, the completion gate) must
// all read the SAME amended target, or an accepted steer becomes invisible to
// the authority that decides whether the run may stop: the judge then vetoes a
// stop the user themselves authorized, and orders work the user withdrew.
//
// The typed control rows a session writes as it accepts each control word are
// the authority. A transcript-only reading remains as a fallback for a store
// written before those rows existed, and every result says which reading it is:
// the fallback can see a steer but is structurally blind to a stop, and a stop
// it cannot see must never read as a stop that did not happen.
//
// Derived once, at the judge payload seam, and carried on the evidence
// snapshot. No consumer re-derives it from raw transcript history.
import { agent_session_control_events, agent_session_messages } from "std/agent/state"
/**
* One accepted mid-run user directive, with the delivery mode that proves the
* model saw it before the run reached this decision point.
*/
pub type CompletionSteer = {message_id: string, mode: string, content: string}
/**
* An accepted stop, as the session recorded it at acceptance.
*
* A stop unwinds the loop and delivers no user message, so it cannot be
* reconstructed from transcript history the way a steer can. The control
* record is the only place it is visible.
*/
pub type CompletionAcceptedStop = {control_id: string, method: string, status: string}
/**
* How this obligation set learned what it knows.
*
* `control_record` means it read the typed rows written when each control was
* accepted. `delivered_messages` means it fell back to the mode stamped on
* delivered user messages, which can see steers and CANNOT see a stop.
*
* Carried so a fallback result can never be read as a recorded one. A consumer
* that gives an accepted stop precedence must check this before concluding
* that no stop happened: under the fallback, "no stop" means "not visible from
* here", not "did not occur".
*/
pub type CompletionObligationSource = "control_record" | "delivered_messages"
/**
* The completion target a run is currently held to.
*
* `original_task` is the task the session opened with. `steers` are the
* accepted mid-run user directives, oldest first. Later entries supersede
* conflicting earlier ones — including requirements frozen at loop start.
* `accepted_stop` is set only when a stop was recorded; `source` says whether
* that silence is authoritative.
*/
pub type CompletionObligations = {
schema?: "harn.completion_obligations.v1",
original_task: string,
steers: list<CompletionSteer>,
accepted_stop?: CompletionAcceptedStop,
source?: CompletionObligationSource,
}
// `audit_only` messages drain at `loop_exit`, after the last model call. The
// model never saw them, so they cannot have changed what it was asked to do.
const __OBLIGATION_DELIVERED_MODES = ["finish_step", "interrupt_immediate"]
// A steer rides in an exit authority's prompt, so it is bounded like every other
// evidence field. Clipping keeps the head and tail: a steer's operative clause
// is usually its first or its last sentence.
const __OBLIGATION_STEER_CHAR_LIMIT: int = 1200
// Rendered newest-last. Older steers are summarized as a count rather than
// silently dropped, so a truncated block cannot read as a complete one.
const __OBLIGATION_STEER_RENDER_LIMIT: int = 12
fn __obligation_text(value: unknown) -> string {
// Injected transcript content is a JSON value: a plain string from the
// in-VM push, but possibly a structured content block from an ACP host.
if type_of(value) == "string" {
return trim(value)
}
if value == nil {
return ""
}
return trim(json_stringify(value))
}
fn __obligation_clip(value: string) -> string {
if len(value) <= __OBLIGATION_STEER_CHAR_LIMIT {
return value
}
const tail_chars = __OBLIGATION_STEER_CHAR_LIMIT / 3
const head_chars = __OBLIGATION_STEER_CHAR_LIMIT - tail_chars
return substring(value, 0, head_chars)
+ "\n…["
+ to_string(len(value) - __OBLIGATION_STEER_CHAR_LIMIT)
+ " chars elided — middle of steer]…\n"
+ substring(value, len(value) - tail_chars, len(value))
}
fn __obligation_steer(message: unknown) -> CompletionSteer? {
if (message?.role ?? "") != "user" {
return nil
}
const mode = to_string(message?.injectedMode ?? "")
if !contains(__OBLIGATION_DELIVERED_MODES, mode) {
return nil
}
const content = __obligation_clip(__obligation_text(message?.content))
if content == "" {
return nil
}
return {message_id: to_string(message?.messageId ?? ""), mode: mode, content: content}
}
/**
* completion_obligations_from_messages.
*
* Derive the run's current completion target from a transcript already in hand.
*
* A steer is identified structurally, by the typed `injectedMode` the host
* bridge stamps on a delivered user message — not by transcript position and
* not by matching prose. A session with no accepted steer yields an empty
* `steers` list, and every consumer then behaves exactly as it did before this
* seam existed.
*
* @effects: []
* @errors: []
* @api_stability: experimental
* @example: completion_obligations_from_messages([], "ship the fix")
*/
pub fn completion_obligations_from_messages(
messages: any,
original_task: string,
) -> CompletionObligations {
let steers: list<CompletionSteer> = []
for message in messages ?? [] {
const steer = __obligation_steer(message)
if steer != nil {
steers = steers.appending(steer)
}
}
// Tagged as the fallback reading. This path sees delivered messages only, so
// its silence about a stop is an absence of evidence and not evidence of
// absence; `accepted_stop` is deliberately left unset rather than set false.
return {
schema: "harn.completion_obligations.v1",
original_task: original_task,
steers: steers,
source: "delivered_messages",
}
}
// Only a `stop` row withdraws the run's remaining obligations, and only when
// the surface wrote it at acceptance. A `heuristic` row was reconstructed from
// prose by a consumer, so it may not name a stop that happened.
const __OBLIGATION_RECORDED_PROVENANCE: string = "recorded"
// The two control words the model is expected to have seen before the run
// reached its next exit decision. A `queue` note drains after the last model
// call, so it cannot have changed what was asked.
const __OBLIGATION_STEER_ACTIONS: list<string> = ["steer", "interrupt"]
fn __obligation_steer_from_control(event: unknown) -> CompletionSteer? {
if !contains(__OBLIGATION_STEER_ACTIONS, to_string(event?.action ?? "")) {
return nil
}
const content = __obligation_clip(__obligation_text(event?.text))
if content == "" {
return nil
}
return {
message_id: to_string(event?.message_id ?? ""),
mode: to_string(event?.delivery_mode ?? ""),
content: content,
}
}
/**
* completion_obligations_from_control_events.
*
* Derive the run's current completion target from the typed control rows the
* session wrote as it accepted each control word.
*
* This is the only derivation that can see an accepted stop. A stop unwinds the
* loop without delivering a user message, so the transcript-only derivation is
* structurally blind to it and reports a run as still owing the work the person
* running it just withdrew.
*
* A row whose provenance is not `recorded` was reconstructed from prose by some
* later consumer. Such a row may still contribute a steer, which only ever adds
* obligation, but it never establishes a stop: a guessed stop would silence work
* nobody cancelled.
*
* @effects: []
* @errors: []
* @api_stability: experimental
* @example: completion_obligations_from_control_events([], "ship the fix")
*/
pub fn completion_obligations_from_control_events(
events: any,
original_task: string,
) -> CompletionObligations {
let steers: list<CompletionSteer> = []
let accepted_stop = nil
for event in events ?? [] {
const steer = __obligation_steer_from_control(event)
if steer != nil {
steers = steers.appending(steer)
}
const recorded = to_string(event?.provenance ?? "") == __OBLIGATION_RECORDED_PROVENANCE
if recorded && to_string(event?.action ?? "") == "stop" {
accepted_stop = {
control_id: to_string(event?.control_id ?? ""),
method: to_string(event?.method ?? ""),
status: to_string(event?.status ?? ""),
}
}
}
const base = {
schema: "harn.completion_obligations.v1",
original_task: original_task,
steers: steers,
source: "control_record",
}
if accepted_stop == nil {
return base
}
return base + {accepted_stop: accepted_stop}
}
/**
* agent_completion_obligations.
*
* Read a live session's transcript and derive its current completion target.
* Convenience over `completion_obligations_from_messages` for a caller that
* does not already hold the messages; the judge payload seam holds them and
* uses the pure form so a run reads its transcript once.
*
* @effects: [host]
* @errors: []
* @api_stability: experimental
* @example: agent_completion_obligations(harness.agent, session_id, "ship the fix")
*/
pub fn agent_completion_obligations(
agent: HarnessAgent,
session_id: any,
original_task: string,
) -> CompletionObligations {
const events = try {
agent_session_control_events(agent, session_id)
} catch (e) {
[]
}
if len(events ?? []) > 0 {
return completion_obligations_from_control_events(events, original_task)
}
// No control row at all. That is either a session where nobody used a control
// word, or a store written before the control schema existed — and from here
// those two are the same observation. Fall back to the transcript reading and
// let `source` say so, rather than reporting an unrecorded stop as no stop.
const messages = try {
agent_session_messages(agent, session_id)
} catch (e) {
[]
}
return completion_obligations_from_messages(messages, original_task)
}
// The stop block leads the steering section: a stop ends the run outright, so an
// authority that reads it has no remaining question about what is still owed.
// Empty when no stop was recorded, which keeps an uninterrupted run's prompt
// byte-identical to the pre-control-record prompt.
fn __obligation_stop_prompt(accepted_stop: CompletionAcceptedStop?) -> string {
if accepted_stop == nil {
return ""
}
return "\n\nThe user STOPPED this run before it finished. The stop was accepted by the"
+ " session, so the agent had no opportunity to continue past it. Remaining work is no"
+ " longer owed: do not order more work, and do not count as a gap anything the run was"
+ " cut off from doing. Judge only what the run had already produced when the stop landed."
}
/**
* completion_obligations_prompt.
*
* Render the accepted steering block for an exit authority's prompt, with the
* authority framing that makes it decisive rather than conversational.
*
* Returns `""` when no steer was accepted, so a steer-free run's prompt is
* byte-identical to the pre-obligations prompt. That keeps the judge's stable
* prefix cacheable across an unsteered run and makes "no steer changes
* nothing" structurally true instead of merely tested.
*
* @effects: []
* @errors: []
* @api_stability: experimental
* @example: completion_obligations_prompt({original_task: "x", steers: []})
*/
pub fn completion_obligations_prompt(obligations: CompletionObligations?) -> string {
const steers = obligations?.steers ?? []
const stop_block = __obligation_stop_prompt(obligations?.accepted_stop)
if len(steers) == 0 {
return stop_block
}
const total = len(steers)
const omitted = if total > __OBLIGATION_STEER_RENDER_LIMIT {
total - __OBLIGATION_STEER_RENDER_LIMIT
} else {
0
}
const rendered = if omitted == 0 {
steers
} else {
steers.slice(omitted, total)
}
let lines: list<string> = []
let index = omitted + 1
for steer in rendered {
lines = lines.appending(to_string(index) + ". " + steer.content)
index = index + 1
}
const omission_note = if omitted == 0 {
""
} else {
"(" + to_string(omitted) + " earlier steering messages omitted; the most recent are shown)\n"
}
return stop_block
+ "\n\nAccepted user steering, in order (the user sent these AFTER the completion goal"
+ " above, and the agent received them mid-run):\n"
+ omission_note
+ join(lines, "\n")
+ "\n\nLater user steering supersedes any conflicting earlier requirement, including the"
+ " completion goal, the rubric, and any requirement row listed above. A steer that narrows,"
+ " redirects, or cancels work makes the narrowed outcome the completion target: the withdrawn"
+ " work is no longer owed, and reverting or not doing it is compliance, not a gap. If the"
+ " latest steering asked the agent to report a finding and stop, a report that answers it is"
+ " a complete run. When a steer states its own completion condition, that condition IS the"
+ " completion test — apply it as written. Verification is owed only for work that still"
+ " stands: a steer that withdrew or forbade work also withdrew the obligation to verify it,"
+ " so do not continue for missing checks on work the user cancelled. Checks on work that"
+ " survives the steering are still required. Judge against the goal as amended here, never"
+ " against the original goal alone."
}
/**
* completion_obligations_digest.
*
* A stable digest of the amended completion target, for binding a terminal
* decision to the obligations it was decided under. Two runs that differ only
* in accepted steering, or in whether the user stopped them, must not share an
* evidence identity.
*
* @effects: []
* @errors: []
* @api_stability: internal
* @example: completion_obligations_digest({original_task: "x", steers: []})
*/
pub fn completion_obligations_digest(obligations: CompletionObligations?) -> string {
const steers = obligations?.steers ?? []
const accepted_stop = obligations?.accepted_stop
if len(steers) == 0 && accepted_stop == nil {
return ""
}
if accepted_stop == nil {
return "sha256:" + sha256(json_stringify(steers))
}
return "sha256:" + sha256(json_stringify({steers: steers, accepted_stop: accepted_stop}))
}