Skip to content

Commit 6902346

Browse files
committed
Merge current main GoalRef fixes into SQLite snapshot PR
Signed-off-by: Lihua <1017343802@qq.com>
2 parents 6323e48 + 6498262 commit 6902346

69 files changed

Lines changed: 2991 additions & 236 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/architecture/rfcs/goal-instance-identity-and-orphan-recovery-v0.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,25 @@ promotion retain their own acceptance. No new paid cohort or soak is authorized.
798798
owners are not qualified. `execution_authority: false` and the M3 activation
799799
hold remain unchanged.
800800

801+
### 2026-09-29: M3 handoff inbox/outbox candidate
802+
803+
- **Baseline:** `738115bde87eef3fd153abe456d53da5e2b249f8`.
804+
- **Proposed:** Bind each new shadow-management lineage to the exact source
805+
GoalRef. Existing outbox entries, commit markers, and cursors remain
806+
byte-compatible; their entry identity already includes the immutable lineage.
807+
Exact bootstrap, management, and outbox-manifest records use new schema
808+
versions. An exact caller cannot infer ownership from a legacy binding.
809+
- **Evidence:** A real source-session A-to-B recreation leaves Goal A's pending
810+
files and candidate head unchanged when B drains. B cannot capture against
811+
A's active lineage. A capture started by A is revalidated under the Goal
812+
lifetime guard and rejected before its primary write if B has replaced A.
813+
Explicit rollback archives A with its GoalRef, and a fresh B bootstrap
814+
accepts and replays only B work. A legacy drain request cannot enter an exact
815+
lineage.
816+
- **Remaining hold:** This qualifies only the `handoff_inbox_outbox` inventory
817+
row. Todo/lease mutation admission, quota, automation, Goal Channel, and the
818+
overall M3 activation hold remain separate.
819+
801820
## Appendix B: Decision log
802821

803822
| Date | Decision | Owner / approval | Alternatives | Normative sections changed |

‎docs/architecture/rfcs/goal-instance-identity-and-orphan-recovery-v0.zh-CN.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,23 @@ service adoption、D1–D3 provider promotion 保留各自验收。不授权付
723723
downstream drain、不支持的旧/常驻二进制和其余 inventory owner 尚未
724724
qualified;`execution_authority: false` 与 M3 activation hold 保持不变。
725725

726+
### 2026-09-29:M3 handoff inbox/outbox 候选
727+
728+
- **基线:** `738115bde87eef3fd153abe456d53da5e2b249f8`。
729+
- **候选实现:** 将每个新 shadow management lineage 绑定到 source registry
730+
的精确 GoalRef。既有 outbox entry、commit marker 和 cursor 字节保持兼容;
731+
entry identity 已包含不可变 lineage。Exact bootstrap、management 和
732+
outbox manifest 使用新 schema。Exact caller 不能从 legacy binding 推断身份。
733+
- **证据:** 真实 source-session A-to-B recreation 后,B drain 不会修改 Goal A
734+
的 pending 文件或 candidate head,B 也不能向 A 的 active lineage 写 capture。
735+
如果 A 已开始 capture 而 B 在 primary write 前替换 A,writer 会在 Goal
736+
lifetime guard 内重新校验,并在写入前拒绝该 capture。显式 rollback 会连同
737+
GoalRef 归档 A;重新 bootstrap 后,B 只提交并 replay 自己的工作。Legacy
738+
drain request 不能进入 exact lineage。
739+
- **剩余 hold:** 本切片只资格化 `handoff_inbox_outbox` inventory 行。
740+
Todo/lease mutation admission、quota、automation、Goal Channel 与 M3 总
741+
activation hold 仍分别验收。
742+
726743
## 附录 B:决策日志
727744

728745
| 日期 | 决策 | Owner/批准 | 替代方案 | 变更的规范章节 |

‎docs/architecture/rfcs/goal-scoped-capability-portfolio-v0.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,26 @@ settings editor already owns these configurations and their readback. Live
526526
memory/usage/correction controls and Lark evidence returns remain delivery work,
527527
not acceptance supplied by CLI tests.
528528

