Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/reference/protocols/goal-vision-replan-contract-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,11 @@ exact `replan-decision-*` id and separately records:
- `goal_gain`: improved, flat, regressed or unknown;
- delivered evidence references and the bounded lesson for the next experiment.

The authoring contract exposes `review_reference_limit` (3). It applies separately
to `previous_review.evidence_refs` and `explore_review.considered_refs`.

编写契约的 `review_reference_limit`(3)分别限制上述两个引用列表。

A claim needs evidence references; unavailable evidence remains unknown. These
are explicit Agent assessments, not host certification of scientific truth.
The next review retains the assessment with the original decision and subsequent
Expand Down
1 change: 1 addition & 0 deletions loopx/control_plane/stride_decision_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"probe_field_limits": {"scope": 120, "prediction": 120, "adoption_criterion": 120, "cost_bound": 100, "minimum_evidence": 120},
"axis_reason_limit": 96,
"review_text_limit": 120,
"review_reference_limit": 3,
"adoption_options": ["executed", "partially_executed", "not_executed", "unknown"],
"information_options": ["new_evidence", "repeated_evidence", "unknown"],
"gain_options": ["improved", "flat", "regressed", "unknown"],
Expand Down
6 changes: 3 additions & 3 deletions loopx/control_plane/work_items/replan_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {requireJsonObject, requireNonEmptyString} from "../runtime_decode.ts";
import {FRESH_PATH_DISPOSITIONS, requiredSemanticOutcomes} from "./replan_semantics.ts";
import {readReplanSnapshot} from "./replan_history_snapshot.ts";
import {normalizeGoalPathDelta} from "../goals/vision_checkpoint.ts";
import {normalizeRecordedStrideDecision, normalizeStrideStrategy, projectStrideExploreBasis} from "./stride_policy.ts";
import {normalizeRecordedStrideDecision, normalizeStrideStrategy, projectStrideExploreBasis, STRIDE_REVIEW_REFERENCE_LIMIT} from "./stride_policy.ts";
import {PROGRESS_RESULT_CLASSES} from "./replan_history.ts";
import {MATERIAL_DELIVERY_OUTCOMES} from "./delivery_outcome.ts";

