import {
CompletionRequirementEvidencePacket,
CompletionRequirementReport,
completion_requirement_assessments_schema,
completion_requirement_contract,
completion_requirement_report,
} from "std/agent/completion_requirements"
import {
COMPLETION_JUDGE_GAP_CLASSES,
CompletionJudgeGapClass,
__completion_judge_gap_class,
} from "std/agent/judge_internals"
/**
* Decoded completion decision. The schema admits `done` and `continue` only;
* an out-of-contract value is preserved verbatim so telemetry can show what
* the judge actually said, and is treated as a non-veto by the caller.
*/
pub type CompletionJudgeVerdict = {
verdict: string,
detail: string,
gap_class: CompletionJudgeGapClass,
requirement_report?: CompletionRequirementReport?,
}
const __COMPLETION_JUDGE_DETAIL_CHAR_LIMIT: int = 240
/**
* __judge_completion_verdict_schema.
*
* One discriminant and one dual-purpose detail keep completion decisions
* inside small-model output budgets. `detail` is the evidence basis for
* `done`, or the single concrete gap and next action for `continue`.
*
* `gap_class` names WHAT a `continue` is refusing on. It is deliberately NOT
* required: the checkpoint validates this schema strictly, and cached, replayed,
* and older-pin judge responses carry no such field. An absent value decodes to
* `other`, which is the reading that grants no authority — so the compatible
* direction and the safe direction are the same direction.
*
* @effects: []
* @errors: []
* @api_stability: experimental
* @example: __judge_completion_verdict_schema()
*/
pub fn __judge_completion_verdict_schema(raw_requirement_contract: unknown = nil) -> dict {
const contract = completion_requirement_contract(raw_requirement_contract)
let properties = {
verdict: {type: "string", enum: ["done", "continue"]},
detail: {
type: "string",
minLength: 1,
description: "Brief evidence basis or gap. Harn keeps the first 240 characters.",
},
gap_class: {
type: "string",
enum: COMPLETION_JUDGE_GAP_CLASSES,
description: "On `continue`, the kind of gap being named. On `done`, use `other`.",
},
}
const assessments = completion_requirement_assessments_schema(contract)
if assessments != nil {
properties = properties + {requirement_report: assessments}
}
return {
type: "object",
properties: properties,
required: ["verdict", "detail"],
additionalProperties: false,
}
}
/**
* __judge_completion_verdict_read.
*
* Decode a judge response into the compact verdict. The superseded shape
* `{action, reason, repair, ...}` still decodes, because cached and replayed
* judge responses outlive the schema that produced them and a decision read
* as absent would silently become an approval.
*
* @effects: []
* @errors: []
* @api_stability: experimental
* @example: __judge_completion_verdict_read({verdict: "done", detail: "tests pass"})
*/
pub fn __judge_completion_verdict_read(
result: dict,
raw_requirement_contract: unknown = nil,
evidence_packet: CompletionRequirementEvidencePacket = {},
) -> CompletionJudgeVerdict {
const raw = trim(to_string(result?.verdict ?? result?.action ?? ""))
const verdict = if raw == "accept" {
"done"
} else {
raw
}
// First non-blank wins rather than first non-nil: the superseded shape
// carried an empty `repair` on approval, which would otherwise shadow the
// `reason` that holds the audit basis.
let detail = ""
for candidate in [result?.detail, result?.repair, result?.reason] {
if detail == "" {
detail = trim(to_string(candidate ?? ""))
}
}
const clamped = if len(detail) > __COMPLETION_JUDGE_DETAIL_CHAR_LIMIT {
substring(detail, 0, __COMPLETION_JUDGE_DETAIL_CHAR_LIMIT)
} else {
detail
}
return {
verdict: verdict,
detail: clamped,
gap_class: __completion_judge_gap_class(result?.gap_class),
requirement_report: completion_requirement_report(
completion_requirement_contract(raw_requirement_contract),
result?.requirement_report,
evidence_packet,
),
}
}