529+
The explicit Agent preference slice now implements a narrow part of the
530+
correction journey: the existing `semantic-preference` capability owns a
531+
TS lifecycle backed by the shared transactional storage implementation in an
532+
isolated private context namespace. Current explicit preferences have stable
533+
subjects, source references, revisions and retirement/expiry; CLI quota and
534+
native Turn entry points disclose an exact current read. This is not a universal
535+
memory database, an authorization grant or proof of learned-experience utility.
536+
See [operation and boundaries](../../../loopx/capabilities/semantic_preference/README.md#explicit-agent-preferences).
537+
Remaining acceptance includes authenticated external-message ingestion,
538+
Dashboard/Lark inspection, cross-host migration, memory-service provider
539+
qualification (including OpenViking, beyond interchangeable storage drivers),
540+
and measured decision utility
541+
for episodic recall. Reuse the existing semantic-preference extension lifecycle:
542+
project-scoped recall is already available, while explicit Goal/Agent correction,
543+
retirement and provider cutover need their own real-service readback. A top-k
544+
recall response does not qualify as a complete current preference view; service
545+
outages or delayed indexing must not resurrect revoked advice. The
546+
[memory-service acceptance boundary](../../../loopx/capabilities/semantic_preference/README.md#memory-service-providers-and-the-next-integration-boundary)
547+
defines the next independent slice. Do not count this slice as completion of all M0–M5.
548+
529549
Next, qualify one **correction → fresh-session decision** journey before adding
530550
a composition planner: persist an authorized correction, show the affected
531551
source and superseded assertion, resume a different session, retrieve the

‎docs/architecture/rfcs/semantic-vocabulary-convergence-v0.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,14 @@ not amend normative sections.
5656
wire values or move value authority to the registry. M2 now generates the
5757
Turn vocabularies, route projection and ordered controller rules from
5858
`turn_loop_controller_contract_v0.json` via `generate_turn_contract.py`;
59-
this does not migrate every cross-runtime vocabulary.
59+
this does not migrate every cross-runtime vocabulary. The semantic binding
60+
generator also derives the existing Python digest-pattern module from its TS
61+
owner. This narrow literal grammar rejects flags, dynamic expressions and
62+
unsupported regex syntax. The twin ratchet excludes a source-derived binding
63+
only after recomputing and matching its entire artifact; a filename/header
64+
alone never qualifies. Digest callers keep their imports and matching behavior,
65+
and no runtime bridge is added. This restores 43 independently maintained
66+
pairs without raising the 43-pair ceiling.
6067
3. **Default and opt-in boundary.** The check is always on for the repository.
6168
It has no runtime flag because it never runs inside the product.
6269
4. **Principal constraint.** Fail closed, deterministic, and not weakenable by

‎docs/architecture/rfcs/semantic-vocabulary-convergence-v0.zh-CN.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,11 @@ TypeScript effective-action/frontier 绑定与[术语表](../../reference/glossa
780780
检查生成物新鲜度,不新增 required CI job。运行 TypeScript 生产者扫描之前,
781781
先用 `npm ci --ignore-scripts` 安装锁定的 Node 依赖。
782782

783+
同一语义绑定生成器还从 TS owner 生成现有 Python 摘要格式模块:仅接受两条无 flags
784+
的受限字面量正则,动态表达式与不支持的语法明确拒绝。孪生预算只在重新生成并逐字
785+
核对产物后,排除独立维护计数;文件名或 generated 注释不能豁免。调用方导入、匹配
786+
行为保持不变,也不增加运行时桥接。独立维护对数因此恢复为 43,上限仍为 43。
787+
783788
Turn 契约使用独立的生成器和来源。只读验证入口:
784789

785790
```bash

‎examples/semantic-vocabulary-drift-smoke.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,8 +1058,11 @@ def check_dual_runtime_twins(registry: dict[str, Any]) -> str:
10581058
paths = {file.path for file in load_sources(REPO_ROOT, entry["root"])}
10591059
twins = sorted(path for path in paths if path.endswith(".py") and not path.endswith("/__init__.py") and path[:-3] + ".ts" in paths)
10601060
from scripts.generate_turn_contract import verified_generated_paths
1061-
generated = verified_generated_paths()
1062-
generated_twins = [path for path in twins if path in generated and path[:-3] + '.ts' in generated]
1061+
from scripts.generate_semantic_bindings import verified_generated_paths as semantic_generated_paths
1062+
generated = verified_generated_paths() | semantic_generated_paths()
1063+
# A verified source-derived binding has no independently maintained rule;
1064+
# its owner may be authored TS/Python or a shared generated contract.
1065+
generated_twins = [path for path in twins if path in generated or path[:-3] + '.ts' in generated]
10631066
maintained = len(twins) - len(generated_twins)
10641067
require(maintained <= entry['module_budget'], f"{maintained} independently maintained py/ts twins; budget is {entry['module_budget']}")
10651068
return f"twins_raw={len(twins)} generated_verified={len(generated_twins)} independently_maintained={maintained}/{entry['module_budget']}"

‎examples/shared-goal-authority-e2e/mutants.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def command(self) -> list[str]:
133133
'tests/control_plane_ts/coordination_runtime_shadow.test.ts', 'observation transaction mixed'),
134134
Case('management_request_digest', ((COORDINATION + "shadow_management.ts", replacement('if (state.operation.request_digest !== digest) throw new ShadowManagementError("management_operation_identity_mismatch");', 'if (false) throw new ShadowManagementError("management_operation_identity_mismatch");')),),
135135
"tests/control_plane_ts/shadow_management.test.ts", 'management request digest'),
136-
Case('management_manifest_hash', ((COORDINATION + "shadow_management.ts", replacement('managementDigest(manifest) !== state.operation.manifest_digest\n || manifest.schema_version !== SHADOW_MANAGEMENT_MANIFEST_SCHEMA\n', 'false\n || manifest.schema_version !== SHADOW_MANAGEMENT_MANIFEST_SCHEMA\n')),),
136+
Case('management_manifest_hash', ((COORDINATION + "shadow_management.ts", replacement('managementDigest(manifest) !== state.operation.manifest_digest\n || !supportedSchema\n', 'false\n || !supportedSchema\n')),),
137137
"tests/control_plane_ts/shadow_management.test.ts", 'management manifest hash'),
138138
Case('management_phase', ((COORDINATION + "shadow_management.ts", replacement('operation.kind !== kind || !phases.includes(String(operation.phase))', 'operation.kind !== kind')),),
139139
"tests/control_plane_ts/shadow_management.test.ts", 'management phase validation'),

‎loopx/capabilities/decision_context/packets.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ...control_plane.runtime.public_safety import (
1414
REMOTE_LOCATION_SURFACE_PATTERN,
1515
SECRET_LIKE_SURFACE_PATTERN,
16+
find_public_safe_local_path,
1617
)
1718

1819
DECISION_EVIDENCE_PACKET_SCHEMA_VERSION = "decision_evidence_packet_v0"
@@ -40,7 +41,10 @@
4041
}
4142

4243
_TOKEN_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$")
43-
_LOCAL_PATH_RE = re.compile(r"(^|[\s:=])(?:/Users/|/private/|/tmp/|~/)")
44+
# Refs #5136, direction 3: "does this text carry a local path?" is decided once
45+
# by find_public_safe_local_path; this site keeps its own rejection message and
46+
# length limit for whatever the owner recognizes.
47+
#
4448
# Local threshold policy only: the credential *shapes* are decided once by
4549
# SECRET_LIKE_SURFACE_PATTERN, which this site consults in addition to this list.
4650
_CREDENTIAL_RE = re.compile(
@@ -77,7 +81,7 @@ def _compact_text(value: Any, *, field: str, max_len: int = 320) -> str:
7781
raise ValueError(f"{field} must be non-empty")
7882
if len(text) > max_len:
7983
raise ValueError(f"{field} must be at most {max_len} characters")
80-
if _LOCAL_PATH_RE.search(text):
84+
if find_public_safe_local_path(text) is not None:
8185
raise ValueError(f"{field} must not contain a local path")
8286
if REMOTE_LOCATION_SURFACE_PATTERN.search(text):
8387
raise ValueError(f"{field} must use an opaque source reference, not a raw URL")

‎loopx/capabilities/material_lifecycle/_validation.py‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
from ...control_plane.runtime.public_safety import (
1313
REMOTE_LOCATION_SURFACE_PATTERN,
1414
SECRET_LIKE_SURFACE_PATTERN,
15+
find_public_safe_local_path,
1516
)
1617

1718
_TOKEN_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$")
18-
_LOCAL_PATH_RE = re.compile(r"(^|[\s:=])(?:/Users/|/private/|/tmp/|~/)")
19+
# Refs #5136, direction 3: "does this text carry a local path?" is decided once
20+
# by find_public_safe_local_path; this site keeps its own rejection message and
21+
# length limit for whatever the owner recognizes.
22+
#
1923
# Local threshold policy only: the credential *shapes* are decided once by
2024
# SECRET_LIKE_SURFACE_PATTERN, which this site consults in addition to this list.
2125
_CREDENTIAL_RE = re.compile(
@@ -53,7 +57,7 @@ def compact_text(value: Any, *, field: str, max_len: int = 320) -> str:
5357
raise ValueError(f"{field} must be non-empty")
5458
if len(text) > max_len:
5559
raise ValueError(f"{field} must be at most {max_len} characters")
56-
if _LOCAL_PATH_RE.search(text):
60+
if find_public_safe_local_path(text) is not None:
5761
raise ValueError(f"{field} must not contain a local path")
5862
if REMOTE_LOCATION_SURFACE_PATTERN.search(text):
5963
raise ValueError(f"{field} must use an opaque reference, not a raw URL")

0 commit comments

Comments
 (0)