Expand Down Expand Up @@ -294,8 +294,8 @@ function reviewEvidence(rows: JsonObject[], request: JsonObject): JsonObject {
throw new EffectRuntimeRequestError("previous decision changed; refresh replan context before reviewing its outcome");
}
const refs = request.evidence_refs;
if (!Array.isArray(refs) || refs.length > 3 || new Set(refs).size !== refs.length) {
throw new EffectRuntimeRequestError("previous review accepts at most three distinct evidence references");
if (!Array.isArray(refs) || refs.length > STRIDE_REVIEW_REFERENCE_LIMIT || new Set(refs).size !== refs.length) {
throw new EffectRuntimeRequestError(`previous review accepts at most ${STRIDE_REVIEW_REFERENCE_LIMIT} distinct evidence references`);
}
for (const ref of refs) identifier(ref, "review evidence reference");
const source = objectOrNull(previous!._source_facts)!;
Expand Down
8 changes: 5 additions & 3 deletions loopx/control_plane/work_items/stride_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const STRIDE_AXIS_NAMES = decisionSchema.axis_names;
export const STRIDE_PLAN_LIMIT = decisionSchema.axis_plan_limit;
export const STRIDE_REASON_LIMIT = decisionSchema.axis_reason_limit;
export const STRIDE_REVIEW_LIMIT = decisionSchema.review_text_limit;
export const STRIDE_REVIEW_REFERENCE_LIMIT = decisionSchema.review_reference_limit;
// Persisted v1 records retain their original meaning; never offered for new reviews.
export const RECORDED_STRIDE_SCHEMA = "stride_decision_v1";
const recordedAdjustments = ["grow", "hold", "shrink"] as const;
Expand All @@ -52,9 +53,9 @@ function exactFields(value: JsonObject, fields: string[], label: string): void {
if (Object.keys(value).some(key => !fields.includes(key))) throw new EffectRuntimeRequestError(`${label} contains unsupported fields`);
}
function refs(value: unknown, label: string): string[] {
if (!Array.isArray(value) || value.length > 3 || value.some(ref => typeof ref !== "string" ||
if (!Array.isArray(value) || value.length > STRIDE_REVIEW_REFERENCE_LIMIT || value.some(ref => typeof ref !== "string" ||
!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(ref)) || new Set(value).size !== value.length) {
throw new EffectRuntimeRequestError(`${label} requires at most three distinct public-safe evidence references`);
throw new EffectRuntimeRequestError(`${label} requires at most ${STRIDE_REVIEW_REFERENCE_LIMIT} distinct public-safe evidence references`);
}
return value as string[];
}
Expand Down Expand Up @@ -389,6 +390,7 @@ export function strideControlContract(context: JsonObject, obligationId: unknown
axis_reason_limit: decisionSchema.axis_reason_limit, probe_field_limits: STRIDE_PROBE_LIMITS,
decision_value_review: {...decisionValueReview},
review_text_limit: decisionSchema.review_text_limit,
review_reference_limit: STRIDE_REVIEW_REFERENCE_LIMIT,
previous_decision_ref: previous,
...(follow ? {decision_followthrough: follow} : {}),
previous_review_options: {adoption: decisionSchema.adoption_options, information_gain: decisionSchema.information_options, goal_gain: decisionSchema.gain_options},
Expand All @@ -406,6 +408,6 @@ export function strideControlContract(context: JsonObject, obligationId: unknown
required_on_periodic_review: true,
rule: "Enabled periodic and observed-stall reviews require a current evidence-linked Vision path and stride decision before any settlement, including progress/successor/blocker/terminal exits. " +
"Each axis needs plan/reason: grow useful completed scope on a supported route; switch names reference method and changed mechanism; verify resolves a grow-or-switch question. Apply these plans to the actual Todo scope and acceptance using the existing Todo authoring/update commands, then record the verified IDs in todo_delta. Retain unfinished useful work; do not create successor microtasks merely to count progress. On grow, consolidate fragmented setup, implementation, integration and decisive validation into a coherent accepted deliverable or complete interpretable experiment, including engineering/maintenance. The next admitted work must execute that scope, method and validation plan; changing review frequency or repeating the proposal is not adoption. Keep the configured review interval and preserve dependencies, acceptance, risk, authority and per-Turn settlement boundaries. " +
"Review the exact previous decision's adoption/information/goal gain and delivered Explore sources in their review fields. Missing/omitted/unread/unprojected evidence stays unknown, not exhausted. Guidance adds no fields/gates; the example is syntax, not an action recommendation. Claims certify no authority, execution or utility. Other legal outcomes cannot bypass a due review.",
"Review the exact previous decision's adoption/information/goal gain and delivered Explore sources in their review fields. Apply review_reference_limit separately to previous_review.evidence_refs and explore_review.considered_refs. Missing/omitted/unread/unprojected evidence stays unknown, not exhausted. Guidance adds no fields/gates; the example is syntax, not an action recommendation. Claims certify no authority, execution or utility. Other legal outcomes cannot bypass a due review.",
};
}
1 change: 1 addition & 0 deletions tests/control_plane/test_replan_progress_native_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ def spend(turn: str, *, todo: str | None = TODO, obligation: str | None = None)
assert fixture["index"].read_bytes() == original_index

control = admitted["replan_action_packet"]["stride_control"]
assert control["review_reference_limit"] == 3
decision = {**control["minimal_example"], "basis": "unexplained_gap", "action": "verify",
"axes": {
"work_slice": {"plan": "Run and compare three complete assignment methods.",
Expand Down
19 changes: 19 additions & 0 deletions tests/control_plane_ts/stride_policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ test("Explore review keeps bare lowercase digest revisions and unavailable null
}
});

test("each authored review list advertises and enforces its own three-reference bound", () => {
const control = strideControlContract({stride_strategy: "evidence_conditioned_v1"})!;
assert.equal(control.review_reference_limit, 3);
const evidence = ["evidence:first", "evidence:second", "evidence:third"];
const review = {reference_decision_ref: "replan-decision-" + "b".repeat(24), adoption: "unknown",
information_gain: "unknown", goal_gain: "unknown", lesson: "Interpret three observations together.",
evidence_refs: evidence};
const explore = {revision: "a".repeat(64), disposition: "used", considered_refs: evidence, reason: "Compared three findings."};
const decision = {...proposal, previous_review: review, explore_review: explore};
assert.deepEqual(normalizeStrideDecision(decision)[0]!.previous_review, review);
for (const extra of ["evidence:fourth", "evidence:first"]) {
const refs = extra === "evidence:first" ? [extra, extra] : [...evidence, extra];
assert.throws(() => normalizeStrideDecision({...decision, previous_review: {...review, evidence_refs: refs}}),
/previous_review\.evidence_refs requires at most 3 distinct/);
assert.throws(() => normalizeStrideDecision({...decision, explore_review: {...explore, considered_refs: refs}}),
/explore_review\.considered_refs requires at most 3 distinct/);
}
});

test("concrete independent plans retain action choice and fit the shared vision budget", () => {
for (const basis of ["unexplained_gap", "uncertain_evidence", "supported_progress"]) {
const decision = normalizeStrideDecision({...proposal, basis})[0]!;
Expand Down
Loading