harn-stdlib 0.10.130

Embedded Harn standard library source catalog
Documentation
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,
  // Whether the RAW reply carried a non-blank `gap_class` field at all, before
  // `__completion_judge_gap_class` folds absent, blank, unrecognized, and an
  // explicit `other` into the same normalized value. The normalized value
  // cannot tell those apart; this can, and it is what the contradiction check
  // below keys on.
  gap_declared: bool,
  requirement_report?: CompletionRequirementReport?,
}

const __COMPLETION_JUDGE_DETAIL_CHAR_LIMIT: int = 240

/**
 * Gap classes that name a specific unmet obligation.
 *
 * `other` is deliberately absent. It is the value the schema documents for a
 * `done` verdict, and the value an absent, blank, or unrecognized field decodes
 * to, so a cached or older-pin reply carrying no gap class at all arrives here
 * as `other`. Reading `other` as a named gap would refuse every one of those
 * replies, which is the opposite of the safe direction.
 */
pub const COMPLETION_JUDGE_NAMED_GAP_CLASSES = [
  "missing_artifact",
  "unmet_manner_clause",
  "failed_verification",
  "unresolved_authorization",
]

/**
 * __judge_completion_verdict_contradicts_itself.
 *
 * Whether a decoded verdict accepts and refuses in the same object: `done`
 * beside ANY declared gap. The pair is checkable without a model, and a judge
 * that produces it has not decided the run is finished, it has decided the
 * run is blocked.
 *
 * This keys on `gap_declared`, not on membership in the four named gap
 * classes. A judge free to launder an unmet obligation into `gap_class:
 * "other"` — the same value a genuinely gapless `done` is told to leave
 * absent — used exactly that escape: the same blocked-write fact that got
 * `unresolved_authorization` (refused) on one call got `other` (accepted) on
 * the next, no schema violation either time. Keying on the four names cannot
 * close that, because `other` is never one of the four names; keying on
 * whether the field was populated at all can, because a compliant `done`
 * never populates it. See harn#7910.
 *
 * @effects: []
 * @errors: []
 * @api_stability: internal
 * @example: __judge_completion_verdict_contradicts_itself({verdict: "done", detail: "", gap_class: "other", gap_declared: true})
 */
pub fn __judge_completion_verdict_contradicts_itself(decoded: CompletionJudgeVerdict) -> bool {
  return decoded.verdict == "done" && decoded.gap_declared
}

/**
 * __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. A `done` verdict
 * that populates the field at all, `other` included, is refused; see
 * `__judge_completion_verdict_contradicts_itself`.
 *
 * @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. Leave unset on `done`; setting it, including to `other`, is read as an unresolved gap and refused.",
    },
  }
  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
  }
  // Raw presence, read before normalization. `__completion_judge_gap_class`
  // folds a missing field, a blank string, an unrecognized string, and an
  // explicit `"other"` into the same `"other"` value, which is right for
  // display and for the arbitration ladder but wrong for this one question:
  // did the reply say anything here at all?
  const gap_declared = trim(to_string(result?.gap_class ?? "")) != ""
  return {
    verdict: verdict,
    detail: clamped,
    gap_class: __completion_judge_gap_class(result?.gap_class),
    gap_declared: gap_declared,
    requirement_report: completion_requirement_report(
      completion_requirement_contract(raw_requirement_contract),
      result?.requirement_report,
      evidence_packet,
    ),
  }
}