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
10 changes: 10 additions & 0 deletions docs/architecture/rfcs/goal-outcome-refinement-v0.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,16 @@ these invalidates its basis. Evidence references are Agent assertions: v0 does
not resolve or fingerprint the cited artifacts, so editing an artifact requires
another review. Do not call a retained reference proof of freshness or quality.

Declaration provenance and progress evidence have separate lifetimes. Creation
and new requirements need `source`; existing-outcome reviews and work-link
maintenance may omit it, preserving all retained origins, including at the
64-source limit. New observations belong in `review[].evidence_refs`, its note,
owning material and operation receipt. Native `refine_outcome` similarly omits
`source_summary` for these updates while retaining its host-bound request/retry
envelope. Explicit sources remain additive and immutable; overflow fails with
guidance rather than dropping provenance or raising the limit. A new declaration
cannot use the review path to evade provenance, ownership or check authority.

The existing admitted-work context carries the complete outcome declaration;
when inline content is present, no duplicate acceptance inspection is required.
Changes can accompany ordinary `refresh-state --goal-outcome-update-json`, or one
Expand Down
7 changes: 7 additions & 0 deletions docs/architecture/rfcs/goal-outcome-refinement-v0.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ active 含义;显式非活动状态仍拒绝细化。
陈述,v0 不解析或计算所引产物的指纹,因此产物修改后必须重新核对。保留引用
不能证明时效或质量。

要求来源与进展证据的生命周期分开:创建成果或新增要求仍需 `source`;已有成果
的自查、工作关联维护可省略它,保留全部旧来源,在 64 项来源上限时也可继续。
新观察写入 `review[].evidence_refs`、理由、所属材料和操作回执。原生
`refine_outcome` 对这些更新同样省略 `source_summary`,仍保留宿主绑定的请求与
重试信封。显式来源保持追加和不可改写;超限返回修复指导,不丢来源、不提高
上限。新增声明不能借自查路径绕过来源、归属或验收权限。

