Skip to content

Commit 0830ae1

Browse files
committed
feat(coordination): default new Goals to canonical SQLite
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
1 parent 22d59bc commit 0830ae1

15 files changed

Lines changed: 185 additions & 52 deletions

File tree

‎apps/presentation/dashboard/smoke/capability-configuration-smoke.ts‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import assert from "node:assert/strict";
22

3-
import { parseEditableCapabilityJson, projectEditableCapabilityConfiguration } from "../src/data/capability-configuration.js";
3+
import { goalStorageEditorValue, parseEditableCapabilityJson, projectEditableCapabilityConfiguration } from "../src/data/capability-configuration.js";
44

55
const periodicReportEditor = {
66
fields: [
@@ -12,6 +12,19 @@ const periodicReportEditor = {
1212
],
1313
};
1414

15+
const storageEditor = { fields: [{ key: "new_goal_provider" }, { key: "canonical_creation" }, { key: "new_goal_handoff_mode" }] };
16+
const storageDefault = { schema_version: "loopx_goal_storage_defaults_v1", new_goal_provider: "sqlite",
17+
canonical_creation: true, new_goal_handoff_mode: "hard_lease" };
18+
assert.deepEqual(projectEditableCapabilityConfiguration(storageEditor,
19+
goalStorageEditorValue({ schema_version: "loopx_goal_storage_defaults_v0", new_goal_provider: "file" }), storageDefault),
20+
{ new_goal_provider: "file", canonical_creation: false, new_goal_handoff_mode: "hard_lease" },
21+
"opening a historical selector must not enable canonical creation through today's defaults");
22+
assert.deepEqual(projectEditableCapabilityConfiguration(storageEditor, goalStorageEditorValue(storageDefault), storageDefault),
23+
{ new_goal_provider: "sqlite", canonical_creation: true, new_goal_handoff_mode: "hard_lease" },
24+
"an unconfigured device editor shows the shared new-Goal default");
25+
assert.equal((goalStorageEditorValue({ ...storageDefault, canonical_creation: false }) as typeof storageDefault).canonical_creation, false,
26+
"an explicit v1 opt-out survives editor mode changes");
27+
1528
assert.deepEqual(
1629
projectEditableCapabilityConfiguration(periodicReportEditor, {
1730
schema_version: "periodic_report_machine_defaults_v0",

‎apps/presentation/dashboard/src/data/capability-configuration.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,11 @@ export function replanCadenceEditorValue(value: unknown): unknown {
6060
}
6161
return value;
6262
}
63+
64+
/** A v0 storage selector did not enable creation; opening Settings must not. */
65+
export function goalStorageEditorValue(value: unknown): unknown {
66+
const record = configurationObject(value);
67+
return record.schema_version === "loopx_goal_storage_defaults_v0"
68+
? { ...record, canonical_creation: false }
69+
: value;
70+
}

‎apps/presentation/dashboard/src/features/personal-workspace/capability-localization.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type FieldCopy = Record<string, Readonly<{ description?: string; label: string;
1212

1313
const capabilityCopy: Record<WorkspaceLocale, Record<string, LocalizedCopy>> = {
1414
en: {
15-
goal_storage: { displayName: "New Goal authority", description: "Opt in to canonical creation and choose the storage and execution policy for future Goals. Existing Goals require a separate backed-up migration." },
15+
goal_storage: { displayName: "New Goal authority", description: "New Goals default to canonical SQLite with hard leases. Choose storage and execution policy for future Goals. Existing Goals require a separate backed-up migration." },
1616
manager_runtime: {
1717
displayName: "Runtime",
1818
description: "Selects the persistent host-tool profile used by owner manager conversations.",
@@ -78,7 +78,7 @@ const capabilityCopy: Record<WorkspaceLocale, Record<string, LocalizedCopy>> = {
7878
},
7979
},
8080
"zh-CN": {
81-
goal_storage: { displayName: "新 Goal 的权威存储", description: "可启用 canonical 创建,选择之后新 Goal 的存储与执行策略。已有 Goal 仍需单独备份、迁移。" },
81+
goal_storage: { displayName: "新 Goal 的权威存储", description: "新 Goal 默认使用 canonical SQLite 与 hard lease;可选择之后新 Goal 的存储与执行策略。已有 Goal 仍需单独备份、迁移。" },
8282
manager_runtime: {
8383
displayName: "运行环境",
8484
description: "选择管家会话持续生效的宿主工具模式。",

‎apps/presentation/dashboard/src/features/personal-workspace/machine-configuration-settings.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
type MachineConfigurationRollbackPlan,
1818
type MachineConfigurationTransaction,
1919
} from "../../data/chat";
20-
import { projectEditableCapabilityConfiguration, replanCadenceEditorValue } from "../../data/capability-configuration";
20+
import { goalStorageEditorValue, projectEditableCapabilityConfiguration, replanCadenceEditorValue } from "../../data/capability-configuration";
2121
import { CapabilityConfigurationFields } from "./capability-configuration-fields";
2222
import { withReportScheduleTimezone } from "./periodic-report-schedule-field";
2323
import { localizeCapability, localizedCapabilityFieldCopy } from "./capability-localization";
@@ -195,7 +195,8 @@ export function MachineConfigurationSettings({ section, onChanged }: { section:
195195
const current = currentConfiguration(inspection, selected);
196196
const editable = projectEditableCapabilityConfiguration(
197197
selected.configuration_editor,
198-
selected.capability_id === "todo_replan_cadence" ? replanCadenceEditorValue(current ?? selected.default) : current ?? selected.default,
198+
selected.capability_id === "todo_replan_cadence" ? replanCadenceEditorValue(current ?? selected.default)
199+
: selected.capability_id === "goal_storage" ? goalStorageEditorValue(current ?? selected.default) : current ?? selected.default,
199200
selected.default,
200201
);
201202
const complete = completeMachineConfiguration(selected, current, editable);
@@ -227,7 +228,8 @@ export function MachineConfigurationSettings({ section, onChanged }: { section:
227228
} else if (parsedJsonDraft) {
228229
setDraft(projectEditableCapabilityConfiguration(
229230
selected.configuration_editor,
230-
selected.capability_id === "todo_replan_cadence" ? replanCadenceEditorValue(parsedJsonDraft) : parsedJsonDraft,
231+
selected.capability_id === "todo_replan_cadence" ? replanCadenceEditorValue(parsedJsonDraft)
232+
: selected.capability_id === "goal_storage" ? goalStorageEditorValue(parsedJsonDraft) : parsedJsonDraft,
231233
selected.default,
232234
));
233235
} else {

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3321,6 +3321,18 @@ new implementation work; changing languages or moving a helper is not an exit.
33213321
| C / L8: Whole-Goal rehearsal and cohort migration | Integrate one exact revision/profile after L2–L7; drain capture, fence old writers, verify canonical readback and projection, then rehearse fenced export/rollback. | D3 evidence packet binds lineage, cursor, source digest, command coverage and profile. Existing Goal migration requires explicit cohort approval; no per-command split authority or stale Markdown revival. |
33223322
| D / L9: New-Goal default and bounded retirement | A dedicated default-change PR makes new-Goal creation/onboarding choose the qualified local profile, including settings/readback, installer and packaged clients. Retire old business writers only as their final callers and migration window close. | L8's integrated product/rollback qualification; distinguish new Goal default from existing Goal migration. Publish compatibility/disable guidance, keep explicit provider choice, permanent rendering and validated import/export. T4 can continue after the default ships. |
33233323

3324+
**L9 creation-default candidate.** Unconfigured new-Goal CLI/App creation now
3325+
uses the same registered SQLite/hard-lease configuration and existing TS
3326+
initialization owner. Explicit v0 selectors and v1 creation-off remain supported;
3327+
the guided editor preserves v0 opt-out when upgrading its envelope. Existing
3328+
Goals, frozen operations, provider receipts and migration fences retain their
3329+
own route. Namespace removal restores the new default, so disable guidance
3330+
uses an explicit creation-off setting. Candidate implementation and packaged
3331+
interaction evidence remain distinct from L8/D3 integrated recovery, D2
3332+
sustained/platform qualification and release-default activation; none of those
3333+
gates is replaced by this checkpoint. No old writer or historical backup reader
3334+
is retired by this change.
3335+
33243336
**Earlier 2026-09-24 implementation context.** Display refresh advances
33253337
projection recovery/client closure without claiming every consumer qualified. SQLite #4910 added the larger measurement axes; #4224 records
33263338
failed 1 MiB receipt/scan budgets and still-missing recovery/soak evidence.
160 KB
Loading
131 KB
Loading

‎docs/reference/local-authority-provider-selection.md‎

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ authenticated service or grant an Agent database access.
4444

4545
The default profile is a routing decision, not a migration. Existing Markdown
4646
state, writer fences, qualification gates, and explicit File/SQLite promotion
47-
holds remain unchanged. SQLite stays an opt-in qualified candidate until the
47+
holds remain unchanged. The released SQLite profile remains opt-in until the
4848
shared-authority RFC's D2 evidence and owner approval are complete. PostgreSQL
4949
remains an independent service-provider qualification path.
5050

@@ -62,15 +62,23 @@ See [reviewed promotion and recovery](reviewed-coordination-promotion.md) for th
6262
## New Goal authority (machine setting)
6363

6464
**Settings → Capability Center → Device defaults → New Goal authority** selects
65-
File or SQLite independently of the execution policy. Enable **Create canonical
66-
authority** to initialize future empty Goals directly with `soft_claim` or
67-
`hard_lease`. Agents inherit the Goal policy; this grants no tool, repository,
65+
File or SQLite independently of the execution policy. In the new-Goal default
66+
candidate, a device without a `goal_storage` namespace creates canonical SQLite
67+
with `hard_lease`; CLI bootstrap and App creation reuse the same configuration
68+
and typed initialization owner. **Create canonical authority** can be disabled
69+
explicitly, or used with File and either `soft_claim` or `hard_lease`. Agents
70+
inherit the Goal policy; this grants no tool, repository,
6871
scheduler, account or network permission and does not migrate existing data.
6972

70-
Canonical creation is default-off. An absent namespace, the released v0 shape,
71-
or v1 with `canonical_creation=false` retains the post-promotion target behavior.
73+
The candidate changes only unconfigured new creation. Released v0 settings and
74+
v1 with `canonical_creation=false` retain the post-promotion target behavior.
7275
Opening v0 in the guided editor previews a v1 envelope upgrade with creation
73-
still disabled. The CLI continues to accept v0.
76+
still disabled; switching editor modes cannot enable it through the new default.
77+
The CLI continues to accept v0. Existing Goals keep their recorded target,
78+
including its absence, even when device settings change. Invalid configuration
79+
fails before registry publication rather than being treated as an absent setting.
80+
Registry-relative runtime paths are compared by their resolved filesystem
81+
location, so an equivalent spelling cannot masquerade as an authority move.
7482

7583
Save this namespace document as `goal-storage.json`:
7684

@@ -116,36 +124,33 @@ cannot adopt it. The original receipt survives later native writes, so replay
116124
cannot erase Todos or repeat their creation. An unavailable selected provider
117125
fails visibly without Markdown fallback. Lost completed authority requires full
118126
backup recovery and cannot be treated as empty creation. Generic forced
119-
bootstrap cannot rebuild an opted-in Goal.
127+
bootstrap cannot rebuild a canonically created Goal.
120128

121129
<details>
122130
<summary>Settings and recovery views / 设置与恢复界面</summary>
123131

124-
Synthetic workspace data; the settings use a real isolated backend. The first
125-
view is the released v0 editor; the remaining views show the proposed v1 path.
132+
Synthetic workspace data on the candidate's packaged App and installed wheel;
133+
model execution is disabled in this isolated creation/configuration rehearsal.
126134

127-
Before: the provider setting only chooses the post-promotion target.
135+
Released v0 preferences remain target-only when opened in the candidate editor.
128136

129-
![Released target-only editor](images/new-goal-authority/before.png)
137+
![Existing File preference stays disabled](images/new-goal-authority/v0-retained.png)
130138

131-
After: provider, explicit canonical opt-in and execution policy, with applied
132-
configuration readback.
139+
Removing that preference restores canonical SQLite/hard-lease defaults, with
140+
native removal readback. It does not migrate the existing Goals.
133141

134-
![Canonical creation settings and readback](images/new-goal-authority/after.png)
142+
![Candidate SQLite defaults after preference removal](images/new-goal-authority/sqlite-default.png)
135143

136-
An unsupported `legacy` policy is rejected before apply; the previous valid
137-
configuration remains. Correcting the policy allows preview and apply again.
138-
139-
![Invalid policy rejected](images/new-goal-authority/invalid-policy.png)
140-
141-
The same device settings at a narrow viewport:
142-
143-
![Narrow device settings](images/new-goal-authority/mobile.png)
144+
The existing preview/apply revision gate is unchanged. Unsupported `legacy`
145+
policy is rejected before apply; correct the policy and preview again. No new
146+
layout or responsive navigation is introduced.
144147

145148
</details>
146149

147150
To disable future canonical creation, preview and apply the same v1 document
148-
with `canonical_creation=false`. To remove the whole preference:
151+
with `canonical_creation=false`. Removing the preference restores the candidate
152+
SQLite/hard-lease default for future new Goals; removal is **not** opt-out.
153+
To remove the whole preference:
149154

150155
```sh
151156
loopx machine-config remove --namespace goal_storage
@@ -162,15 +167,18 @@ already-canonical Goals use the [reviewed File/SQLite cutover](file-authority-st
162167
Retain verified backups, stop writers, settle leases and preserve newer writes
163168
on reverse migration. Supported historical backup/format/receipt readers remain.
164169

165-
This opt-in path does not close full existing-Goal upgrade, D2 sustained
166-
qualification or the release-default decision. Trial admission and release
170+
This implementation candidate does not close full existing-Goal upgrade, D2
171+
sustained qualification or authorize release-default activation. Trial admission and release
167172
default admission remain separate; the existing RFC acceptance is unchanged.
168173

169174
### 新 Goal 的权威存储
170175

171176
在“设置 → 能力中心 → 此设备默认 → 新 Goal 的权威存储”中,分别选择 File/SQLite
172-
和 `soft_claim`/`hard_lease`,并显式启用 canonical 创建。默认关闭;旧 v0 或关闭
173-
状态仍只固定晋升后的目标。表单以关闭状态预览 v1 升级,CLI 继续接受旧格式。
177+
和 `soft_claim`/`hard_lease`。候选实现让未配置此命名空间的新 Goal 默认建立
178+
canonical SQLite、使用 `hard_lease`,CLI 与 App 共用配置和类型化创建归属。
179+
旧 v0 或显式关闭状态仍只固定晋升后的目标;表单以关闭状态预览 v1 升级,
180+
切换编辑模式也不会自动启用。CLI 继续接受旧格式,已有 Goal 保留原路径。
181+
Registry 中的相对 runtime 路径按实际文件位置比较;等价路径不会误触发权威迁移检查。
174182
Agent 继承 Goal 策略;此设置不授予工具、仓库、账户或网络权限。
175183

176184
CLI 使用上面的完整 JSON 和 preview/apply/inspect/bootstrap 命令;App 用现有
@@ -184,10 +192,11 @@ CLI 使用上面的完整 JSON 和 preview/apply/inspect/bootstrap 命令;App
184192
后的存储丢失须恢复完整备份,不能重新创建空库;通用 force 不能重建。原回执在
185193
后续写入后仍可读回,重试不得丢失或重复 Todo。
186194

187-
关闭或按上面的 remove 预览/执行命令删除偏好,只影响之后新建;不会迁回已有数据、
195+
显式设置 `canonical_creation=false` 才关闭之后的新建;remove 删除偏好会恢复候选
196+
SQLite/hard-lease 默认,不能用于关闭。两者均不会迁回已有数据、
188197
删除 fence 或重新开放旧 writer。既有 Goal 升级仍需备份、停止写入、结算租约和
189198
审核计划;反向迁移须保留新增写入。受支持的旧备份、格式和原回执恢复能力保留。
190-
此路径不代表完整升级、D2 长期资格或发布默认已通过。
199+
配置损坏明确失败,不视为未配置;候选实现不代表完整升级、D2 长期资格或发布默认已通过。
191200

192201
Prose-only source maintenance compares the exact canonical JSON bytes of the
193202
existing stable partition view. Only the resume evaluation clock is excluded;

‎docs/reference/sqlite-authority-store.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,14 @@ Before changing release defaults, the existing owners must close these gaps:
113113
including installed runtime admission, settings/readback and packaged entry
114114
points. Keep explicit provider selection and reviewed backup/rollback.
115115

116+
The L9 implementation candidate now resolves an absent `goal_storage` namespace
117+
to canonical SQLite/hard-lease creation through the existing configuration and
118+
TS initialization owners. Explicit v0 selectors, v1 opt-out and existing Goals
119+
keep their recorded route. Settings preserves v0 opt-out during guided/JSON
120+
conversion; removing a setting restores the new default. See [new-Goal creation
121+
and compatibility](local-authority-provider-selection.md#new-goal-authority-machine-setting).
122+
This candidate does not certify the gates above or activate an installed release.
123+
116124
Both current local providers require Node >=22.22.3. SQLite uses built-in
117125
`node:sqlite`: it adds no database service or external SQLite package. Its
118126
actual embedded SQLite/finalization probe remains required, and a pre-existing

‎loopx/bootstrap.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ def bootstrap_project(
350350
if not state_file.is_absolute():
351351
state_file = project / state_file
352352
goal_doc = resolve_project_path(project, goal_doc)
353-
runtime_root = resolve_runtime_root(read_json_if_exists(registry_path), str(runtime_root) if runtime_root else None, registry_path=registry_path)
353+
runtime_root = resolve_runtime_root(read_json_if_exists(registry_path), str(runtime_root) if runtime_root else None, registry_path=registry_path).resolve()
354354
updated_at = now_iso()
355355
execution_profile = build_execution_profile(
356356
minimum_scale=execution_minimum_scale,
@@ -568,7 +568,7 @@ def bootstrap_project(
568568
# A first explicit bootstrap has no previous Goal authority to fence.
569569
# Existing Goals still resolve and authorize their original route.
570570
if current_registry.get("goals"):
571-
previous_root = resolve_runtime_root(current_registry, None, registry_path=registry_path)
571+
previous_root = resolve_runtime_root(current_registry, None, registry_path=registry_path).resolve()
572572
if previous_root != runtime_root:
573573
for previous_goal in current_registry["goals"]:
574574
if isinstance(previous_goal, dict) and previous_goal.get("id"):

0 commit comments

Comments
 (0)