@namewta/speculo 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/package.json +5 -2
  2. package/template/canonical/canonical-specdev-goal-plan.md +2 -2
  3. package/template/canonical/canonical-specdev-grill-with-docs.md +2 -2
  4. package/template/canonical/canonical-specdev-spec.md +11 -136
  5. package/template/canonical/canonical-specdev-tickets.md +2 -2
  6. package/template/canonical/canonical-specdev-wayfinder.md +2 -2
  7. package/template/commands/handoff.md +16 -0
  8. package/template/commands/retro.md +1 -1
  9. package/template/skills/github-npm-ops/references/issue-pr-triage.md +8 -0
  10. package/template/skills/speculo-retro/references/entry-procedure.md +19 -3
  11. package/template/skills/speculo-retro/references/issue-drafting-sop.md +3 -1
  12. package/template/workflows/learning/A-archive/A-archive.md +2 -5
  13. package/template/workflows/learning/A-assess-and-plan/A-assess-and-plan.md +2 -5
  14. package/template/workflows/learning/C-consolidate/C-consolidate.md +2 -5
  15. package/template/workflows/learning/G-goal/G-goal.md +5 -23
  16. package/template/workflows/learning/H-homework/H-homework.md +2 -5
  17. package/template/workflows/learning/I-init-setup/I-init-setup.md +4 -9
  18. package/template/workflows/learning/L-lesson/L-lesson.md +2 -5
  19. package/template/workflows/learning/Q-question/Q-question.md +16 -8
  20. package/template/workflows/learning/Q-question/inquiry-template.md +2 -0
  21. package/template/workflows/learning/Q-question/tools/validate-inquiry.mjs +112 -0
  22. package/template/workflows/learning/R-review/R-review.md +3 -6
  23. package/template/workflows/learning/README.md +2 -2
  24. package/template/workflows/learning/common/rules/knowledge-organization.md +1 -1
  25. package/template/workflows/learning/common/rules/mastery-policy.md +1 -1
  26. package/template/workflows/learning/common/skills/socratic-questioning/SKILL.md +1 -1
  27. package/template/workflows/ops/D-project-deploy/D-project-deploy.md +15 -9
  28. package/template/workflows/ops/H-host-manage/H-host-manage.md +14 -21
  29. package/template/workflows/ops/H-host-manage/references/host-profiles.md +21 -0
  30. package/template/workflows/ops/I-initialize/I-initialize.md +7 -7
  31. package/template/workflows/ops/INDEX.md +20 -16
  32. package/template/workflows/ops/README.md +29 -73
  33. package/template/workflows/ops/S-server-connect/S-server-connect.md +28 -0
  34. package/template/workflows/ops/V-inventory-view/V-inventory-view.md +30 -0
  35. package/template/workflows/ops/common/CAPABILITIES.md +22 -15
  36. package/template/workflows/ops/common/WORKSPACE-USAGE.md +78 -0
  37. package/template/workflows/ops/common/examples/task-host.example.json +64 -0
  38. package/template/workflows/ops/common/rules/activation-and-memory.md +5 -3
  39. package/template/workflows/ops/common/rules/deployment-layout.md +51 -0
  40. package/template/workflows/ops/common/rules/inventory-and-records.md +55 -0
  41. package/template/workflows/ops/common/rules/recovery.md +6 -0
  42. package/template/workflows/ops/common/rules/research-and-decisions.md +18 -0
  43. package/template/workflows/ops/common/rules/server-onboarding.md +27 -0
  44. package/template/workflows/ops/common/rules/workspace-and-authorization.md +39 -0
  45. package/template/workflows/ops/common/schemas/fleet-view.schema.json +487 -0
  46. package/template/workflows/ops/common/schemas/server-check.schema.json +95 -0
  47. package/template/workflows/ops/common/schemas/task-request.schema.json +138 -0
  48. package/template/workflows/ops/common/templates/FLEET.html +61 -0
  49. package/template/workflows/ops/common/tests/test_ops_workspace.mjs +246 -0
  50. package/template/workflows/ops/common/tools/ops.mjs +5 -3
  51. package/template/workflows/ops/common/tools/opslib/fleet.mjs +155 -0
  52. package/template/workflows/ops/common/tools/opslib/server_checks.mjs +149 -0
  53. package/template/workflows/ops/common/tools/opslib/tasks.mjs +313 -0
  54. package/template/workflows/ops/common/tools/opslib/workspace.mjs +107 -0
  55. package/template/workflows/ops/common/tools/opslib/workspace_cli.mjs +80 -0
  56. package/template/workflows/ops/common/tools/validate-ops.mjs +11 -8
  57. package/template/workflows/ops/manifest.json +43 -7
  58. package/template/workflows/person/M-mao-zedong-cognitive-os/M-mao-zedong-cognitive-os.md +13 -68
  59. package/template/workflows/person/S-steelman-deliberation/S-steelman-deliberation.md +11 -123
  60. package/template/workflows/person/S-steelman-deliberation/references/state-and-publication.md +86 -0
  61. package/template/workflows/specdev/A-archive-and-consolidate/A-archive-and-consolidate.md +2 -17
  62. package/template/workflows/specdev/A-archive-and-consolidate/consolidation-interview.md +10 -1
  63. package/template/workflows/specdev/C-code-review/C-code-review.md +3 -14
  64. package/template/workflows/specdev/C-code-review/code-review-template.md +4 -0
  65. package/template/workflows/specdev/D-diagnose-bugs/D-diagnose-bugs.md +1 -23
  66. package/template/workflows/specdev/G-grill-with-docs/G-grill-with-docs.md +2 -2
  67. package/template/workflows/specdev/I-implement/I-implement.md +2 -2
  68. package/template/workflows/specdev/I-implement/evidence-template.md +8 -0
  69. package/template/workflows/specdev/I-implement/references/implementation-procedure.md +8 -42
  70. package/template/workflows/specdev/I-init-setup/I-init-setup.md +16 -117
  71. package/template/workflows/specdev/I-init-setup/references/first-setup.md +46 -0
  72. package/template/workflows/specdev/L-learn-change/L-learn-change.md +11 -89
  73. package/template/workflows/specdev/L-learn-change/references/lesson-format.md +47 -0
  74. package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +2 -2
  75. package/template/workflows/specdev/P-prototype/P-prototype.md +2 -16
  76. package/template/workflows/specdev/R-review-architecture/R-review-architecture.md +19 -57
  77. package/template/workflows/specdev/R-review-architecture/architecture-review-template.md +2 -1
  78. package/template/workflows/specdev/R-review-architecture/references/selected-design.md +23 -0
  79. package/template/workflows/specdev/R-review-architecture/review-rubric.md +2 -2
  80. package/template/workflows/specdev/README.md +4 -4
  81. package/template/workflows/specdev/S-spec/S-spec.md +11 -138
  82. package/template/workflows/specdev/T-tickets/T-tickets.md +2 -2
  83. package/template/workflows/specdev/T-triage/T-triage.md +21 -136
  84. package/template/workflows/specdev/T-triage/intake-protocol.md +19 -0
  85. package/template/workflows/specdev/W-wayfinder/W-wayfinder.md +2 -2
  86. package/template/workflows/specdev/common/rules/deployment-handoff.md +23 -0
  87. package/template/workflows/specdev/common/skills/code-review/SKILL.md +5 -4
  88. package/template/workflows/specdev/common/skills/code-review/references/result-reuse.md +15 -0
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+ /** Read-only validation of the current inquiry batch, never historical migration.
3
+ * A supplied before snapshot proves byte preservation, not who authored it.
4
+ */
5
+ import { lstatSync, readFileSync, realpathSync } from 'node:fs';
6
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ function visible(text) {
10
+ let fence = null;
11
+ // Replace hidden characters with spaces, preserving exact source offsets.
12
+ const blank = (value) => value.replace(/[^\r\n]/g, ' ');
13
+ return text.replace(/<!--[\s\S]*?-->/g, blank).split('\n').map((line) => {
14
+ const marker = /^\s*(`{3,}|~{3,})/.exec(line)?.[1];
15
+ if (marker && !fence) { fence = marker; return blank(line); }
16
+ if (fence) {
17
+ if (marker && marker[0] === fence[0] && marker.length >= fence.length) fence = null;
18
+ return blank(line);
19
+ }
20
+ return line;
21
+ }).join('\n');
22
+ }
23
+
24
+ function parse(text) {
25
+ const errors = [];
26
+ if (typeof text !== 'string') return { errors: ['inquiry must be text'] };
27
+ const header = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
28
+ if (!header) return { errors: ['frontmatter is required'] };
29
+ const counts = [...header[1].matchAll(/^question_count:\s*(.*?)\s*$/gm)];
30
+ const count = counts.length === 1 && /^[1-9]\d*$/.test(counts[0][1]) ? Number(counts[0][1]) : NaN;
31
+ if (!Number.isSafeInteger(count)) errors.push('question_count must be one positive integer field');
32
+ const body = visible(text.slice(header[0].length));
33
+ const markers = [...body.matchAll(/^Response:[ \t]*(pending|ready|closed)[ \t\r]*$/gm)];
34
+ if (markers.length !== 1) errors.push('exactly one Response: pending|ready|closed marker is required');
35
+ const response = markers[0]?.[1];
36
+ const q = [...body.matchAll(/^## Questions[ \t\r]*$/gm)];
37
+ const a = [...body.matchAll(/^## Learner Answers[ \t\r]*$/gm)];
38
+ const mark = markers[0]?.index ?? -1;
39
+ if (q.length !== 1 || a.length !== 1 || !(q[0]?.index < a[0]?.index && a[0]?.index < mark)) {
40
+ errors.push('Questions, Learner Answers and Response must occur once in order');
41
+ } else {
42
+ const qs = [...body.slice(q[0].index, a[0].index).matchAll(/^### Q(\d+)\b/gm)].map((m) => Number(m[1]));
43
+ const as = [...body.slice(a[0].index, mark).matchAll(/^### A(\d+)\b/gm)].map((m) => Number(m[1]));
44
+ for (const [kind, numbers] of [['Q', qs], ['A', as]]) {
45
+ if (numbers.length !== count || numbers.some((n, i) => n !== i + 1)) errors.push(`${kind} numbering must be contiguous 1..question_count`);
46
+ }
47
+ }
48
+ const teaching = [...body.matchAll(/^## Teaching[ \t\r]*$/gm)];
49
+ const lesson = [...body.matchAll(/^## Inquiry Lesson[ \t\r]*$/gm)];
50
+ if (response !== 'closed' && (teaching.length || lesson.length)) errors.push('pending/ready batch must not contain Teaching or Inquiry Lesson');
51
+ if (response === 'closed' && !(teaching.length === 1 && lesson.length === 1 && teaching[0].index > mark && lesson[0].index > teaching[0].index)) {
52
+ errors.push('closed batch requires appended Teaching then Inquiry Lesson');
53
+ }
54
+ if (response === 'closed' && !body.includes('Explain (English)')) errors.push('Teaching requires Explain (English)');
55
+ if (/^Submission:|\bverdict\s*:/m.test(body)) errors.push('inquiry must not use Homework Submission or verdict fields');
56
+ return { errors, count, response, frozen: mark >= 0 ? text.slice(0, header[0].length + mark) : null };
57
+ }
58
+
59
+ export function validateInquiry(text, { expectedCount, before } = {}) {
60
+ const parsed = parse(text);
61
+ const errors = [...parsed.errors];
62
+ if (expectedCount !== undefined && (!Number.isSafeInteger(expectedCount) || expectedCount < 1 || expectedCount !== parsed.count)) {
63
+ errors.push('actual question_count differs from the requested count');
64
+ }
65
+ let frozenInputs = 'not-checked';
66
+ if (parsed.response === 'closed' && before === undefined) errors.push('closing requires the original Response: ready snapshot');
67
+ if (before !== undefined) {
68
+ const previous = parse(before);
69
+ if (previous.errors.length || previous.response !== 'ready') errors.push('before must be a valid original Response: ready batch');
70
+ else if (parsed.response !== 'closed' || previous.frozen !== parsed.frozen) errors.push('closing must preserve original metadata, questions and answers byte-for-byte');
71
+ else frozenInputs = 'verified-against-supplied-snapshot';
72
+ }
73
+ return { valid: errors.length === 0, question_count: parsed.count ?? null, response: parsed.response ?? null,
74
+ frozen_inputs: frozenInputs, scope: 'current batch structure and supplied bytes; not human authorship or teaching-quality certification', errors };
75
+ }
76
+
77
+ function readWithin(root, value) {
78
+ if (!value || value.split(/[\\/]/).includes('..')) throw new Error('unsafe inquiry path');
79
+ const full = resolve(root, value), rel = relative(root, full);
80
+ if (!rel || isAbsolute(rel) || rel === '..' || rel.startsWith(`..${sep}`) || !full.endsWith('.md')) throw new Error('inquiry path must be a Markdown file inside change-dir');
81
+ if (realpathSync(root) !== root) throw new Error('change-dir must not traverse a symlink');
82
+ let current = root;
83
+ for (const part of rel.split(sep)) {
84
+ current = resolve(current, part);
85
+ if (lstatSync(current).isSymbolicLink()) throw new Error('inquiry symlink is not permitted');
86
+ }
87
+ if (!lstatSync(full).isFile()) throw new Error('inquiry must be a regular file');
88
+ return readFileSync(full, 'utf8');
89
+ }
90
+
91
+ function main(argv) {
92
+ const flags = new Map();
93
+ for (let i = 0; i < argv.length; i += 2) {
94
+ const key = argv[i], value = argv[i + 1];
95
+ if (!['--change-dir', '--file', '--before', '--expected-count'].includes(key) || flags.has(key) || !value || value.startsWith('--')) throw new Error('invalid, duplicate or missing option');
96
+ flags.set(key, value);
97
+ }
98
+ if (!flags.has('--change-dir') || !flags.has('--file')) throw new Error('use --change-dir ABSOLUTE_CHANGE --file BATCH.md [--expected-count N] [--before READY.md]');
99
+ if (!isAbsolute(flags.get('--change-dir'))) throw new Error('change-dir must be absolute');
100
+ const root = resolve(flags.get('--change-dir'));
101
+ const count = flags.has('--expected-count') ? Number(flags.get('--expected-count')) : undefined;
102
+ const result = validateInquiry(readWithin(root, flags.get('--file')), {
103
+ expectedCount: count,
104
+ before: flags.has('--before') ? readWithin(root, flags.get('--before')) : undefined,
105
+ });
106
+ console.log(JSON.stringify(result, null, 2));
107
+ process.exitCode = result.valid ? 0 : 1;
108
+ }
109
+
110
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
111
+ try { main(process.argv.slice(2)); } catch (error) { console.error(error.message); process.exitCode = 1; }
112
+ }
@@ -13,19 +13,16 @@ keywords: [复习, retention, spaced-review, transfer]
13
13
 
14
14
  ## 读取范围
15
15
 
16
- 当前步骤开始前,读取 `<Path>{roots.workflows}/learning/common/rules/homework-contract.md</Path>`;它们是本步骤必需合同,不默认加载其他分支。
17
-
18
- 1. 先读取 `<Path>{roots.workflows}/learning/README.md</Path>` 与当前 Work 的状态入口。
19
- 2. 再读取 `<Path>{roots.workflows}/learning/common/rules/activation-and-memory.md</Path>`,按当前分支、状态和关键词定位最小相关工件。
20
- 3. 只在本 Work 明确要求恢复、冲突、执行安全或归档证据时扩展为全量读取;缺少匹配证据或 owner/gateway 时停止受影响分支。
16
+ 当前步骤开始前,读取 `<Path>{roots.workflows}/learning/common/rules/homework-contract.md</Path>`;只加载本 Work 需要的领域合同。
21
17
 
18
+ 读取 `<Path>{roots.workflows}/learning/common/rules/activation-and-memory.md</Path>`,按当前 Change、OBJ、主题与证据 ID 定位本轮输入;仅当前恢复或安全门要求时扩读。
22
19
 
23
20
  ## 流程
24
21
 
25
22
  1. 用户明确指定 Lesson、Homework、Change 或 topic;按 review/来源索引只读取对应 sources、目标和到期的过去证据。没有真实间隔时只记录 `due_at`,不伪造通过。
26
23
  2. 在 Change 的 `review/INDEX.md` 和 `review/RV-<id>.md` 生成新复习记录。题目必须包含延迟回忆、机制/反例和新的迁移情境,不复制刚看过的示例。
27
24
  3. 原样保存回答并给出逐项证据;失败只生成补救范围和 `needs_review`,不删除历史、不改写 archived 原文。
28
- 4. 只有通过真实延迟复习才设置 `mastery.retention=passed`、`mastery.overall=retention_verified`,并在 context topic view 标记 `mastered`。R 完成后不自动激活 A。
25
+ 4. 只有通过真实延迟复习才设置 `mastery.retention=passed`、`mastery.overall=retention_verified`,仅更新当前 Change 的 retention 证据与状态投影。永久 context topic view 仍由 `<Path>{roots.workflows}/learning/C-consolidate/C-consolidate.md</Path>` 通过原发布网关在用户确认后消费该证据并标记 `mastered`;R 不直接写 context,不自动激活 C 或 A。
29
26
 
30
27
  ## 完成标准
31
28
 
@@ -11,7 +11,7 @@
11
11
  - **A-archive** — 冷归档:用户明确关闭后移动整个 Change 树到日期目录;不做知识综合或掌握判断。
12
12
  - **A-assess-and-plan** — 评估背景并设计课程:以目标和证据为起点建立课程、背景、基线、来源和可变 Lesson 地图。
13
13
  - **C-consolidate** — 主题整合:将选定 Change 物理嵌入父 Change,生成带 claim 级 provenance 的可迭代主题综合。
14
- - **G-goal** — 目标学习(目标模式):为选定编程项目编译一份可被外部 /goal 执行的完整 Goal-Plan;按项目切 ≤15 节的 mine unit,先写齐再按课派 miner。计划会话可跟随 A 写出课程地图,但不写 Lesson、不向学习者提问、不自动串联 H/R/C。
14
+ - **G-goal** — 目标学习(目标模式):为选定编程项目编译一份可被外部 /goal 执行的完整 Goal-Plan;计划会话可跟随 A 写出课程地图并按库存切 ≤15 的 mine unit,但不写 Lesson、不进行教学探针提问、不自动串联 H/R/C。
15
15
  - **H-homework** — 课程作业与评审:以单一 Markdown 文件生成题目、接收显式提交并追加逐题评审;不与 Lesson 混写。
16
16
  - **I-init-setup** — 初始化学习系统:初始化 Learning v2 的教学偏好、空索引、位置登记和可验证状态。
17
17
  - **L-lesson** — 完整课程讲解:一次输出 30–40 分钟、通俗但完整的 Lesson;不生成作业、不评分、不宣称掌握。
@@ -56,7 +56,7 @@ Any closed root tree --(user chooses A)--> archive/YYYY-MM/<change>
56
56
 
57
57
  ## 状态字段
58
58
 
59
- `.speculo/learning/status.json` 与 `.speculo/learning/locations.json` 使用 v2。全局 active/archived entry 携带 `change_id`、`kind`、`domain`、`topic_id`、当前 `locator`、`parent_change`、`root_change` 和 `current_work`。`locations.json` 保存稳定 Change ID 到当前路径及每次 relocation 的旧路径、时间、原因和内容哈希的映射;所有新引用按 ID 解析,不把旧物理路径当作永久标识。
59
+ `<Path>{roots.state}/learning/status.json</Path>` 与 `<Path>{roots.state}/learning/locations.json</Path>` 使用 v2。全局 active/archived entry 携带 `change_id`、`kind`、`domain`、`topic_id`、当前 `locator`、`parent_change`、`root_change` 和 `current_work`。`locations.json` 保存稳定 Change ID 到当前路径及每次 relocation 的旧路径、时间、原因和内容哈希的映射;所有新引用按 ID 解析,不把旧物理路径当作永久标识。
60
60
 
61
61
  每个 Change 的 `.status.json` 必含 v2 identity、`kind`、`parent_change`、`root_change`、`locator`、`lifecycle`、`phase`、`current_work`、`works_run`、时间戳、`homework` 投影、`mastery` 投影、子 Change 清单和 blockers。`mastery.immediate` 只表示当前作业评审,`mastery.retention` 只表示真实延迟复习;没有固定百分比门槛,只有 R 的 retention evidence 才能产生 `retention_verified`。
62
62
 
@@ -4,4 +4,4 @@
4
4
 
5
5
  每个 claim 记录稳定 `claim_id`、陈述、`evidence_status`(`draft|supported|contested|unresolved`)、source Change ID、Lesson/Homework/Review anchor、外部 source ID、验证时间和冲突/空白。所有链接用 `{roots.*}` aliases;物理 relocation 后由 `locations.json` 按 Change ID 解析当前路径。
6
6
 
7
- 只有 R 的真实 retention evidence 才能把 claim/status 标为 `retention_verified` 或 `mastered`。C 可以综合未掌握材料,但必须保留 evidence status,不能从综合文本推断掌握。
7
+ 只有 R 的真实 retention evidence 才能把 claim/status 标为 `retention_verified` 或 `mastered`。R 只产生 retention 原始证据与 Change 投影,永久 context 发布仍由 C 经原网关和用户确认完成。C 可以综合未掌握材料,但必须保留 evidence status,不能从综合文本推断掌握。
@@ -2,4 +2,4 @@
2
2
 
3
3
  即时理解来自 H 的逐题评审,字段为 `mastery.immediate` 和 objective/transfer projection;H 评审后可以结束当前轮次。没有固定 80% 门槛,也不要求 Homework、R 或掌握才能使用 A-archive。
4
4
 
5
- 保持掌握只能来自 R:必须在真实间隔后重新回忆、解释、反例和新情境迁移;时间未到只能记录 due date。通过后设置 `mastery.retention=passed`、`mastery.overall=retention_verified`,并允许 context 标记 mastered。失败不删除历史,必要时建立补救 Lesson/Change。
5
+ 保持掌握只能来自 R:必须在真实间隔后重新回忆、解释、反例和新情境迁移;时间未到只能记录 due date。通过后设置 `mastery.retention=passed`、`mastery.overall=retention_verified`,此证据可供 C 在原网关经用户确认后更新 context 的 mastered 投影;R 本身不直接发布永久 context。失败不删除历史,必要时建立补救 Lesson/Change。
@@ -12,7 +12,7 @@ compatibility: Requires the owning Speculo workflow and its workspace path resol
12
12
  2. 读取调用方给出的 topic、OBJ、baseline、指定 `teaching_method` 和已有 inquiry 索引;按 `<Path>{roots.workflows}/learning/common/rules/questioning-policy.md</Path>` 选择配方,不要整读 archive。
13
13
  3. 先判断能否提问:真新手或高元素交互时返回降级探针或「先走 L-lesson」建议,而不是硬出机制题。
14
14
  4. 默认 `socratic` 五槽:澄清、机制证据、假设反例、迁移视角、元问题/下一步。用户指定 `5e-recipe` / `feynman` / `productive-failure` / custom 时只改题目,不改 inquiry 文件协议。
15
- 5. `audience=tutor` 写入 `inquiry/IQ-*.md`:Q1–Q5、空 A、`Response: pending`。`Response: ready` 后只追加 Teaching 与 Inquiry Lesson;不改写答案,不写 `lessons/`、`homework/`、mastered、`Submission`、`verdict`。
15
+ 5. `audience=tutor` 写入 `inquiry/IQ-*.md`:本批实际 n 对 Q1–Qn/A1–An(用户指定,否则默认 5)、`question_count=n`、`Response: pending`。`Response: ready` 后只追加 Teaching 与 Inquiry Lesson;不改写答案,不写 `lessons/`、`homework/`、mastered、`Submission`、`verdict`。
16
16
  6. `audience=mine` 写入 `goal/probes/GP-*.md`:只审问已写 Lesson 与源码,不写学习者问答,不写 `Response:`、`Submission:`、verdict、mastered,不写 `inquiry/`,不得写 `lessons/`。默认一批 5 问(`b01` = Q1–Q5);每课最多两批 10 问(`b02` = Q6–Q10)。第三批必须返回 `split-proposal` 路由而不是再出题。禁止 `b03`。满 10 后只走 `split-lesson`。
17
17
  7. Teaching 每题含思路复原、`aligned|partial|off|uncertain`、中文详解、`Explain (English)`、纠错、未见知识、来源。Inquiry Lesson 把 5 题收成一课并给 keep-alive 钩子。需要完整 30–40 分钟讲义或正式测评时只返回路由,不自动激活 L/H/R。
18
18
 
@@ -2,22 +2,24 @@
2
2
  id: ops/project-deploy
3
3
  type: workflow-entry
4
4
  workflow: ops
5
- name: APP 与公共服务部署
6
- description: 按固定项目根规划部署、共享资源、版本更新与双边文档。
7
- keywords: [ops, project-deploy, 主机, 持久化, 审批]
5
+ name: 项目与共享服务部署
6
+ description: 固定一个项目及目标服务器,配置项目容器、依赖、升级与双边文档,不隐式取得整台服务器的维护权限。
7
+ keywords: [ops, project-deploy, 项目, 持久化, 明确范围]
8
8
  ---
9
9
 
10
- # APP 与公共服务部署
10
+ # 项目与共享服务部署
11
11
 
12
12
  激活本 Work 后先读取 `<Path>{roots.workflows}/ops/README.md</Path>`。
13
13
 
14
14
  ## 读取范围
15
15
 
16
- 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前主机/项目/部署 ID 定位最小证据。只因冲突、unknown、权限或迁移安全需要扩读,不默认遍历全域明文。
16
+ 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前 ID 定位最小证据。规划、执行或恢复前读取 `<Path>{roots.workflows}/ops/common/rules/workspace-and-authorization.md</Path>`、`<Path>{roots.workflows}/ops/common/rules/persistence-and-secrets.md</Path>`、`<Path>{roots.workflows}/ops/common/rules/deployment-layout.md</Path>` 与 `<Path>{roots.workflows}/ops/common/rules/recovery.md</Path>`;共享依赖再读取 `<Path>{roots.workflows}/ops/common/rules/shared-services.md</Path>`。
17
17
 
18
18
  ## 流程与完成标准
19
19
 
20
- 从用户指定的本地路径或固定 Git commit 读取实际清单;analyze 不执行仓库代码。网络获取源码必须用户允许并固定完整提交,不用浮动 main/tag。修改来源版本用 resource_updates 写进新计划,而非伪造旧部署的源码版本。
20
+ 先固定 project_id、显式 server_ids、环境和实例;公共 MySQL/Redis/MinIO 作为 shared-service 项目,Host.host_services 里的 Nginx/WireGuard 不伪装成项目。服务器缺接入走 S,缺系统基线走 H;已明确授权的前置 H/D specs 可组成同一 task 顺序执行,不重复确认。
21
+
22
+ 从用户指定的本地路径或固定 Git commit 读取实际清单;analyze 不执行仓库代码。网络获取源码必须用户允许并固定完整提交,不用浮动 main/tag。修改来源版本用 resource_updates 写进新计划,而非伪造旧部署的源码版本。任务执行所用本地构件/脚本放入 input_paths 冻结,编译器新发现的未审阅输入必须停止。
21
23
 
22
24
  识别项目真实启动、构建、所有持久化参数、环境变量、迁移、健康检查及恢复能力。不能仅生成通用 Compose 后声称完成。选择专用、shared、external 依赖:优先遵循用户指定 provider,多候选不得随机选择。MySQL/Redis/MinIO 按显式逻辑资源与应用账号分配;未知 lauctric 保留原名,需要真实仓库/版本和经验证的适配规则,不猜产品。
23
25
 
@@ -25,10 +27,14 @@ keywords: [ops, project-deploy, 主机, 持久化, 审批]
25
27
 
26
28
  完整 plan 明示持久化映射、来源和构件摘要、执行顺序、账号版本、网络、受影响消费者、数据库迁移单一执行者、备份与恢复限制。新装或现有 provider 均先准备并验证,再分配逻辑资源,再部署消费者。跨主机失败停止后续,逐主机保留事实,不假装全局事务。
27
29
 
28
- 用户确认摘要后 apply。upgrade/rollback 使用新的明确版本和新计划,不把旧授权或数据回滚隐含继承。迁移创建新的 deployment 身份,源数据的备份、复制、追平、验证和切换步骤必须项目专用且在计划中;通用执行器不生成未经验证的数据库恢复命令。
30
+ 已确认任务按 workspace-and-authorization.md 连续执行;未采用任务授权时仍须精确单计划批准。upgrade/rollback 使用新的明确版本和新计划,不把旧授权或数据回滚隐含继承。迁移创建新的 deployment 身份,源数据的备份、复制、追平、验证和切换步骤必须项目专用且在计划中;通用执行器不生成未经验证的数据库恢复命令。
29
31
 
30
32
  uninstall 只停止自身、退役绑定和实例,保留所有数据、账号、公共服务和共享网络。删除逻辑业务数据不是默认能力。
31
33
 
32
- 完成条件:所有业务步骤与健康检查成功;服务端 README 具有最新版本、时间、配置、持久化、步骤和依赖;控制端对应目录保存完整明文与配置镜像;两边文档 SHA256 回执通过。docs_pending 不得报全部完成。
34
+ 完成条件:所有业务步骤与健康检查成功;服务端 README 具有最新版本、时间、配置、持久化、步骤和依赖;控制端对应目录保存完整部署记录和受限真实配置镜像,普通文档默认 secret_ref,明文导出需显式 opt-in;两边文档 SHA256 回执通过。docs_pending 不得报全部完成。最后执行 V 更新项目→服务器与服务器→项目清单。
35
+
36
+ 需要实际命令参数时,只查当前动作的合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>` 与 `<Path>{roots.workflows}/ops/common/WORKSPACE-USAGE.md</Path>`;执行只通过现有 ops.mjs 网关及明确新增的任务命令,不绕过授权直接拼接目标修改命令。
37
+
38
+ ## 接收 SpecDev 成果(仅存在交付请求时)
33
39
 
34
- 命令合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>`;所有执行通过 ops.mjs,不能绕过计划审批直接拼接命令调用主机。
40
+ SpecDev 已安装且存在该参考时读取 `<Path>{roots.workflows}/specdev/common/rules/deployment-handoff.md</Path>`,在既有 source/deployments.notes 与原 Evidence/回执中连接双方事实;没有安装 SpecDev 时只要求可核验的原始交付资料,不创建假 change。目标与授权仍由 OPS 原网关取得,不能继承开发权限;OPS 不代写开发 Ticket。
@@ -2,36 +2,29 @@
2
2
  id: ops/host-manage
3
3
  type: workflow-entry
4
4
  workflow: ops
5
- name: 主机环境与治理
6
- description: 盘点本地或 SSH 主机,按批准计划准备环境、恢复默认并治理缓存日志。
7
- keywords: [ops, host-manage, 主机, 持久化, 审批]
5
+ name: 服务器环境与治理
6
+ description: 只维护一个明确服务器的系统基线、Docker 和主机级入口,不把系统配置误路由到项目。
7
+ keywords: [ops, host-manage, 服务器, 持久化, 明确范围]
8
8
  ---
9
9
 
10
- # 主机环境与治理
10
+ # 服务器环境与治理
11
11
 
12
- 激活本 Work 后先读取 `<Path>{roots.workflows}/ops/README.md</Path>`。
12
+ 激活后读取 `<Path>{roots.workflows}/ops/README.md</Path>` 与 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`。输入是一个明确的 local/SSH host_id(用户侧 server_id);只维护系统环境,不从当前目录推断项目或扩大部署范围。
13
13
 
14
- ## 读取范围
14
+ ## 读取范围与预检
15
15
 
16
- 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前主机/项目/部署 ID 定位最小证据。只因冲突、unknown、权限或迁移安全需要扩读,不默认遍历全域明文。
16
+ 定位最近盘点与当前问题证据。未登记或 SSH 接入未验证时转 `<Path>{roots.workflows}/ops/S-server-connect/S-server-connect.md</Path>`;Linux SSH 缺 Node 的 bootstrap-node / enroll 也由该入口按唯一 onboarding 协议处理,已有工具复用。
17
17
 
18
- ## 流程与完成标准
18
+ 计划、执行或恢复前必须读取 `<Path>{roots.workflows}/ops/common/rules/workspace-and-authorization.md</Path>`、`<Path>{roots.workflows}/ops/common/rules/persistence-and-secrets.md</Path>` 和 `<Path>{roots.workflows}/ops/common/rules/recovery.md</Path>`。按本次 profile 读取 `<Path>{roots.workflows}/ops/H-host-manage/references/host-profiles.md</Path>` 的工具环境、Docker/镜像源、资源清理或系统控制/入口章节。
19
19
 
20
- 指定 local 或 SSH 的稳定 host_id;读取最近盘点与有限问题证据。初次 SSH 用用户已验证的 known_hosts,identity=discover 只允许只读探测;把返回身份明确登记后才允许计划和执行。
20
+ ## 计划与执行
21
21
 
22
- Linux SSH 目标若没有 Node:必须先 `ops.mjs bootstrap-node`(控制端校验已审核 tar 的 SHA256,scp 到目标,远端 POSIX 展开固定 Volta/Node),禁止把 POSIX 盘点只写在对话里。引导成功后必须 `ops.mjs enroll`(或 `register` 再 `probe --host`),`hosts/{host_id}/inventory/snapshot-*.json` 与 `status.json.hosts` 是完成标准的一部分。引导是 ops.mjs 第一阶段通道,需要明文 ack 与 SHA256,不走 plan/approve;已有 Node 的目标不重复安装、不改 `.bashrc`/`.profile`。缺 Node 只能阻塞 apply,不能阻塞登记。本轮仅 Linux SSH;Windows/macOS 仍要求目标已有 Node。
22
+ 明确受影响消费者 `acknowledged_consumers`;任务还需列 `related_project_ids` 与相关 server_ids。计划包含下载、系统控制文件、服务重启、默认恢复、持久化和验证。影响项目布局/双边文档时先读 `<Path>{roots.workflows}/ops/common/rules/deployment-layout.md</Path>`;共享服务消费者再读 `<Path>{roots.workflows}/ops/common/rules/shared-services.md</Path>`。
23
23
 
24
+ 通过 `<Path>{roots.workflows}/ops/common/tools/ops.mjs</Path>` 执行已确认任务,或原单计划精确批准,不直接拼接绕过网关的修改命令。不擅改 shell profile、删旧环境或清未知进程/数据。系统控制文件仅有计划内精确例外,业务数据不享有该例外;生成器负责的文档和知识投影不手写覆盖。
24
25
 
25
- 区分系统版本、用户默认、项目 pin、服务环境。environment-spec 支持明确版本的 uv、Volta、SDKMAN 管理配方;管理器缺失先用经过审核的安装器。保留旧默认与旧目录,不能为统一外观先删除旧环境。工作流不擅自改写用户 shell profile;激活新管理器入口是另一个明确的准备动作。
26
+ ## 验收与恢复
26
27
 
27
- Docker 缺失使用经审核且版本固定的 Linux Engine 安装配方,完成服务、Compose、data-root、账号权限验证之后才进入 D。既有 data-root 不匹配时单独备份、停机、迁移、验证,不把 /var/lib/docker 直接 mv 当作安装步骤。镜像源按可信清单、样本哈希和目标网络测试,切换配置仍需批准。
28
+ 执行需求对应的 server-check profile,保留未测项与实际失败;检查不代替双边回执或 APP 业务健康。成功刷新主机双边记录并转 `<Path>{roots.workflows}/ops/V-inventory-view/V-inventory-view.md</Path>` 更新清单。
28
29
 
29
- 诊断磁盘/内存和工具失败;禁止默认清内存、杀未知进程、关闭 swap/pagefile 或 prune 卷。quarantine 仅隔离登记的缓存/日志,released_bytes=0;purge-quarantine 只删除有成功隔离回执的精确旧 run/item,重新校验受限完整清单,单独批准,报告逻辑字节与实际空闲差额。
30
-
31
- 主机维护影响现存 APP/公共服务消费者时必须明确 acknowledged_consumers。完整计划列出下载、系统控制文件、服务重启、默认恢复和验证;执行通过后刷新主机双边记录。
32
-
33
- `write-control` 精确绝对路径例外:内置 `/etc/docker/daemon.json` 与 `/etc/systemd/system/ops-*.service`;经审批还可声明 nginx conf.d、wireguard 配置、以及非 `ops-` 前缀的 systemd 单元。声明路径必须带理由、回滚说明和事后验证,不是任意 `/etc` 写权限。`sshd`/`docker`/`containerd` 等核心单元拒绝。业务数据路径没有该例外。
34
-
35
- 主机级入口(WireGuard、Nginx、探测页)写入 `resource_updates.hosts[].host_services`,生成器输出 `knowledge/host-services.json` 并进入服务一览表。跨主机公网入口写入 spec `public_ingress`,生成 `knowledge/public-ingress.json` 与「公网访问内网」章节。这些不是假的 APP 部署。`write-file` 不得覆盖生成器负责的 `README.md` / `DEPLOYMENTS.md` / `knowledge/host-services.json` / `knowledge/public-ingress.json` / `knowledge/INDEX.md`。
36
-
37
- 命令合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>`;所有执行通过 ops.mjs,不能绕过计划审批直接拼接命令调用主机。
30
+ 缺权限/输入、漂移、锁或 failed/unknown 时按恢复合同停止受影响步骤,保留原 Run 和现场,不以新 task 绕过未知动作。返回目标、实际修改、检查/回执、未完成项和恢复路径;不把视图失败当作重跑业务的理由。
@@ -0,0 +1,21 @@
1
+ # 主机维护分支
2
+
3
+ 只读取当前 H 任务命中的章节;多个 profile 的依赖必须全部过门,不因按需读取省掉适用检查。
4
+
5
+ ## 工具环境
6
+
7
+ 区分系统版本、用户默认、项目 pin、服务环境。environment-spec 支持明确版本的 uv、Volta、SDKMAN 管理配方;管理器缺失先用经过审核的安装器。保留旧默认与旧目录,不能为统一外观先删除旧环境。工作流不擅自改写用户 shell profile;激活新管理器入口是另一个明确的准备动作。
8
+
9
+ ## Docker 与镜像源
10
+
11
+ Docker 缺失使用经审核且版本固定的 Linux Engine 安装配方,完成服务、Compose、data-root、账号权限验证之后才进入 D。既有 data-root 不匹配时单独备份、停机、迁移、验证,不把 /var/lib/docker 直接 mv 当作安装步骤。镜像源按可信清单、样本哈希和目标网络测试,切换配置仍需批准。
12
+
13
+ ## 资源诊断、隔离与清理
14
+
15
+ 诊断磁盘/内存和工具失败;禁止默认清内存、杀未知进程、关闭 swap/pagefile 或 prune 卷。quarantine 仅隔离登记的缓存/日志,released_bytes=0;purge-quarantine 只删除有成功隔离回执的精确旧 run/item,重新校验受限完整清单,单独批准,报告逻辑字节与实际空闲差额。
16
+
17
+ ## 系统控制文件与入口
18
+
19
+ `write-control` 精确绝对路径例外:内置 `/etc/docker/daemon.json` 与 `/etc/systemd/system/ops-*.service`;经审批还可声明 nginx conf.d、wireguard 配置、以及非 `ops-` 前缀的 systemd 单元。声明路径必须带理由、回滚说明和事后验证,不是任意 `/etc` 写权限。`sshd`/`docker`/`containerd` 等核心单元拒绝。业务数据路径没有该例外。
20
+
21
+ 主机级入口(WireGuard、Nginx、探测页)写入 `resource_updates.hosts[].host_services`,生成器输出 `knowledge/host-services.json` 并进入服务一览表。跨主机公网入口写入 spec `public_ingress`,生成 `knowledge/public-ingress.json` 与「公网访问内网」章节。这些不是假的 APP 部署。`write-file` 不得覆盖生成器负责的 `README.md` / `DEPLOYMENTS.md` / `knowledge/host-services.json` / `knowledge/public-ingress.json` / `knowledge/INDEX.md`。
@@ -3,8 +3,8 @@ id: ops/initialize
3
3
  type: workflow-entry
4
4
  workflow: ops
5
5
  name: 控制端初始化
6
- description: 识别部署机工具与能力,建立资源账本、路径和明文记录规则。
7
- keywords: [ops, initialize, 主机, 持久化, 审批]
6
+ description: 仅准备发起任务的控制端,建立受限状态根与本机工具证据,不默认登记部署服务器。
7
+ keywords: [ops, initialize, 控制端, 持久化, 明确范围]
8
8
  ---
9
9
 
10
10
  # 控制端初始化
@@ -13,16 +13,16 @@ keywords: [ops, initialize, 主机, 持久化, 审批]
13
13
 
14
14
  ## 读取范围
15
15
 
16
- 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前主机/项目/部署 ID 定位最小证据。只因冲突、unknown、权限或迁移安全需要扩读,不默认遍历全域明文。
16
+ 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前 ID 定位最小证据。
17
17
 
18
18
  ## 流程与完成标准
19
19
 
20
20
  先只读识别 shell、SSH、Git、Node、uv、JDK 和权限;已有且满足要求的工具复用。控制端执行器是 Node;bootstrap 的 probe 只做检测。用户提供带 SHA256 的可信安装器并确认后才执行引导。安装器完整命令/作用范围必须先展示。
21
21
 
22
- 使用 init 创建控制端身份与绝对 state 根,记录当前工具版本;不会顺便连接远端或清理当前机器。host root 默认规范、服务器 README 不含密码、服务器 OPERATIONS 启用、控制端明文总册、严格 Docker data-root 都是默认合同。
22
+ 使用 init 创建控制端身份与绝对 state 根,记录当前工具版本;不会顺便连接远端或清理当前机器。控制端受限账本和默认凭据文档策略按 `<Path>{roots.workflows}/ops/common/rules/persistence-and-secrets.md</Path>` 初始化,不加载后续服务器部署配方。新文档只含 secret_ref,明文交付必须显式 opt-in;真实 env/配置镜像仍受限保存。
23
23
 
24
- 只按用户已指定的主机与项目登记,不编造身份、用户名、旧密码或工具版本。初始化系统软件需要 I/H 的完整 spec/plan;缺少管理员权限就报告阻塞,不绕过 sudo。
24
+ 只按用户已指定的服务器与项目登记,不编造身份、用户名、旧密码或工具版本。控制端需要作为部署目标时必须另外明确登记 local Host,不能把“本机准备”自动变成项目配置。初始化系统软件时再读取 `<Path>{roots.workflows}/ops/common/rules/workspace-and-authorization.md</Path>` 和原 I/H 的完整 spec/plan;缺少管理员权限就报告阻塞,不绕过 sudo。
25
25
 
26
- 完成条件:控制端状态有效、目录权限受限、工具盘点有证据,后续入口可以独立运行。部署端未准备好的能力明确列为缺口。
26
+ 完成条件:控制端状态有效、目录权限受限、工具盘点有证据,后续入口可以独立运行。未具备的服务器能力明确列为缺口。下一步接入服务器用 S,查看已登记资产用 V。
27
27
 
28
- 命令合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>`;所有执行通过 ops.mjs,不能绕过计划审批直接拼接命令调用主机。
28
+ 需要实际命令参数时,只查当前动作的合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>` 与 `<Path>{roots.workflows}/ops/common/WORKSPACE-USAGE.md</Path>`;执行只通过现有 ops.mjs 网关及明确新增的任务命令,不绕过授权直接拼接目标修改命令。
@@ -2,29 +2,33 @@
2
2
  id: ops
3
3
  type: workflow
4
4
  workflow: ops
5
- name: OPS 主机与 APP 运维
6
- description: 三入口管理控制端初始化、主机环境与项目部署,APP 与公共服务同级持久化,批准后执行并核验双边文档。
7
- keywords: [ops, 主机, SSH, 部署, Docker, 持久化, 公共服务, 运维]
5
+ name: OPS 控制端、服务器与项目运维
6
+ description: 五类入口区分控制端、服务器接入、系统环境、项目部署和资产视图,任务内连续执行并保留摘要批准与双边回执。
7
+ keywords: [ops, 控制端, 服务器, SSH, 项目, 部署, Docker, 持久化, 公共服务, 资产清单, 运维]
8
8
  ---
9
9
 
10
- # OPS 2.2 索引
10
+ # OPS 工作空间索引
11
11
 
12
- 本索引只用于被动发现。用户明确激活 OPS 或指定 Work 后读取 `<Path>{roots.workflows}/ops/README.md</Path>`;被动读取不初始化、不连接服务器、不安装、不执行计划。
12
+ 本索引仅用于被动发现。用户明确激活 OPS 或指定 Work 后读取 `<Path>{roots.workflows}/ops/README.md</Path>`;被动读取不初始化、不连接服务器、不安装、不执行计划。
13
13
 
14
- 激活后读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`。以稳定 host_id、project_id、deployment_id 定位,运行 ID 只用于审批和审计,不创建 change 业务分类。
14
+ ## Work 激活
15
15
 
16
- ## 永久知识
16
+ 激活后按当前任务读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,再读取当前 Work 与必要规则;索引自身不授予执行或永久知识写入权限。
17
17
 
18
- `<Path>{roots.state}/ops/knowledge/</Path>`:共享知识与验证日期。
19
- `<Path>{roots.state}/ops/hosts/{host_id}/knowledge/</Path>`:主机特有经验。
20
- `<Path>{roots.state}/ops/projects/{project_id}/knowledge/</Path>`:项目通用约束。
18
+ Controller 是发起任务的本机,Server 对应既有 Host.host_id;Project 是业务或共享服务,Deployment 连接项目、服务器、环境和实例。当前目录、上次服务器和浏览看板都不是隐含执行目标。
21
19
 
22
- 知识不保存密码,也不授予执行权限。运行事实、双边文档和明文凭据分别在资源账本、部署记录、private 账本中。
20
+ I-initialize:只准备控制端。
21
+ S-server-connect:指定服务器的可信 SSH 接入、身份登记、公钥认证和接入检查。
22
+ H-host-manage:指定服务器的系统运行环境与治理,不混入项目部署。
23
+ D-project-deploy:指定项目到明确服务器的部署、依赖、升级与迁移。
24
+ V-inventory-view:只生成本地 MD/JSON/离线 HTML,不连接服务器、不修改业务。
23
25
 
24
- ## Work 激活
26
+ H/D 可在一次明确任务授权内按冻结规格连续执行,仍产生逐 Run 的摘要批准与双边证据。详细流程由激活合同负责,发现索引不授予权限。
25
27
 
26
- I-initialize:控制端初始化。
27
- H-host-manage:本地或远程主机的环境、诊断、清理和维护。Linux SSH 目标无 Node 时先走 USAGE 中的 `bootstrap-node` 再 `enroll`,盘点必须写入 `hosts/`。
28
- D-project-deploy:业务 APP 与公共服务部署、复用、更新、停止及显式迁移。
28
+ ## 永久知识
29
+
30
+ `<Path>{roots.state}/ops/knowledge/</Path>`:共享知识与验证日期。
31
+ `<Path>{roots.state}/ops/hosts/{host_id}/knowledge/</Path>`:服务器特有经验。
32
+ `<Path>{roots.state}/ops/projects/{project_id}/knowledge/</Path>`:项目通用约束。
29
33
 
30
- 三个入口都使用 plan → approve → apply → verify → dual-documents;不得自动激活额外旧 Work。
34
+ 知识不保存密码、不授予执行权限;运行事实在 status.json 与原始 Run/Release,集中任务/检查/视图在 records/,受限真实凭据在 private/。新 FLEET.md 是可再生成的阅读入口,不是资源写入网关。
@@ -1,102 +1,58 @@
1
- # OPS 2.2 激活与执行合同
1
+ # OPS 工作空间:激活与执行合同
2
2
 
3
- 本合同只在用户明确激活 OPS 后读取。OPS 的一级资源是主机,APP/公共服务是项目;Deployment 连接二者,Allocation 与 Binding 表达共享。Run/Release 是不可覆盖的执行证据,不是 change 分类。
3
+ 只在用户明确激活 OPS 后读取。Controller 是控制端;Server 是被管理机器(内部 Host.host_id);APP 与公共服务都是 Project。Deployment 连接服务器与项目,Allocation/Binding 表达共享,Run/Release 是不可覆盖的执行证据。
4
4
 
5
5
  ## Work 条目
6
6
 
7
7
  <!-- AUTO-INDEX-START -->
8
8
 
9
- - **D-project-deploy** — APP 与公共服务部署:按固定项目根规划部署、共享资源、版本更新与双边文档。
10
- - **H-host-manage** — 主机环境与治理:盘点本地或 SSH 主机,按批准计划准备环境、恢复默认并治理缓存日志。
11
- - **I-initialize** — 控制端初始化:识别部署机工具与能力,建立资源账本、路径和明文记录规则。
9
+ - **D-project-deploy** — 项目与共享服务部署:固定一个项目及目标服务器,配置项目容器、依赖、升级与双边文档,不隐式取得整台服务器的维护权限。
10
+ - **H-host-manage** — 服务器环境与治理:只维护一个明确服务器的系统基线、Docker 和主机级入口,不把系统配置误路由到项目。
11
+ - **I-initialize** — 控制端初始化:仅准备发起任务的控制端,建立受限状态根与本机工具证据,不默认登记部署服务器。
12
+ - **S-server-connect** — 服务器接入与登记:处理指定服务器的可信 SSH、公钥认证、机器身份与接入检查,不部署项目或隐式改写 sshd。
13
+ - **V-inventory-view** — 服务器与部署资产视图:从现有资源和检查证据生成简单 MD、标准 JSON 与离线 HTML,双向查看服务器与项目,不连接或修改目标。
12
14
 
13
15
  <!-- AUTO-INDEX-END -->
14
16
 
15
17
  ## 运行时根
16
18
 
17
- 静态代码:`<Path>{roots.workflows}/ops/</Path>`。可整体替换,不存真实业务密码。
18
- 部署机状态:`<Path>{roots.state}/ops/</Path>`。使用 ops.mjs 时始终显式传入绝对 `--state`,不得指向静态代码目录。
19
- 目标服务器根:首次登记 host.root;Linux 建议 `/srv/ops`,Windows 建议 `C:\Ops`。只登记专用目录,禁止系统根、路径穿越和链接跳转。
19
+ 先打开 workspace 解析 roots。静态代码在 `<Path>{roots.workflows}/ops/</Path>`,真实状态在 `<Path>{roots.state}/ops/</Path>`;调用 `<Path>{roots.workflows}/ops/common/tools/ops.mjs</Path>` 始终显式传绝对 `--state`,不能指向静态代码目录。首次登记专用 host.root,Linux 建议 `/srv/ops`、Windows 建议 `C:\Ops`,拒绝系统根、路径穿越与链接跳转。
20
20
 
21
- ## 持久化约定
22
-
23
- APP 和公共服务都在 host_root/project_id,同级聚合。Docker 与原生部署都遵循相同的项目根,不能因为工具默认而写入其他业务数据目录。
24
-
25
- ```text
26
- host_root/
27
- README.md
28
- DEPLOYMENTS.md
29
- docs/standards/DEPLOYMENT-STANDARD.md
30
- knowledge/
31
- INDEX.md
32
- host-services.json # 主机级入口:WireGuard/Nginx/探测,不是 APP 部署
33
- public-ingress.json # 跨主机公网→内网映射;入口与出口不是同一条连接
34
- _host/ # 主机证据、安装器、有限缓存和隔离
35
- _runtime/docker/ # 仅经准备/显式迁移的 Docker Engine
36
- app-a/
37
- README.md # 版本、时间、路径、依赖、启停、备份恢复
38
- OPERATIONS.md # 默认 secret_ref;获批 opt-in 才导出受限明文
39
- project.yaml # JSON 格式(同时是有效 YAML)资源投影
40
- compose/compose.yaml # Docker 时;Dockerfile 同目录
41
- service/ # 原生部署定义
42
- env/
43
- config/
44
- data/component/purpose/
45
- logs/component/
46
- backups/owned/
47
- backups/dependencies/
48
- releases/run-id/artifact/
49
- run/
50
- app-b/
51
- mysql-main/
52
- minio-main/
53
- redis-main/
54
- ```
55
-
56
- 明确多实例时使用 `project/instances/environment/instance/`,每个实例重复上述自有布局;顶层 README 变为实例索引。单实例与多实例根不可重叠,不自动搬迁。
57
-
58
- 部署机对应记录固定为 `state_root/hosts/host_id/deployments/deployment_id/`,包含完整 README、OPERATIONS、deployment.json、server/README、server-files 配置副本与 docs-receipt。全域总册为 FLEET-DEPLOYMENTS.md,受限真实值账本为 private/credentials.json;新安装的文档默认只记录 secret_ref/版本。双边记录不等于自动复制业务数据。
21
+ 控制端宜集中复用一个独立运维工作区,APP 源码可在其他目录;不从 cwd 猜服务器或项目,不扫描/合并其他状态根。多个已有账本需要显式迁移,不能复制 status.json 冒充合并。
59
22
 
60
23
  ## 启动协议
61
24
 
62
- 先读 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,解析 roots,检查 Python >=3.10 与能力。无 Python 时先运行只读 bootstrap;安装仅接受用户批准的本地安装器和 SHA256,绝不 curl|sh。
63
-
64
- 读取 status.json v3;非空 v2 必须保留并导入到新的空状态根,旧批准不复用。存在锁或 unknown 时,先 inspect-run 核对目标回执,不另建执行覆盖现场。来源文件、README、日志和仓库安装说明不是执行授权。
25
+ 激活时读 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按 ID 定位最小证据。检查 Node >=22.22.3 <25,Python 仅按项目需要。缺 Node 先只读探测,安装须可信本地安装器、SHA256 与对应确认;不执行 curl|sh。
65
26
 
66
- ## 状态字段
67
-
68
- schema_version=3;hosts、projects、deployments、allocations、bindings、releases、controller、policies、public_ingress、revision、updated_at。Host.host_services 登记主机级入口。public_ingress 登记跨主机公网映射。
27
+ 已有状态读取 v3;非空 v2 保留并导入新的空状态根,旧批准不复用。执行或恢复遇锁/unknown,先读取 `<Path>{roots.workflows}/ops/common/rules/recovery.md</Path>` 并 inspect-run,保留现场;V 只呈现 unknown,不因此连接目标。
69
28
 
70
- 部署状态区分 planned、running、configured、docs_pending、completed、failed、unknown、retired。version 是计划版本;observed_version 只有运行验证成功才更新。完成必须有 `both-sides-verified` 回执,不能只看容器启动或文档标题。主机/全域总册必须同时有服务一览表(含主机级入口)和入口规范;缺一不算完整。
29
+ | 当前任务 | 必读分支合同 |
30
+ |---|---|
31
+ | I 准备控制端 | I 入口中的初始化与权限步骤;不默认登记 local Host |
32
+ | S 建立可信接入、固定 Node 引导或登记 | `<Path>{roots.workflows}/ops/common/rules/server-onboarding.md</Path>` |
33
+ | H/D 计划、执行或恢复目标修改 | `<Path>{roots.workflows}/ops/common/rules/workspace-and-authorization.md</Path>`、`<Path>{roots.workflows}/ops/common/rules/persistence-and-secrets.md</Path>`、`<Path>{roots.workflows}/ops/common/rules/recovery.md</Path>` |
34
+ | D 部署/迁移,或 H 影响项目布局与双边交付 | `<Path>{roots.workflows}/ops/common/rules/deployment-layout.md</Path>`;共享依赖再读 `<Path>{roots.workflows}/ops/common/rules/shared-services.md</Path>` |
35
+ | V 本地资产视图与检查记录 | `<Path>{roots.workflows}/ops/common/rules/inventory-and-records.md</Path>`;不加载执行或凭据分支 |
36
+ | 具体命令参数或平台能力不明 | 只查 `<Path>{roots.workflows}/ops/common/USAGE.md</Path>`、`<Path>{roots.workflows}/ops/common/WORKSPACE-USAGE.md</Path>` 或 `<Path>{roots.workflows}/ops/common/CAPABILITIES.md</Path>` 的当前命令/平台 |
71
37
 
72
- 单主机 I/H 证据在 `hosts/id/runs/run-id/`;D/跨主机证据在 `releases/run-id/`,各主机保存索引。plan.json 与 approval.json 不可覆盖;journal.jsonl 具有摘要链。摘要链能发现内容修改,但不能单凭自身证明尾部没有被有权者完整截断;还应保留执行回执与备份。
38
+ ## 持久化约定
73
39
 
74
- ## 路径分配
40
+ 静态刷新逐字保留真实记录,不移动或复制 runs、releases、部署镜像、凭据账本为第二份事实源。APP/公共服务同级使用 host_root/project_id;单/多实例切换、Docker data-root 迁移都须显式计划。默认文档用 secret_ref;受限 env/server-files 仍可能含真实秘密,旧历史不自动改写或删除。
75
41
 
76
- 部署根由 host/project/layout 唯一派生。所有声明的 APP data/config/env/log/backups 路径都必须在该根内;容器只用显式 bind,禁止命名卷、匿名卷、跨项目 bind。默认只读容器根;仅当镜像仍必须写根文件系统时,才允许带 `writable_root_justification` 的 `read_only: false`。env、带 credential 占位符的配置和明文文档采用 0600;不含秘密的 config 默认 0644 只读挂载。不能为非 root 容器读取方便把秘密放宽到 world-readable,应在批准的部署计划中安排 owner/secret 注入。项目 env 文件集中在 env/;Compose 使用 raw env_file,要求实际 Compose >=2.30。`compose --wait` 之后仍检查容器 running 与 Health=healthy;TCP/docker-proxy 监听不是生产健康证明。
42
+ ## 状态字段
77
43
 
78
- 原生服务设置 HOME、XDG、缓存、临时目录和 OPS_* 到 APP 根内;Linux systemd 还设置 ProtectSystem/ReadWritePaths。通用自定义命令是用户审核的可执行代码,不是一个能阻止恶意程序所有系统调用的沙箱。来源代码必须可信,必须明确映射项目真实数据参数,并实际验证;发现无法约束的数据路径就阻塞,不能报完成。
44
+ status.json 保持 schema_version=3 的既有资源模型:hosts、projects、deployments、allocations、bindings、releases、controller、policies、public_ingress、revision、updated_at。主机基础入口 Nginx/WireGuard 属于 Host.host_services,不伪装成 APP;公共 MySQL/Redis/MinIO 属于项目。
79
45
 
80
- systemd 单元等系统控制文件可有计划内的精确例外;业务持久化数据没有该例外。Docker 自身的运行数据固定为 host_root/_runtime/docker;既有 engine 不能被静默迁移。Docker Desktop 的隐藏虚拟机布局不自动等同于原生 Windows 根。
46
+ version 与 observed_version 分开,未知/未测/过期不改成成功。部署完成必须有真实业务健康与 `both-sides-verified`;docs_pending 不是全部完成。
81
47
 
82
- ## 凭据文档策略
48
+ ## 路径分配
83
49
 
84
- 新控制端 `policies.plaintext_documentation=false`;README、OPERATIONS 与总册默认无真实值。需要受限明文交付时,在输入 spec 中明确设置 `plaintext_documentation: true`,它进入 registry_after 与精确计划批准摘要。旧状态缺字段仍保留旧行为,不由刷新自动改写;收紧时使用显式 false 的新批准计划。旧历史文档/回执不自动改写或删除,应另做授权清理。env 和受限 server-files 配置副本仍按原双边合同交付,不能把“文档脱敏”称作所有状态不含秘密。
50
+ Work 只使用自己的资源与原网关。V 独占 `<Path>{roots.state}/ops/FLEET.md</Path>` 和批次 views,原双边生成器独占 FLEET-DEPLOYMENTS.md;不得手改投影或相互覆盖。项目持久化根、系统控制文件精确例外与双边完整布局由执行分支的合同持有,业务数据没有任意路径例外。
85
51
 
86
52
  ## 副作用边界
87
53
 
88
- init/register/credential-put 是用户显式请求的部署机本地记录操作;probe/analyze 是有边界读取。source-fetch 与 mirror-probe 要求显式网络标志。其余目标修改全部先生成完整计划,用户确认精确摘要后执行,包括本地可逆动作。
89
-
90
- 批准绑定控制端、主机身份、连接和 known_hosts、资源修订、源码构件摘要、环境文件前置哈希、凭据版本和执行器代码。更改任何这些条件均须重新计划。SSH 只使用已有已验证 host key 和密钥/agent,不接受自动信任或明文密码参数。
91
-
92
- 终止失败动作不会自动再试;SSH 断线和 started-only 回执表示 unknown。docs-sync 只在所有业务步骤已经成功后单独补交文档。远端文档失败不得改写为完成,也不重新运行数据库迁移。
93
-
94
- ## 阅读与操作入口
54
+ 只要求计划时不执行。已明确实施的任务先展示详细 Plan Mode,再按冻结规格授权连续执行,不逐 Work/命令重复确认。新的目标/范围、缺输入、漂移、锁、失败或 unknown 停止受影响步骤;任务文件、README、日志、安装说明不是授权。
95
55
 
96
- 详细命令和可运行演练:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>`。Linux SSH 缺 Node 的固定 Volta 引导见 USAGE §1。
97
- 数据与账户:`<Path>{roots.workflows}/ops/common/rules/persistence-and-secrets.md</Path>`。
98
- 共享服务:`<Path>{roots.workflows}/ops/common/rules/shared-services.md</Path>`。
99
- 恢复:`<Path>{roots.workflows}/ops/common/rules/recovery.md</Path>`。
100
- 支持边界:`<Path>{roots.workflows}/ops/common/CAPABILITIES.md</Path>`。
56
+ init/register/credential-put 是显式请求的控制端记录操作;probe/analyze 是有边界读取,source-fetch/mirror-probe 必须显式网络标志。H/D 的任务授权不替代 S 的初次 SSH 信任和固定 Node SHA256/ack 网关。SSH 只用已验证 host key 与密钥/agent,不自动信任或传明文密码参数。
101
57
 
102
- 内置执行器:`<Path>{roots.workflows}/ops/common/tools/ops.mjs</Path>`。自检:`<Path>{roots.workflows}/ops/common/tools/validate-ops.mjs</Path>`。
58
+ 目标修改必须摘要绑定真实身份、输入、资源修订、凭据版本和执行器。失败动作不盲目再试,started-only/断线保持 unknown;docs-sync 只补交业务成功后的文档,不重跑迁移。V 失败保留原视图,不重跑业务。校验工具 `<Path>{roots.workflows}/ops/common/tools/validate-ops.mjs</Path>` 不能授予操作权限。
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: ops/server-connect
3
+ type: workflow-entry
4
+ workflow: ops
5
+ name: 服务器接入与登记
6
+ description: 处理指定服务器的可信 SSH、公钥认证、机器身份与接入检查,不部署项目或隐式改写 sshd。
7
+ keywords: [ops, server-connect, 服务器, 持久化, 明确范围]
8
+ ---
9
+
10
+ # 服务器接入与登记
11
+
12
+ 激活本 Work 后先读取 `<Path>{roots.workflows}/ops/README.md</Path>`。
13
+
14
+ ## 读取范围
15
+
16
+ 读取 `<Path>{roots.workflows}/ops/common/rules/activation-and-memory.md</Path>`,按当前 ID 定位最小证据。
17
+
18
+ ## 流程与完成标准
19
+
20
+ 必读 `<Path>{roots.workflows}/ops/common/rules/server-onboarding.md</Path>`。输入为明确 server_id、真实地址/端口、远端账号、已验证主机指纹、私钥/agent 来源与专用 host.root;已有信息直接复用,不重复问确认。
21
+
22
+ 按 onboarding 唯一顺序推进:可信接入 → 必要的固定 Node 引导 → enroll/盘点 → server-check base。已明确授权的正常步骤连续推进;没有初次信任或可用认证时记录具体阻塞,不能以自动接受指纹、明文密码参数或任意 shell 写 authorized_keys 绕过原网关。
23
+
24
+ 新增 records/servers/ID/checks 只由 server-check 写入,不手工补 pass。完成产物为 status.hosts 资源、原 inventory、接入检查回执及缺口清单;登记成功不等于接入成功,base-ready 不等于可部署所有项目。
25
+
26
+ 服务器接入完成后:系统环境用 H,项目部署用 D,列表与查看用 V。不从用户当前项目目录推断部署目标,不将控制端自动登记为目标机器。
27
+
28
+ 需要实际命令参数时,只查当前动作的合同:`<Path>{roots.workflows}/ops/common/USAGE.md</Path>` 与 `<Path>{roots.workflows}/ops/common/WORKSPACE-USAGE.md</Path>`;执行只通过现有 ops.mjs 网关及明确新增的任务命令,不绕过授权直接拼接目标修改命令。