既有准入工作上下文携带完整成果声明;内联内容完整时,无需额外查询验收。
变化可合并到普通 `refresh-state --goal-outcome-update-json`,或一次原生
`refine_outcome` 调用。无变化不额外调用、不增加往返,也不重复登记自查。
Expand Down
10 changes: 6 additions & 4 deletions loopx/chat_loopx_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"The host supplies the Goal and preparing Agent. It saves only a reviewable goal.acceptance.check proposal; it does not configure acceptance or run commands. "
"The local owner can use that plan beside the delivery in the workspace. "
"Action=outcomes reads persistent supporting outcomes and the provider revision. "
"Action=refine_outcome takes operation_id, expected_provider_revision and document with outcome_id and source_summary; add only changed requirements [{id,description}], todo_ids or review. Creation also needs the original objective. "
"Action=refine_outcome takes operation_id, expected_provider_revision and document with outcome_id; add only changed requirements [{id,description}], todo_ids or review. Creation also needs the original objective. source_summary is required for creation/new requirements; omit it for existing-outcome reviews/work links and put milestone evidence in review.evidence_refs to retain declaration origins. "
"Action=prepare_goal_objective takes operation_id and document {objective,reason}; it prepares an owner-reviewed shared objective revision without changing root commitments. Action=adopt_goal_objective takes operation_id, expected_provider_revision and document {revision,digest,work_digest,review_summary} after reconciling your work; action=outcomes returns its basis. "
"Optional review addresses every retained requirement with {id,conclusion: met|unmet|uncertain,evidence_refs: strings,note}. "
"The host fixes the owner and retains the first source Turn for an unchanged operation in this conversation. After response loss, retry the same operation, revision and document. "
Expand All @@ -69,7 +69,7 @@
"expected_provider_revision": {"type": "string"},
"document": {
"type": "object",
"description": "For refine_outcome: outcome_id and source_summary, plus changed requirements [{id,description}], todo_ids (existing work) or review; original objective required on creation; no actor/source routing. For prepare_check, prefer {outcome_id, criteria: [{id: existing requirement ID, validation_argv: string array, optional validation_timeout_seconds}]}; the owner resolves retained descriptions and linked work. Legacy standalone check document: objective (string), non_goals (strings), scope ({kind: selected_work, todo_ids: existing advancement Todo ids} or {kind: all_advancement}), criteria (id, description, validation_argv string array, optional validation_timeout_seconds), bindings (todo_id, criterion_ids). Checks use the registered Goal workspace or its pinned oracle snapshot only after local-owner apply. Use known requirements and approved scope; do not invent an oracle or authorization.",
"description": "For refine_outcome: outcome_id, plus changed requirements [{id,description}], todo_ids (existing work) or review; original objective required on creation. source_summary is required only for creation/new requirements; omit for review/work maintenance, with new evidence in review.evidence_refs. No actor/source routing. For prepare_check, prefer {outcome_id, criteria: [{id: existing requirement ID, validation_argv: string array, optional validation_timeout_seconds}]}; the owner resolves retained descriptions and linked work. Legacy standalone check document: objective (string), non_goals (strings), scope ({kind: selected_work, todo_ids: existing advancement Todo ids} or {kind: all_advancement}), criteria (id, description, validation_argv string array, optional validation_timeout_seconds), bindings (todo_id, criterion_ids). Checks use the registered Goal workspace or its pinned oracle snapshot only after local-owner apply. Use known requirements and approved scope; do not invent an oracle or authorization.",
},
"limit": {"type": "integer", "minimum": 1, "maximum": 50},
"cursor": {"type": "string"},
Expand Down Expand Up @@ -935,7 +935,7 @@ def dispatch(name, arguments):
if set(arguments) != {"action", "operation_id", "expected_provider_revision", "document"}:
raise ValueError("refine_outcome needs its stable operation, inspected revision and document")
document = arguments["document"]
if not isinstance(document, dict) or not {"outcome_id", "source_summary"} <= set(document) or set(document) - {"outcome_id", "objective", "requirements", "todo_ids", "source_summary", "review"}:
if not isinstance(document, dict) or "outcome_id" not in document or set(document) - {"outcome_id", "objective", "requirements", "todo_ids", "source_summary", "review"}:
raise ValueError("refine_outcome document cannot replace host identity or source")
if not isinstance(operation_id, str) or not operation_id.strip():
raise ValueError("refine_outcome requires a stable operation id")
Expand All @@ -953,7 +953,9 @@ def dispatch(name, arguments):
refinement = {key: document[key] for key in ("outcome_id", "objective", "requirements", "todo_ids") if key in document}
if "review" in document:
refinement["review"] = document["review"]
refinement.update(owner_agent_id=settings["agent_id"], source={"ref": envelope["source_ref"], "summary": document["source_summary"]})
refinement["owner_agent_id"] = settings["agent_id"]
if "source_summary" in document:
refinement["source"] = {"ref": envelope["source_ref"], "summary": document["source_summary"]}
result = public_goal_acceptance(refine_goal_outcome(**route, refinement=refinement,
expected_provider_revision=arguments["expected_provider_revision"], operation_id=operation_id, execute=True))
elif action == "prepare_check":
Expand Down
20 changes: 15 additions & 5 deletions loopx/control_plane/goals/outcome_requirements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export function refineGoalOutcome(head: JsonObject, goalId: string, goalRef: Wir
}
}
const patch = canonicalAuthorityObject(value, "outcome refinement");
keys(patch, ["outcome_id", "source"], ["owner_agent_id", "objective", "requirements", "todo_ids", "review"]);
keys(patch, ["outcome_id"], ["source", "owner_agent_id", "objective", "requirements", "todo_ids", "review"]);
const outcomeId = id(patch.outcome_id, "outcome id");
const old = previous?.outcomes.find(o => o.id === outcomeId);
const owner = id(patch.owner_agent_id === undefined ? old?.owner_agent_id : patch.owner_agent_id, "outcome Agent");
Expand All @@ -146,13 +146,23 @@ export function refineGoalOutcome(head: JsonObject, goalId: string, goalRef: Wir
requireValue(actor === null || !todo.claimed_by || todo.claimed_by === actor, "an Agent cannot attach another Agent's claimed work");
}
const reqs = new Map((old?.requirements ?? []).map(row => [row.id, row]));
for (const row of requirements(patch.requirements === undefined ? [] : patch.requirements)) {
const additions = requirements(patch.requirements === undefined ? [] : patch.requirements);
const declaresRequirements = !old || additions.some(row => !reqs.has(row.id));
for (const row of additions) {
requireValue(!reqs.has(row.id) || reqs.get(row.id)!.description === row.description, "an existing requirement cannot be overwritten; reconcile conflicting intent explicitly");
reqs.set(row.id, row);
}
const origin = source(patch.source), sources = new Map((old?.sources ?? []).map(row => [row.ref, row]));
requireValue(!sources.has(origin.ref) || sources.get(origin.ref)!.summary === origin.summary, "source reference already identifies another refinement");
sources.set(origin.ref, origin);
const sources = new Map((old?.sources ?? []).map(row => [row.ref, row]));
// Declaration origins survive progress reviews. Operation receipts and the
// review's evidence references retain the new observation, not another origin.
const origin = Object.hasOwn(patch, "source") ? source(patch.source) : null;
requireValue(origin !== null || !declaresRequirements, "new outcomes or requirements require source provenance; review evidence belongs in review.evidence_refs");
if (origin !== null) {
requireValue(!sources.has(origin.ref) || sources.get(origin.ref)!.summary === origin.summary, "source reference already identifies another refinement");
requireValue(sources.has(origin.ref) || sources.size < 64,
"outcome source capacity reached; review/work updates may omit source and retain evidence in review.evidence_refs; new declarations still require provenance");
sources.set(origin.ref, origin);
}
const outcome: Outcome = {id: outcomeId, owner_agent_id: owner, objective, revision: (old?.revision ?? 0) + 1,
requirements: [...reqs.values()], todo_ids: [...new Set([...(old?.todo_ids ?? []), ...links])], sources: [...sources.values()],
...(old?.review ? {review: old.review} : {})};
Expand Down
35 changes: 25 additions & 10 deletions skills/loopx-project/references/outcome-refinement.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ original Goal too. Only if this basis is absent or stale, use the bound route:
loopx --format json goal-acceptance inspect --goal-id <goal>
```

Reuse the matching outcome ID. Creation needs its original objective and owner;
updates need only the ID, source and changed fields. Add stable IDs for
Reuse the matching outcome ID. Creation needs its original objective, owner and
request source; adding requirements also needs that provenance. Existing-outcome
reviews and work-link maintenance need only the ID and changed fields: omit
`source`, retaining all declared origins. Add stable IDs for
new requirements and link real existing advancement Todos; normal Todo admission
creates missing work. Omitted earlier requirements/work links remain. Changing
an existing requirement description fails: conflicting intent needs explicit
Expand All @@ -36,6 +38,13 @@ or owner approval. It may settle planning for unconfigured requirements; it
cannot bypass configured checks. Do not infer success from a closed Todo.
Changes to requirements/work declarations invalidate the review basis; artifact
edits require another review because references are not fingerprinted here.
Record each milestone in `review[].evidence_refs` and `note`, with detailed
evidence in its owning material and the operation receipt. Do not create a fresh
requirement source for each self-review, heartbeat, artifact revision or retry.
An explicit source remains additive: it is never silently discarded or pruned.
Retained sources have a bounded capacity; increasing that limit, deleting old
origins, or creating another outcome merely to escape it does not repair the
authoring error. A genuinely new declaration still needs its actual provenance.

For changed requirements or reviews, add this envelope to the **existing**
`refresh-state` writeback using `--goal-outcome-update-json update.json`. Retain
Expand All @@ -52,27 +61,33 @@ replace them. Reuse the revision from inline context when still current:
"objective": "Deliver a clear product tour",
"requirements": [{"id": "tour-opening", "description": "Retain the approved introduction"}],
"todo_ids": ["todo_tour"],
"source": {"ref": "evidence:tour-request", "summary": "Owner requested a tour with its introduction"}
"source": {"ref": "message:tour-request", "summary": "Owner requested a tour with its introduction"}
}
}
```

Use actual declarations, not the example claims. At a later milestone, the
refinement needs only `outcome_id`, `source` and `review`; all existing
requirements still need review:
Use actual declarations, not the example claims. At a later milestone, omit
`source`; all existing requirements still need review:

```json
"review": [{"id": "tour-opening", "conclusion": "met", "evidence_refs": ["tour.txt#introduction"], "note": "Read the output and confirmed the introduction remains"}]
{
"outcome_id": "product-tour",
"review": [{"id": "tour-opening", "conclusion": "met", "evidence_refs": ["tour.txt#introduction"], "note": "Read the output and confirmed the introduction remains"}]
}
```

When retention is needed before substantial work, use one standalone
`goal-acceptance refine --goal-id <goal> --agent-id <agent> --document refinement.json
--expected-provider-revision <revision> --operation-id <id> --execute` with the
inner refinement document. Native enabled conversations expose `outcomes` and
`refine_outcome` through `loopx_collaboration`; the host fixes Goal/Agent/Turn
identity. Its document uses `source_summary` instead of caller owner/source and
accepts the same optional review. Older threads may retain an older tool schema;
use CLI without replacing a live thread.
identity. Its document uses `source_summary` for creation/new requirements
instead of caller owner/source. Omit `source_summary` for reviews/work links;
it accepts the same review evidence without adding a declaration origin. Older
builds that still require a source can reuse an inspected existing source's
exact ref and unchanged summary through CLI for unchanged requirements; do not
invent a new source or relabel new user intent. Older threads may retain an
older tool schema; use CLI without replacing a live thread.

## Continue and recover

Expand Down
1 change: 1 addition & 0 deletions skills/loopx-self-repair/references/repair-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ teaches a reusable control-plane lesson.

| Pattern | Symptoms | Evidence To Read | Likely Root | Durable Repair |
| --- | --- | --- | --- | --- |
| `outcome_review_source_capacity` | Repeated milestone reviews fail with `goal_acceptance_invalid_request` and `outcome sources exceeds its supported capacity` or `outcome source capacity reached`. | The exact failed operation/receipt, inspected original outcome sources and requirements, and its review evidence; verify whether refinement committed before a later writeback failure. | Requirement provenance is used as an append-only progress log; older native/CLI contracts required a source even for a review. | Keep the original outcome and all origins. Existing-outcome reviews/work links omit source (native: source_summary); put observations in review evidence/notes and owning materials. Creation/new requirements still need real provenance. On an older build, use an inspected existing source with exactly the same ref/summary for unchanged requirements only. Never prune origins, inflate limits, invent a new outcome to escape capacity, or silently relabel a new request. Preserve failed receipts and exact-operation recovery; qualify repeated reviews at the source limit and ownership/CAS/replay negative cases through real backends. |
| `premerge_binary_visual_coverage` | A first-screen PNG makes premerge fail with invalid UTF-8, although its text checks are clean. | Exact changed paths, text scan coverage, raster evidence and the existing exact-head review boundary. | The premerge adapter feeds binary images into a text-only scan and loses the distinction between text readability and visual privacy. | Keep the text scanner unchanged; explicitly list changed images as outside text coverage and retain the existing manual-review hold, including image-only changes. Unknown binary/text decode failures remain failures. Inspect pixels, metadata and provenance in the ordinary exact-head review; never silently skip images, certify them with a text pass, add a bypass flag or demand another user presentation approval. |
| `planning_visibility_requires_declared_complexity` | A flat runnable backlog hides the Goal or broader work view because no dependency, blocked work or acceptance gap has been registered. | Same-source default/opt-out planning packets, original Goal, bounded work summary, omission counts and full-read routes. | A supplemental-context condition is mistaken for evidence that no strategic planning is needed; byte reduction removes useful visibility. | Show Goal and bounded work context by default at applicable preselection boundaries, including flat backlogs. Preserve omission counts, complete-read routes and action authority. Reduce exact duplication instead of hiding work; qualify input-cost changes with matched fixtures and keep model benefit unproven until measured. |
| `stale_objective_repeated_as_current` | Current planning repeatedly projects an obsolete objective despite newer direct user direction. | Recorded source versus owner-applied objective revision, current canonical basis and each peer's adoption. | Fresh file bytes are mistaken for current intent; a registry/display edit cannot establish peer adoption. | Prepare an evidence-linked operating-objective revision through the existing Goal update surface. Preserve original commitments and use owner apply. Reconcile each peer's work and record its own exact adoption before new execution; do not revise for ordinary progress/diagnostics/age, impersonate peers, or interrupt in-flight settlement. Reuse a pending proposal; adoption is once per objective revision, not per Turn or peer/work write. Verify native tool invocation, current projection and stale-execution refusal, not only serializer output. |
Expand Down
Loading
Loading