frontend-project-context 1.7.0 → 1.8.0
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.
- package/CHANGELOG.md +9 -0
- package/README.md +16 -9
- package/UPGRADING.md +8 -0
- package/docs/08-INSTALLATION-AND-DISTRIBUTION.md +23 -6
- package/docs/24-A130-REAL-HOST-TARGET-PROJECT-COMPARISON.md +1 -1
- package/docs/26-A130-QUALITY-CLOSURE-AND-ADAPTIVE-DELIVERY-REPAIR-DESIGN.md +1 -1
- package/docs/27-TEAM-SHARED-CONTEXT-DIRECTION-DISCUSSION.md +30 -0
- package/docs/28-REAL-PROJECT-ONBOARDING-CLOSURE-DESIGN.md +534 -0
- package/docs/AI-PROJECT-INITIALIZATION.md +89 -0
- package/docs/README.md +12 -0
- package/docs/USER-AND-AI-OPERATION-MANUAL.md +17 -13
- package/examples/README.md +2 -2
- package/examples/package.json +1 -1
- package/migration-manifest.json +19 -7
- package/package.json +2 -2
- package/schemas/capabilities.schema.json +23 -8
- package/schemas/evidence-bundle.schema.json +1 -1
- package/schemas/initialization-instruction.schema.json +60 -0
- package/schemas/migration-manifest.schema.json +3 -3
- package/schemas/migration-plan.schema.json +2 -2
- package/schemas/project-status.schema.json +5 -4
- package/schemas/upgrade-assessment.schema.json +2 -2
- package/schemas/upgrade-result-bundle.schema.json +1 -1
- package/src/project-context/ai-entry.mjs +8 -6
- package/src/project-context/capabilities.mjs +14 -0
- package/src/project-context/cli.mjs +15 -0
- package/src/project-context/contract-schema.mjs +1 -1
- package/src/project-context/exchange-schema.mjs +4 -4
- package/src/project-context/initialization-instruction.mjs +42 -0
- package/src/project-context/migration-manifest.mjs +3 -3
- package/src/project-context/project-status.mjs +14 -3
- package/src/project-context/project-store.mjs +27 -2
- package/src/project-context/upgrade-schema.mjs +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Frontend Project Context 操作手册
|
|
2
2
|
|
|
3
|
-
> 适用版本:`frontend-project-context@1.
|
|
3
|
+
> 适用版本:`frontend-project-context@1.8.0` 本地实现
|
|
4
4
|
>
|
|
5
5
|
> 适用对象:项目维护者、开发者、使用 Codex / Claude / Cursor / 其他 Coding Agent 的团队,以及集成该 CLI 的 AI Host Agent。
|
|
6
6
|
>
|
|
@@ -101,7 +101,7 @@ AI 可以提取事实、整理文字、去重、建议 scope/override、生成 p
|
|
|
101
101
|
固定为项目开发依赖,使本地与 CI 使用同一版本:
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
npm install --save-dev frontend-project-context@1.
|
|
104
|
+
npm install --save-dev frontend-project-context@1.8.0
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
建议在 `package.json` 中提供稳定入口:
|
|
@@ -121,15 +121,16 @@ npm install --save-dev frontend-project-context@1.7.0
|
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
123
|
npm exec --offline -- project-context --help
|
|
124
|
+
npm exec --offline -- project-context instructions --project . --prompt
|
|
124
125
|
npm exec --offline -- project-context capabilities --project . --json
|
|
125
126
|
npm exec --offline -- project-context status --project . --json
|
|
126
127
|
```
|
|
127
128
|
|
|
128
129
|
所有正式命令都通过 `npm exec --offline -- project-context` 或上面的项目脚本调用。`--offline` 会在本地依赖缺失时失败封闭,不能退回 registry 下载无关的同名 `project-context` 包。持久初始化必须发生在精确版本安装之后,避免后续补装依赖改变已登记的 `package.json` source digest。
|
|
129
130
|
|
|
130
|
-
`capabilities`
|
|
131
|
+
`instructions` 和 `capabilities` 在项目未初始化时也可用。初始化的唯一规范正文是 [AI-PROJECT-INITIALIZATION.md](./AI-PROJECT-INITIALIZATION.md);本手册只引用它,不另行定义执行顺序。
|
|
131
132
|
|
|
132
|
-
`1.
|
|
133
|
+
`1.8.0` 的 AI Entry renderer 4 固定离线项目本地 CLI 入口,并要求 clean 状态的真实任务先运行 task/path `context`、消费实际命中的 item IDs、scope 与 read targets。既有 renderer 1/2/3 不会被静默覆盖,升级后会报告 stale,必须先预览并获得明确写入授权再 republish。
|
|
133
134
|
|
|
134
135
|
### 4.3 全新初始化不是普通升级
|
|
135
136
|
|
|
@@ -143,9 +144,11 @@ npm exec --offline -- project-context status --project . --json
|
|
|
143
144
|
|
|
144
145
|
工具没有自动 reset 命令,也不会把删除 store、翻译批准规则或接受 source drift 伪装成普通升级。
|
|
145
146
|
|
|
146
|
-
## 5.
|
|
147
|
+
## 5. 唯一初始化指令与底层原语参考
|
|
147
148
|
|
|
148
|
-
|
|
149
|
+
首次接入只遵循 [AI-PROJECT-INITIALIZATION.md](./AI-PROJECT-INITIALIZATION.md)。下面保留的是单个 CLI 原语的参数参考,不是可由 Host 自行拼装的第二套初始化流程;语义审查、执行顺序、临时工件清理和完成门均以包内唯一指令为准。
|
|
150
|
+
|
|
151
|
+
### 底层参考:setup 只读 preview
|
|
149
152
|
|
|
150
153
|
```bash
|
|
151
154
|
npm exec --offline -- project-context setup \
|
|
@@ -165,7 +168,7 @@ npm exec --offline -- project-context setup \
|
|
|
165
168
|
|
|
166
169
|
此时项目文件应保持不变。
|
|
167
170
|
|
|
168
|
-
###
|
|
171
|
+
### 底层参考:setup 的显式 bootstrap 写入
|
|
169
172
|
|
|
170
173
|
确认项目 ID、名称和 proposal 路径后执行:
|
|
171
174
|
|
|
@@ -181,7 +184,7 @@ npm exec --offline -- project-context setup \
|
|
|
181
184
|
|
|
182
185
|
`setup --write` 只代表允许创建三个 store 和一份 create-only proposal,**不代表批准 proposal,也不代表允许生成 AGENTS/Ruler 投影**。
|
|
183
186
|
|
|
184
|
-
###
|
|
187
|
+
### 底层参考:读取 work unit
|
|
185
188
|
|
|
186
189
|
AI 应:
|
|
187
190
|
|
|
@@ -192,7 +195,7 @@ AI 应:
|
|
|
192
195
|
5. 需要额外来源时,先说明原因并把它列为 source 候选;
|
|
193
196
|
6. 不以“代码存在”推导出“团队长期 policy”。
|
|
194
197
|
|
|
195
|
-
###
|
|
198
|
+
### 底层参考:补充来源和候选合同项
|
|
196
199
|
|
|
197
200
|
支持的来源类型:
|
|
198
201
|
|
|
@@ -241,7 +244,7 @@ scope 只有:
|
|
|
241
244
|
- `path-prefix`:指定目录及其后代;
|
|
242
245
|
- `file`:单个文件。
|
|
243
246
|
|
|
244
|
-
###
|
|
247
|
+
### 底层参考:审查视图字段
|
|
245
248
|
|
|
246
249
|
AI 必须先展示:
|
|
247
250
|
|
|
@@ -272,7 +275,7 @@ AI 必须先展示:
|
|
|
272
275
|
应该没问题。
|
|
273
276
|
```
|
|
274
277
|
|
|
275
|
-
###
|
|
278
|
+
### 底层参考:批准精确 ID
|
|
276
279
|
|
|
277
280
|
```bash
|
|
278
281
|
npm exec --offline -- project-context approve \
|
|
@@ -284,7 +287,7 @@ npm exec --offline -- project-context approve \
|
|
|
284
287
|
|
|
285
288
|
先看 preview,确认无误后才加 `--write`。一份 proposal 中未被 `--ids` 点名的 item 不会自动获得批准。
|
|
286
289
|
|
|
287
|
-
###
|
|
290
|
+
### 底层参考:生成上下文和投影
|
|
288
291
|
|
|
289
292
|
为目标路径生成临时上下文:
|
|
290
293
|
|
|
@@ -319,7 +322,7 @@ npm exec --offline -- project-context publish \
|
|
|
319
322
|
|
|
320
323
|
如果根 `AGENTS.md` 由人工或其他工具管理,不要覆盖。可以改为在无冲突的子目录生成受管 `AGENTS.md`,或使用 `.ruler/` 投影。
|
|
321
324
|
|
|
322
|
-
###
|
|
325
|
+
### 底层参考:检查结果
|
|
323
326
|
|
|
324
327
|
```bash
|
|
325
328
|
npm exec --offline -- project-context check --project .
|
|
@@ -809,6 +812,7 @@ Receipt 只记录阶段证据,不代表人已验收、合并或批准长期规
|
|
|
809
812
|
|
|
810
813
|
| 命令 | 用途 | 是否可写 |
|
|
811
814
|
| --- | --- | --- |
|
|
815
|
+
| `instructions` | 返回包内唯一初始化指令、digest 与 resolved targetRoot | 否 |
|
|
812
816
|
| `capabilities` | 查询版本、schema、action kind 和永久边界 | 否 |
|
|
813
817
|
| `setup` | 聚合安全初始化、保守 discovery 和 Assist Bundle | 仅显式 `--write` |
|
|
814
818
|
| `init` | 创建空的三个 store | 仅显式 `--write` |
|
package/examples/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
包实际发布后,把 [package.json](./package.json) 中的脚本和 devDependency 合并到项目,并把 [project-context-check.yml](./project-context-check.yml) 复制到 `.github/workflows/project-context-check.yml`。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
维护者首次初始化前先读取包内唯一指令;后续命令由该指令和一次集中语义确认驱动:
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm
|
|
8
|
+
npm exec --offline -- project-context instructions --project . --prompt
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
为完全新窗口写入稳定入口并查询治理健康:
|
package/examples/package.json
CHANGED
package/migration-manifest.json
CHANGED
|
@@ -23,14 +23,16 @@
|
|
|
23
23
|
"consumerChanges": {
|
|
24
24
|
"actionPlan": {"reason": "Action Plan schema 1 and 2 readers remain compatible; writers remain schema 2.", "state": "preserve"},
|
|
25
25
|
"adaptiveContextBundle": {"reason": "Schema 1 Adaptive Context Bundles lack task lineage and strict withheld-delivery semantics; regenerate as schema 2.", "state": "regenerate"},
|
|
26
|
-
"capabilities": {"reason": "Consumers must branch on capabilities schema
|
|
26
|
+
"capabilities": {"reason": "Consumers must branch on capabilities schema 8 and exchange protocol 8.", "state": "regenerate"},
|
|
27
27
|
"contextQuery": {"reason": "Context Query schema 1 is short-lived and must use current snapshots.", "state": "regenerate"},
|
|
28
28
|
"coverageAudit": {"reason": "Coverage Audit schema 1 is derived from the current Contract and filesystem evidence.", "state": "regenerate"},
|
|
29
29
|
"evidenceBundle": {"reason": "Evidence Bundle schema 1 remains readable and separate from upgrade results.", "state": "preserve"},
|
|
30
30
|
"evidenceInput": {"reason": "Evidence Input schema 1 remains readable and is never rewritten by upgrade.", "state": "preserve"},
|
|
31
|
-
"exchange": {"reason": "Exchange protocol capability metadata changes to version
|
|
31
|
+
"exchange": {"reason": "Exchange protocol capability metadata changes to version 8.", "state": "regenerate"},
|
|
32
32
|
"hostPromotionEvidence": {"reason": "Host Promotion Evidence is short-lived and remains bound to exact code, artifact, and Project Context snapshots.", "state": "regenerate"},
|
|
33
|
+
"initializationInstruction": {"reason": "Schema 1 is package-derived from the exact installed instruction and resolved target root.", "state": "regenerate"},
|
|
33
34
|
"integrationReviewBundle": {"reason": "Short-lived integration review bundles must be regenerated against current baselines.", "state": "regenerate"},
|
|
35
|
+
"projectStatus": {"reason": "Schema 2 separates governance health from Contract readiness and task-context routing.", "state": "regenerate"},
|
|
34
36
|
"reviewBundle": {"reason": "Review Bundle schema 2 remains readable but short-lived reviews must be regenerated when their baselines change.", "state": "regenerate"},
|
|
35
37
|
"routingIndex": {"reason": "Routing Index schema 1 is disposable derived data and must be rebuilt from the current Contract.", "state": "invalidate"},
|
|
36
38
|
"stageContextBundle": {"reason": "Short-lived stage context bundles must be regenerated against current receipts.", "state": "regenerate"},
|
|
@@ -40,8 +42,8 @@
|
|
|
40
42
|
,"truthReconciliationReviewBundle": {"reason": "Schema 1 reviews lack finding digests and machine-verifiable resolution outcomes; recompute as schema 2.", "state": "regenerate"}
|
|
41
43
|
},
|
|
42
44
|
"externalEffects": {"automaticUpgrade": false, "businessCode": false, "git": false, "network": false, "packageManager": false, "projectTests": false},
|
|
43
|
-
"manifestDigest": "sha256:
|
|
44
|
-
"package": {"name": "frontend-project-context", "version": "1.
|
|
45
|
+
"manifestDigest": "sha256:be29e7ee930d34533380e6d2408f614fc7406ad3491a1657776d904bcc5ebacf",
|
|
46
|
+
"package": {"name": "frontend-project-context", "version": "1.8.0"},
|
|
45
47
|
"paths": [
|
|
46
48
|
{
|
|
47
49
|
"acceptance": ["project-context-clean", "target-renderers-current"],
|
|
@@ -74,6 +76,14 @@
|
|
|
74
76
|
"migrationIds": ["upgrade.republish-ai-entry.v1"],
|
|
75
77
|
"requiresHumanReview": false,
|
|
76
78
|
"rollbackClass": "package-only"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"acceptance": ["project-context-clean", "target-renderers-current"],
|
|
82
|
+
"classification": "package-only",
|
|
83
|
+
"fromVersion": "1.7.0",
|
|
84
|
+
"migrationIds": ["upgrade.republish-ai-entry.v1"],
|
|
85
|
+
"requiresHumanReview": false,
|
|
86
|
+
"rollbackClass": "package-only"
|
|
77
87
|
}
|
|
78
88
|
],
|
|
79
89
|
"protocols": {
|
|
@@ -83,9 +93,11 @@
|
|
|
83
93
|
"coverageAudit": {"readable": [1], "written": 1},
|
|
84
94
|
"evidenceBundle": {"readable": [1], "written": 1},
|
|
85
95
|
"evidenceInput": {"readable": [1], "written": 1},
|
|
86
|
-
"exchange": {"readable": [4, 5, 6, 7], "written":
|
|
96
|
+
"exchange": {"readable": [4, 5, 6, 7, 8], "written": 8},
|
|
87
97
|
"hostPromotionEvidence": {"readable": [1], "written": 1},
|
|
98
|
+
"initializationInstruction": {"readable": [1], "written": 1},
|
|
88
99
|
"integrationReviewBundle": {"readable": [1], "written": 1},
|
|
100
|
+
"projectStatus": {"readable": [1, 2], "written": 2},
|
|
89
101
|
"reviewBundle": {"readable": [1, 2], "written": 2},
|
|
90
102
|
"routingIndex": {"readable": [1, 2], "written": 2},
|
|
91
103
|
"stageContextBundle": {"readable": [1], "written": 1},
|
|
@@ -95,7 +107,7 @@
|
|
|
95
107
|
"truthReconciliationReviewBundle": {"readable": [2], "written": 2}
|
|
96
108
|
},
|
|
97
109
|
"renderers": {
|
|
98
|
-
"aiEntry": {"readable": [1, 2, 3], "written":
|
|
110
|
+
"aiEntry": {"readable": [1, 2, 3, 4], "written": 4},
|
|
99
111
|
"projection": {"readable": [1, 2, 3], "written": 3}
|
|
100
112
|
},
|
|
101
113
|
"rollback": {"automatic": false, "defaultClass": "package-only", "externalRestoreRequired": true},
|
|
@@ -106,5 +118,5 @@
|
|
|
106
118
|
"proposal": {"readable": [1], "written": [1]},
|
|
107
119
|
"sourceLock": {"readable": [1], "written": [1]}
|
|
108
120
|
},
|
|
109
|
-
"upgradeFrom": ["1.3.1", "1.4.0", "1.5.0", "1.6.0"]
|
|
121
|
+
"upgradeFrom": ["1.3.1", "1.4.0", "1.5.0", "1.6.0", "1.7.0"]
|
|
110
122
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frontend-project-context",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Govern, compile, and verify project-local context for AI coding tools.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"check": "node --check bin/project-context.mjs && npm test",
|
|
30
|
-
"test": "node --test test/project-context/acceptance.test.mjs test/project-context/adaptive-context.test.mjs test/project-context/adaptive-delivery-v2.test.mjs test/project-context/assist.test.mjs test/project-context/cli.test.mjs test/project-context/dashboard.test.mjs test/project-context/evidence.test.mjs test/project-context/exchange.test.mjs test/project-context/maintenance.test.mjs test/project-context/source-lifecycle.test.mjs test/project-context/task-context.test.mjs test/project-context/takeover.test.mjs test/project-context/truth-reconciliation.test.mjs test/project-context/upgrade.test.mjs test/release/acceptance.test.mjs",
|
|
30
|
+
"test": "node --test test/project-context/acceptance.test.mjs test/project-context/adaptive-context.test.mjs test/project-context/adaptive-delivery-v2.test.mjs test/project-context/assist.test.mjs test/project-context/cli.test.mjs test/project-context/dashboard.test.mjs test/project-context/evidence.test.mjs test/project-context/exchange.test.mjs test/project-context/maintenance.test.mjs test/project-context/onboarding-closure.test.mjs test/project-context/source-lifecycle.test.mjs test/project-context/task-context.test.mjs test/project-context/takeover.test.mjs test/project-context/truth-reconciliation.test.mjs test/project-context/upgrade.test.mjs test/release/acceptance.test.mjs",
|
|
31
31
|
"prepack": "npm run check"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "urn:frontend-project-context:schema:capabilities:
|
|
3
|
+
"$id": "urn:frontend-project-context:schema:capabilities:8",
|
|
4
4
|
"title": "Frontend Project Context Capabilities",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
@@ -12,23 +12,24 @@
|
|
|
12
12
|
"commands",
|
|
13
13
|
"actionKinds",
|
|
14
14
|
"contextBudget",
|
|
15
|
+
"initializationInstruction",
|
|
15
16
|
"initialization",
|
|
16
17
|
"initialized",
|
|
17
18
|
"project",
|
|
18
19
|
"boundaries"
|
|
19
20
|
],
|
|
20
21
|
"properties": {
|
|
21
|
-
"schemaVersion": { "const":
|
|
22
|
+
"schemaVersion": { "const": 8 },
|
|
22
23
|
"package": {
|
|
23
24
|
"type": "object",
|
|
24
25
|
"additionalProperties": false,
|
|
25
26
|
"required": ["name", "version"],
|
|
26
27
|
"properties": {
|
|
27
28
|
"name": { "const": "frontend-project-context" },
|
|
28
|
-
"version": { "const": "1.
|
|
29
|
+
"version": { "const": "1.8.0" }
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
|
-
"exchangeProtocolVersion": { "const":
|
|
32
|
+
"exchangeProtocolVersion": { "const": 8 },
|
|
32
33
|
"schemas": {
|
|
33
34
|
"type": "object",
|
|
34
35
|
"additionalProperties": false,
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"evidenceInput",
|
|
46
47
|
"hostPromotionEvidence",
|
|
47
48
|
"integrationReviewBundle",
|
|
49
|
+
"initializationInstruction",
|
|
48
50
|
"projectionLock",
|
|
49
51
|
"projectionLockReadable",
|
|
50
52
|
"projectionLockWritten",
|
|
@@ -69,7 +71,7 @@
|
|
|
69
71
|
"actionPlan": { "const": 2 },
|
|
70
72
|
"adaptiveContextBundle": { "const": 2 },
|
|
71
73
|
"assistBundle": { "const": 1 },
|
|
72
|
-
"capabilities": { "const":
|
|
74
|
+
"capabilities": { "const": 8 },
|
|
73
75
|
"contract": { "const": 2 },
|
|
74
76
|
"contextQuery": { "const": 2 },
|
|
75
77
|
"coverageAudit": { "const": 1 },
|
|
@@ -78,13 +80,14 @@
|
|
|
78
80
|
"evidenceInput": { "const": 1 },
|
|
79
81
|
"hostPromotionEvidence": { "const": 1 },
|
|
80
82
|
"integrationReviewBundle": { "const": 1 },
|
|
83
|
+
"initializationInstruction": { "const": 1 },
|
|
81
84
|
"projectionLock": { "const": 2 },
|
|
82
85
|
"projectionLockReadable": { "const": [1, 2] },
|
|
83
86
|
"projectionLockWritten": { "enum": [1, 2] },
|
|
84
87
|
"projectionRenderer": { "type": "integer" },
|
|
85
88
|
"proposal": { "const": 1 },
|
|
86
|
-
"projectStatus": { "const":
|
|
87
|
-
"aiEntryRenderer": { "const":
|
|
89
|
+
"projectStatus": { "const": 2 },
|
|
90
|
+
"aiEntryRenderer": { "const": 4 },
|
|
88
91
|
"migrationManifest": { "const": 2 },
|
|
89
92
|
"migrationPlan": { "const": 1 },
|
|
90
93
|
"reviewBundle": { "const": 2 },
|
|
@@ -99,7 +102,7 @@
|
|
|
99
102
|
"upgradeResultBundle": { "const": 1 }
|
|
100
103
|
}
|
|
101
104
|
},
|
|
102
|
-
"commands": { "type": "array", "minItems": 1, "uniqueItems": true, "allOf": [{"contains": {"const": "upgrade-check"}}, {"contains": {"const": "upgrade-plan"}}, {"contains": {"const": "upgrade-apply"}}], "items": { "type": "string" } },
|
|
105
|
+
"commands": { "type": "array", "minItems": 1, "uniqueItems": true, "allOf": [{"contains": {"const": "instructions"}}, {"contains": {"const": "upgrade-check"}}, {"contains": {"const": "upgrade-plan"}}, {"contains": {"const": "upgrade-apply"}}], "items": { "type": "string" } },
|
|
103
106
|
"actionKinds": {
|
|
104
107
|
"type": "array",
|
|
105
108
|
"minItems": 10,
|
|
@@ -130,6 +133,18 @@
|
|
|
130
133
|
"callerMustProvideLimit": { "const": true }
|
|
131
134
|
}
|
|
132
135
|
},
|
|
136
|
+
"initializationInstruction": {
|
|
137
|
+
"type": "object",
|
|
138
|
+
"additionalProperties": false,
|
|
139
|
+
"required": ["id", "version", "packagePath", "digest", "command"],
|
|
140
|
+
"properties": {
|
|
141
|
+
"id": {"const": "ai-project-initialization"},
|
|
142
|
+
"version": {"const": 1},
|
|
143
|
+
"packagePath": {"const": "docs/AI-PROJECT-INITIALIZATION.md"},
|
|
144
|
+
"digest": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"},
|
|
145
|
+
"command": {"const": "project-context instructions --project PATH [--json | --prompt]"}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
133
148
|
"initialization": { "enum": ["uninitialized", "partial", "initialized"] },
|
|
134
149
|
"initialized": { "type": "boolean" },
|
|
135
150
|
"project": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"required": ["name", "version", "exchangeProtocolVersion"],
|
|
15
15
|
"properties": {
|
|
16
16
|
"name": { "const": "frontend-project-context" },
|
|
17
|
-
"version": { "const": "1.
|
|
17
|
+
"version": { "const": "1.8.0" },
|
|
18
18
|
"exchangeProtocolVersion": { "const": 6 }
|
|
19
19
|
}
|
|
20
20
|
},
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:frontend-project-context:schema:initialization-instruction:1",
|
|
4
|
+
"title": "Frontend Project Context Initialization Instruction",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["schemaVersion", "package", "instruction", "targetRoot", "boundaries"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schemaVersion": {"const": 1},
|
|
10
|
+
"package": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"required": ["name", "version"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"name": {"const": "frontend-project-context"},
|
|
16
|
+
"version": {"const": "1.8.0"}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"instruction": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"required": ["id", "version", "packagePath", "digest", "content"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"id": {"const": "ai-project-initialization"},
|
|
25
|
+
"version": {"const": 1},
|
|
26
|
+
"packagePath": {"const": "docs/AI-PROJECT-INITIALIZATION.md"},
|
|
27
|
+
"digest": {"$ref": "#/$defs/digest"},
|
|
28
|
+
"content": {"type": "string", "minLength": 1}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"targetRoot": {"type": "string", "minLength": 1},
|
|
32
|
+
"boundaries": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"required": ["provider", "agentRuntime", "git", "network", "dependencyInstallation", "automaticApproval", "businessCodeWrites", "taskExecution", "stagePathBodyReads", "applyPlan", "scheduler", "daemon", "telemetry", "selfUpdate", "automaticEvidenceUpload", "packageManager", "automaticUpgrade"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"provider": {"const": false},
|
|
38
|
+
"agentRuntime": {"const": false},
|
|
39
|
+
"git": {"const": false},
|
|
40
|
+
"network": {"const": false},
|
|
41
|
+
"dependencyInstallation": {"const": false},
|
|
42
|
+
"automaticApproval": {"const": false},
|
|
43
|
+
"businessCodeWrites": {"const": false},
|
|
44
|
+
"taskExecution": {"const": false},
|
|
45
|
+
"stagePathBodyReads": {"const": false},
|
|
46
|
+
"applyPlan": {"const": false},
|
|
47
|
+
"scheduler": {"const": false},
|
|
48
|
+
"daemon": {"const": false},
|
|
49
|
+
"telemetry": {"const": false},
|
|
50
|
+
"selfUpdate": {"const": false},
|
|
51
|
+
"automaticEvidenceUpload": {"const": false},
|
|
52
|
+
"packageManager": {"const": false},
|
|
53
|
+
"automaticUpgrade": {"const": false}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"$defs": {
|
|
58
|
+
"digest": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"required": ["schemaVersion", "package", "upgradeFrom", "stores", "renderers", "protocols", "paths", "builtInMigrations", "consumerChanges", "acceptanceCommands", "rollback", "externalEffects", "manifestDigest"],
|
|
8
8
|
"properties": {
|
|
9
9
|
"schemaVersion": {"const": 2},
|
|
10
|
-
"package": {"type": "object", "additionalProperties": false, "required": ["name", "version"], "properties": {"name": {"const": "frontend-project-context"}, "version": {"const": "1.
|
|
11
|
-
"upgradeFrom": {"const": ["1.3.1", "1.4.0", "1.5.0", "1.6.0"]},
|
|
10
|
+
"package": {"type": "object", "additionalProperties": false, "required": ["name", "version"], "properties": {"name": {"const": "frontend-project-context"}, "version": {"const": "1.8.0"}}},
|
|
11
|
+
"upgradeFrom": {"const": ["1.3.1", "1.4.0", "1.5.0", "1.6.0", "1.7.0"]},
|
|
12
12
|
"stores": {"type": "object", "additionalProperties": false, "required": ["contract", "projectionLock", "proposal", "sourceLock"], "properties": {"contract": {"$ref": "#/$defs/versionMatrix"}, "projectionLock": {"$ref": "#/$defs/versionMatrix"}, "proposal": {"$ref": "#/$defs/versionMatrix"}, "sourceLock": {"$ref": "#/$defs/versionMatrix"}}},
|
|
13
13
|
"renderers": {"type": "object", "additionalProperties": false, "required": ["aiEntry", "projection"], "properties": {"aiEntry": {"$ref": "#/$defs/versionTarget"}, "projection": {"$ref": "#/$defs/versionTarget"}}},
|
|
14
14
|
"protocols": {"type": "object", "additionalProperties": {"$ref": "#/$defs/versionTarget"}},
|
|
15
|
-
"paths": {"type": "array", "minItems":
|
|
15
|
+
"paths": {"type": "array", "minItems": 5, "maxItems": 5, "items": {"type": "object", "additionalProperties": false, "required": ["fromVersion", "classification", "migrationIds", "requiresHumanReview", "rollbackClass", "acceptance"], "properties": {"fromVersion": {"enum": ["1.3.1", "1.4.0", "1.5.0", "1.6.0", "1.7.0"]}, "classification": {"enum": ["package-only", "republish-ai-entry", "republish-projection", "built-in-store-migration", "invalidate-ephemeral-protocol"]}, "migrationIds": {"$ref": "#/$defs/strings"}, "requiresHumanReview": {"type": "boolean"}, "rollbackClass": {"$ref": "#/$defs/rollbackClass"}, "acceptance": {"$ref": "#/$defs/strings"}}}},
|
|
16
16
|
"builtInMigrations": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["id", "kind", "input", "targetType", "writes", "rollbackClass", "reverseMigrationId"], "properties": {"id": {"type": "string"}, "kind": {"enum": ["package-only", "republish-ai-entry", "republish-projection", "built-in-store-migration", "invalidate-ephemeral-protocol"]}, "input": {"type": "object", "additionalProperties": false, "required": ["schemaVersions", "beforeDigestRequired"], "properties": {"schemaVersions": {"type": "array", "items": {"type": "integer", "minimum": 1}}, "beforeDigestRequired": {"type": "boolean"}}}, "targetType": {"enum": ["none", "ai-entry", "projection", "store", "ephemeral-protocol"]}, "writes": {"type": "boolean"}, "rollbackClass": {"$ref": "#/$defs/rollbackClass"}, "reverseMigrationId": {"type": ["string", "null"]}}}},
|
|
17
17
|
"consumerChanges": {"type": "object", "additionalProperties": {"type": "object", "additionalProperties": false, "required": ["state", "reason"], "properties": {"state": {"enum": ["preserve", "regenerate", "invalidate"]}, "reason": {"type": "string"}}}},
|
|
18
18
|
"acceptanceCommands": {"$ref": "#/$defs/strings"},
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"properties": {
|
|
9
9
|
"schemaVersion": {"const": 1},
|
|
10
10
|
"kind": {"const": "target-upgrade-plan"},
|
|
11
|
-
"fromVersion": {"enum": ["1.3.1", "1.4.0", "1.5.0", "1.6.0"]},
|
|
12
|
-
"targetVersion": {"const": "1.
|
|
11
|
+
"fromVersion": {"enum": ["1.3.1", "1.4.0", "1.5.0", "1.6.0", "1.7.0"]},
|
|
12
|
+
"targetVersion": {"const": "1.8.0"},
|
|
13
13
|
"manifestDigest": {"$ref": "#/$defs/digest"},
|
|
14
14
|
"assessmentDigest": {"$ref": "#/$defs/digest"},
|
|
15
15
|
"snapshots": {"anyOf": [{"type": "null"}, {"$ref": "#/$defs/snapshots"}]},
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "urn:frontend-project-context:schema:project-status:
|
|
3
|
+
"$id": "urn:frontend-project-context:schema:project-status:2",
|
|
4
4
|
"title": "Frontend Project Context Project Status",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"additionalProperties": false,
|
|
7
|
-
"required": ["schemaVersion", "package", "initialization", "project", "snapshots", "health", "entry", "summary", "findingCodes", "sourceIds", "itemIds", "projectionPaths", "readTargets", "workUnits", "nextActions", "boundaries"],
|
|
7
|
+
"required": ["schemaVersion", "package", "initialization", "project", "snapshots", "health", "entry", "contractReadiness", "summary", "findingCodes", "sourceIds", "itemIds", "projectionPaths", "readTargets", "workUnits", "nextActions", "boundaries"],
|
|
8
8
|
"properties": {
|
|
9
|
-
"schemaVersion": { "const":
|
|
9
|
+
"schemaVersion": { "const": 2 },
|
|
10
10
|
"package": {
|
|
11
11
|
"type": "object",
|
|
12
12
|
"additionalProperties": false,
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"rendererVersion": { "type": ["integer", "null"] }
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
|
+
"contractReadiness": {"enum": ["not-initialized", "contract-incomplete", "contract-ready"]},
|
|
39
40
|
"summary": {
|
|
40
41
|
"type": "object",
|
|
41
42
|
"additionalProperties": false,
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"nextActions": {
|
|
57
58
|
"type": "array",
|
|
58
59
|
"uniqueItems": true,
|
|
59
|
-
"items": { "enum": ["
|
|
60
|
+
"items": { "enum": ["read-initialization-instructions", "complete-onboarding", "compile-task-context", "run-sync", "review-pending", "review-source-change", "review-projection", "publish-ai-entry", "resolve-conflict"] }
|
|
60
61
|
},
|
|
61
62
|
"boundaries": { "type": "object", "additionalProperties": { "const": false } }
|
|
62
63
|
},
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"schemaVersion": {"const": 1},
|
|
10
10
|
"kind": {"const": "upgrade-assessment"},
|
|
11
11
|
"product": {"type": "object", "additionalProperties": false, "required": ["name"], "properties": {"name": {"const": "frontend-project-context"}}},
|
|
12
|
-
"fromVersion": {"enum": ["1.3.1", "1.4.0", "1.5.0", "1.6.0"]},
|
|
13
|
-
"targetVersion": {"const": "1.
|
|
12
|
+
"fromVersion": {"enum": ["1.3.1", "1.4.0", "1.5.0", "1.6.0", "1.7.0"]},
|
|
13
|
+
"targetVersion": {"const": "1.8.0"},
|
|
14
14
|
"fromVersionEvidence": {"const": "host-asserted"},
|
|
15
15
|
"manifestSchemaVersion": {"const": 2},
|
|
16
16
|
"manifestDigest": {"$ref": "#/$defs/digest"},
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"kind": {"const": "upgrade-result-bundle"},
|
|
11
11
|
"product": {"type": "object", "additionalProperties": false, "required": ["name"], "properties": {"name": {"const": "frontend-project-context"}}},
|
|
12
12
|
"fromVersion": {"type": "string"},
|
|
13
|
-
"targetVersion": {"const": "1.
|
|
13
|
+
"targetVersion": {"const": "1.8.0"},
|
|
14
14
|
"manifestDigest": {"$ref": "#/$defs/digest"},
|
|
15
15
|
"planDigest": {"$ref": "#/$defs/digest"},
|
|
16
16
|
"mode": {"enum": ["preview", "write"]},
|
|
@@ -6,23 +6,25 @@ import { fail } from "./errors.mjs";
|
|
|
6
6
|
import { atomicWriteFile, atomicWriteJson, readJsonFile } from "./io.mjs";
|
|
7
7
|
import { normalizeRelativePath, resolveWritableInside } from "./path-policy.mjs";
|
|
8
8
|
|
|
9
|
-
export const AI_ENTRY_RENDERER_VERSION =
|
|
9
|
+
export const AI_ENTRY_RENDERER_VERSION = 4;
|
|
10
10
|
export const AI_ENTRY_REGION_ID = "project-context-ai-entry";
|
|
11
11
|
export const AI_ENTRY_START = "<!-- project-context:ai-entry:start -->";
|
|
12
12
|
export const AI_ENTRY_END = "<!-- project-context:ai-entry:end -->";
|
|
13
13
|
|
|
14
14
|
const ENTRY_LINES = [
|
|
15
15
|
AI_ENTRY_START,
|
|
16
|
-
"<!-- project-context:ai-entry; schema-version: 1; renderer-version:
|
|
16
|
+
"<!-- project-context:ai-entry; schema-version: 1; renderer-version: 4 -->",
|
|
17
17
|
"## Project Context 启动流程",
|
|
18
18
|
"",
|
|
19
19
|
"开始项目工作前,使用项目本地安装的 `frontend-project-context` CLI,不要临时下载其他版本。",
|
|
20
20
|
"",
|
|
21
21
|
"1. 运行 `npm exec --offline -- project-context status --project . --json`;如果本地依赖不存在,停止并报告,不要临时下载同名包。",
|
|
22
|
-
"2. 如果状态为 `partial` 或 `invalid`,停止写入并报告准确的恢复证据。",
|
|
23
|
-
"3.
|
|
24
|
-
"4.
|
|
25
|
-
"5.
|
|
22
|
+
"2. 如果状态为 `uninitialized`,运行 `npm exec --offline -- project-context instructions --project . --prompt`,按包内唯一指令完成完整初始化;如果为 `partial` 或 `invalid`,停止写入并报告准确的恢复证据。",
|
|
23
|
+
"3. 如果状态为 `attention`,执行 `sync` 返回的维护工作单元;不得重新运行 `setup` 覆盖已有 store。",
|
|
24
|
+
"4. 如果状态为 `clean`,根据真实任务确定项目内目标路径,并运行 `npm exec --offline -- project-context context --project . --path <RELATIVE_PATH> --task <TEXT>`。",
|
|
25
|
+
"5. 必须先消费命中的 Project Contract,报告实际 item IDs、scope 和必要 read targets;Contract 为空、目标 scope 未命中或关键上下文不足时,报告 onboarding/context gap 并停止,不能直接进入源码。",
|
|
26
|
+
"6. 任何 plan、bundle、receipt、review 或 AI 建议都不代表人工批准。",
|
|
27
|
+
"7. 声明完成前,将 Project Context 恢复为 `clean`,否则报告准确的阻断项。",
|
|
26
28
|
AI_ENTRY_END,
|
|
27
29
|
];
|
|
28
30
|
|
|
@@ -37,6 +37,11 @@ import {
|
|
|
37
37
|
TRUTH_RECONCILIATION_INPUT_SCHEMA_VERSION,
|
|
38
38
|
TRUTH_RECONCILIATION_REVIEW_BUNDLE_SCHEMA_VERSION,
|
|
39
39
|
} from "./truth-reconciliation-schema.mjs";
|
|
40
|
+
import {
|
|
41
|
+
INITIALIZATION_INSTRUCTION_COMMAND,
|
|
42
|
+
INITIALIZATION_INSTRUCTION_SCHEMA_VERSION,
|
|
43
|
+
readInitializationInstruction,
|
|
44
|
+
} from "./initialization-instruction.mjs";
|
|
40
45
|
|
|
41
46
|
function schemas(projectionLockWritten = 1) {
|
|
42
47
|
return {
|
|
@@ -51,6 +56,7 @@ function schemas(projectionLockWritten = 1) {
|
|
|
51
56
|
evidenceBundle: EVIDENCE_BUNDLE_SCHEMA_VERSION,
|
|
52
57
|
evidenceInput: EVIDENCE_INPUT_SCHEMA_VERSION,
|
|
53
58
|
integrationReviewBundle: INTEGRATION_REVIEW_BUNDLE_SCHEMA_VERSION,
|
|
59
|
+
initializationInstruction: INITIALIZATION_INSTRUCTION_SCHEMA_VERSION,
|
|
54
60
|
hostPromotionEvidence: HOST_PROMOTION_EVIDENCE_SCHEMA_VERSION,
|
|
55
61
|
projectionLock: 2,
|
|
56
62
|
projectionLockReadable: [1, 2],
|
|
@@ -96,6 +102,7 @@ export const PERMANENT_BOUNDARIES = Object.freeze({
|
|
|
96
102
|
|
|
97
103
|
export async function buildCapabilities(root) {
|
|
98
104
|
const initialization = await inspectProjectInitialization(root);
|
|
105
|
+
const instruction = await readInitializationInstruction();
|
|
99
106
|
let project = null;
|
|
100
107
|
let projectionLockWritten = 1;
|
|
101
108
|
if (initialization.status === "initialized") {
|
|
@@ -111,6 +118,13 @@ export async function buildCapabilities(root) {
|
|
|
111
118
|
commands: [...COMMANDS],
|
|
112
119
|
actionKinds: [...ACTION_KINDS],
|
|
113
120
|
contextBudget: { unit: CONTEXT_BUDGET_UNIT, modelTokens: false, callerMustProvideLimit: true },
|
|
121
|
+
initializationInstruction: {
|
|
122
|
+
id: instruction.id,
|
|
123
|
+
version: instruction.version,
|
|
124
|
+
packagePath: instruction.packagePath,
|
|
125
|
+
digest: instruction.digest,
|
|
126
|
+
command: INITIALIZATION_INSTRUCTION_COMMAND,
|
|
127
|
+
},
|
|
114
128
|
initialization: initialization.status,
|
|
115
129
|
initialized: initialization.status === "initialized",
|
|
116
130
|
project,
|
|
@@ -24,12 +24,14 @@ import { renderContextBundle } from "./renderer.mjs";
|
|
|
24
24
|
import { buildIntegrationReviewBundleFiles, buildStageContextBundleFiles } from "./task-context.mjs";
|
|
25
25
|
import { applyMigrationPlanFile, buildMigrationPlanFile, buildUpgradeAssessment } from "./upgrade.mjs";
|
|
26
26
|
import { buildTruthReconciliationReviewFiles } from "./truth-reconciliation.mjs";
|
|
27
|
+
import { buildInitializationInstruction, renderInitializationPrompt } from "./initialization-instruction.mjs";
|
|
27
28
|
|
|
28
29
|
const HELP = `project-context — model-neutral project contract compiler
|
|
29
30
|
|
|
30
31
|
Usage:
|
|
31
32
|
project-context init --project PATH --id ID --name NAME [--write] [--json]
|
|
32
33
|
project-context capabilities --project PATH [--json]
|
|
34
|
+
project-context instructions --project PATH [--json | --prompt]
|
|
33
35
|
project-context status --project PATH [--json]
|
|
34
36
|
project-context evidence --project PATH --input FILE [--json]
|
|
35
37
|
project-context upgrade-check --project PATH --from-version VERSION [--json]
|
|
@@ -75,6 +77,7 @@ const BOOLEAN_FLAGS = new Set(["write", "json", "full-json", "help", "pending",
|
|
|
75
77
|
const COMMAND_OPTIONS = new Map([
|
|
76
78
|
["init", new Set(["project", "id", "name", "write", "json", "help"])],
|
|
77
79
|
["capabilities", new Set(["project", "json", "help"])],
|
|
80
|
+
["instructions", new Set(["project", "json", "prompt", "help"])],
|
|
78
81
|
["status", new Set(["project", "json", "help"])],
|
|
79
82
|
["evidence", new Set(["project", "input", "json", "help"])],
|
|
80
83
|
["upgrade-check", new Set(["project", "from-version", "json", "help"])],
|
|
@@ -342,6 +345,18 @@ async function runCommand(command, options) {
|
|
|
342
345
|
if (!COMMAND_OPTIONS.has(command)) fail("command-unknown", `unknown command: ${command}`);
|
|
343
346
|
rejectUnsupportedOptions(command, options, COMMAND_OPTIONS.get(command));
|
|
344
347
|
const root = await resolveProjectRoot(required(options, "project"));
|
|
348
|
+
if (command === "instructions") {
|
|
349
|
+
if (options.json && options.prompt) fail("argument-conflict", "instructions accepts only one of --json or --prompt");
|
|
350
|
+
const instruction = await buildInitializationInstruction(root, PERMANENT_BOUNDARIES);
|
|
351
|
+
if (options.prompt) return { exitCode: 0, stdout: renderInitializationPrompt(instruction), stderr: "" };
|
|
352
|
+
const summary = [
|
|
353
|
+
`Initialization instruction ${instruction.instruction.id} v${instruction.instruction.version}.`,
|
|
354
|
+
`Package: ${instruction.package.name}@${instruction.package.version}.`,
|
|
355
|
+
`Target root: ${instruction.targetRoot}.`,
|
|
356
|
+
`Instruction: ${instruction.instruction.packagePath}; ${instruction.instruction.digest}.`,
|
|
357
|
+
].join("\n") + "\n";
|
|
358
|
+
return { exitCode: 0, stdout: jsonOrText(options, instruction, summary), stderr: "" };
|
|
359
|
+
}
|
|
345
360
|
if (command === "capabilities") {
|
|
346
361
|
const capabilities = await buildCapabilities(root);
|
|
347
362
|
const summary = [
|
|
@@ -308,7 +308,7 @@ export function validateProjectionLock(lock) {
|
|
|
308
308
|
if (entry.regionId !== "project-context-ai-entry") fail("schema-invalid-enum", "AI Entry regionId is invalid");
|
|
309
309
|
string(entry.regionDigest, `${label}.regionDigest`);
|
|
310
310
|
if (!SHA256.test(entry.regionDigest)) fail("schema-invalid", "AI Entry regionDigest must be sha256");
|
|
311
|
-
if (![1, 2, 3].includes(entry.rendererVersion)) fail("schema-version-unsupported", "AI Entry rendererVersion must be 1, 2, or
|
|
311
|
+
if (![1, 2, 3, 4].includes(entry.rendererVersion)) fail("schema-version-unsupported", "AI Entry rendererVersion must be 1, 2, 3, or 4");
|
|
312
312
|
if (typeof entry.createdFile !== "boolean") fail("schema-invalid", `${label}.createdFile must be boolean`);
|
|
313
313
|
} else {
|
|
314
314
|
if (entry.target !== "agents" && entry.target !== "ruler") fail("schema-invalid-enum", "projection target is invalid");
|