@pm_zhousl/xinyun-ai-init 1.12.0 → 1.12.1

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 (28) hide show
  1. package/init/xinyun-ai-init/README.md +1 -1
  2. package/init/xinyun-ai-init/rules/directory-self-completion.md +1 -0
  3. package/init/xinyun-ai-init/rules/init-rules.md +4 -0
  4. package/init/xinyun-ai-init/rules/session-workbench.md +6 -0
  5. package/init/xinyun-ai-init/rules/upgrade-rules.md +4 -0
  6. package/init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md +25 -0
  7. package/init/xinyun-ai-init/templates/AGENTS.template.md +1 -0
  8. package/init/xinyun-ai-init/templates/README.template.md +4 -0
  9. package/init/xinyun-ai-init/templates/core-rules.template.md +4 -0
  10. package/init/xinyun-ai-init/templates/current-task.template.md +2 -0
  11. package/init/xinyun-ai-init/templates/init-result.template.json +10 -1
  12. package/init/xinyun-ai-init/templates/manifest.template.json +20 -2
  13. package/init/xinyun-ai-init/templates/manual-session-binding.template.json +7 -1
  14. package/init/xinyun-ai-init/templates/project-check.template.md +9 -0
  15. package/init/xinyun-ai-init/templates/project-guide.template.md +2 -0
  16. package/init/xinyun-ai-init/templates/project-index.template.json +13 -0
  17. package/init/xinyun-ai-init/templates/provider-session-binding.template.json +60 -0
  18. package/init/xinyun-ai-init/templates/role-execution.template.md +1 -0
  19. package/init/xinyun-ai-init/templates/role-session-binding.template.json +19 -2
  20. package/init/xinyun-ai-init/templates/task-index.template.json +2 -0
  21. package/init/xinyun-ai-init/templates/team/README.md +1 -0
  22. package/init/xinyun-ai-init/templates/team/assignments.json +2 -1
  23. package/init/xinyun-ai-init/version.json +1 -1
  24. package/package.json +1 -1
  25. package/scripts/verify-init-package.js +51 -1
  26. package/scripts/verify-rules-package.js +33 -1
  27. package/test-scenarios/v1.12.1-behavior-evidence.json +27 -0
  28. package/test-scenarios/v1.12.1-scenarios.md +42 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  本目录是“欣芸技术开发 Agent 流”的初始化包,负责把完整 AI 执行要求下发到目标项目。
4
4
 
5
- 当前规则版本:`1.12.0`。
5
+ 当前规则版本:`1.12.1`。
6
6
 
7
7
  ## Codex 一句话入口
8
8
 
@@ -61,6 +61,7 @@ When takeover initialization is authorized, create `host-preflight.json`, `index
61
61
  - `manifest.json`、`project-index.json` 和 `task-index.json` 必须登记 `roleSessions`、`roleSessionBindingIds`、`roleSessionBindings`、`provider=codex` 和 `sessionStatus` 枚举。
62
62
  - 绑定目录只保存 Codex 宿主返回的真实 `sessionId` 摘要、onboarding 状态、失败原因和 audit,不保存伪造 sessionId。
63
63
  - 宿主不支持创建子会话时,仍可补齐本地目录和降级记录,状态使用 `local-degraded-no-fake-session-id`。
64
+ - v1.12.1 provider 绑定记录固定写入 `xinyun-ai/sessions/provider-session-bindings.json`,模板来源为 `xinyun-ai-init/templates/provider-session-binding.template.json`。只有宿主 canonical `providerSessionId`、身份/交互证据和独占占用均通过时才可绑定;未知或普通线程 ID 保持 blocked/pending。
64
65
 
65
66
  ## v1.8 按需目录
66
67
 
@@ -1,5 +1,9 @@
1
1
  # 初始化规则
2
2
 
3
+ ## v1.12.1 provider session binding
4
+
5
+ Use the provider-specific binding contract before role-session work. `providerSessionId` must be a provider canonical session value, not a normal thread ID. Identity and interaction evidence are required for binding; missing evidence remains pending or blocked.
6
+
3
7
  - 首次只创建最小 `xinyun-ai/` 骨架和极简 `AGENTS.md`。
4
8
  - 首次不创建大量规则、模板、脚本和业务沉淀目录。
5
9
  - 首次不执行语言级语法检查、lint、typecheck、测试或构建命令。
@@ -1,5 +1,11 @@
1
1
  # 会话工作台规则
2
2
 
3
+ ## v1.12.1 provider-specific session binding
4
+
5
+ Read `v1.12.1-provider-session-binding.md` before role-session work. `providerSessionId` must come from the provider's canonical session API; a normal thread ID, task ID, title, history summary, or user statement is not a binding. Verify project identity, roleId, taskId, title, cwd, occupancy, and real send/receive evidence before binding. Missing evidence stays `bindingStatus=pending/blocked` and `executionEligible=false`.
6
+
7
+ Recovery reuses taskId and roleTaskId, increments attempt, and enters `recovery-required` after a writeback failure without creating duplicates. Unsupported hosts use `local-degraded` with `providerSessionId=null`; never fabricate a session ID.
8
+
3
9
  首次初始化不创建会话工作台。复杂任务中可按需创建:
4
10
 
5
11
  ```md
@@ -1,5 +1,9 @@
1
1
  # 升级规则
2
2
 
3
+ ## v1.12.1 provider session binding
4
+
5
+ Validate provider canonical session identity, project identity, role/task, title/cwd, interaction evidence, and exclusive occupancy before reuse. Unknown or missing evidence is blocked; ordinary thread IDs cannot be reused. Writeback recovery reuses the original task IDs, increments attempt, and cannot create duplicate sessions.
6
+
3
7
  如果项目已存在 `xinyun-ai/`,不要重复初始化,应进入升级检查模式。
4
8
 
5
9
  升级流程:
@@ -0,0 +1,25 @@
1
+ # v1.12.1 provider-specific session binding
2
+
3
+ ## Canonical provider identity
4
+
5
+ `providerSessionId` is valid only when it is returned by the declared provider's supported session API as a canonical session identifier. A normal Codex thread ID, task ID, local filename, random value, title, history summary, or user statement is not sufficient evidence and must never be copied into `providerSessionId`.
6
+
7
+ Every binding records `provider`, `providerSessionId`, `roleId`, `taskId`, `projectRootHash`, `workspaceScope`, `repositoryScopeHash`, `workstream`, `title`, `cwd`, `createdAt`, `identityEvidence`, `interactionEvidence`, `bindingMode`, `bindingStatus`, `boundBy`, and `boundAt`.
8
+
9
+ `identityEvidence` must verify the provider session ID, project identity, role, task, title, cwd, evidence source, verification time, and evidence hash. `interactionEvidence` must contain a real send receipt, receive receipt, transcript hash, message count, recorded time, and evidence hash. Sensitive prompt or response content is redacted before persistence.
10
+
11
+ ## Binding gate and states
12
+
13
+ `bindingMode` is one of `auto-created`, `auto-reused`, `manual`, `recovery`, or `local-degraded`. `bindingStatus` is one of `pending`, `validating`, `bound`, `blocked`, `rejected`, `released`, `conflict`, or `recovery-required`.
14
+
15
+ Only `bindingStatus=bound` with both evidence groups verified and exclusive occupancy may produce a project `sessionId` or `executionEligible=true`. Manual binding without evidence remains `pending` or `blocked`. Host unsupported, identity mismatch, role/task mismatch, invalid title/cwd, missing interaction evidence, occupied session, or writeback failure must not become ready.
16
+
17
+ ## Reuse and recovery
18
+
19
+ Candidate reuse first validates the provider session and all project identity fields. The v1.9 eight-field JCS-SHA-256 key remains the candidate reuse key. v1.7.3 four-field data is compatibility lookup only and never selects or binds a candidate. Recovery reuses the original task and role-task IDs, increments `attempt`, preserves audit, and never creates duplicate tasks or sessions.
20
+
21
+ If the host cannot provide a canonical provider session ID, keep `providerSessionId=null`, record `bindingStatus=blocked`, `blockedReason=host-session-capability-unavailable`, and a concrete `nextAction`. Do not fabricate an ID.
22
+
23
+ ## Boundaries
24
+
25
+ Do not install or log in to a provider, change business files, connect to a database, execute SQL, write Git, install dependencies, or publish npm packages as part of binding.
@@ -195,6 +195,7 @@ CodeGraph 为必需能力时,只有 `initialized` 或 `healthy` 才能将结
195
195
  - 真实 `sessionId` 必须来自 Codex 宿主返回值;不得伪造 sessionId。宿主不支持时记录 `local-degraded-no-fake-session-id`,保持 `sessionId=null`。
196
196
  - 创建后的角色会话先进入只读 `onboarding`;只有职责理解、职责确认、成员 / 会话绑定、确认门禁和执行资格都满足后才允许 `sessionStatus=ready`。
197
197
  - 创建成功不等于业务代码修改授权;普通咨询不创建角色会话,不写绑定文件,不创建外部账号或第三个会话。
198
+ - v1.12.1 起,角色会话必须另外记录 provider canonical `providerSessionId`;普通线程 ID、taskId、标题或历史摘要不得直接绑定。绑定前必须验证项目身份、roleId、taskId、title、cwd、独占占用、`identityEvidence` 和 `interactionEvidence`;证据不全时保持 pending/blocked。
198
199
 
199
200
  AI 接手本项目时,请先读取:
200
201
 
@@ -2,6 +2,10 @@
2
2
 
3
3
  本目录是当前项目的 AI 协作工作区,采用“欣芸技术开发 Agent 流”。
4
4
 
5
+ ## v1.12.1 provider session binding
6
+
7
+ The canonical external identity of a role session is the provider-returned `providerSessionId`. A normal thread ID, taskId, title, or history summary cannot bind a role. Binding requires project identity, roleId, taskId, title, cwd, exclusive occupancy, and real send/receive evidence; incomplete evidence cannot become ready or executionEligible.
8
+
5
9
  ## v1.10 接管门禁
6
10
 
7
11
  当前项目必须先完成 `preflight-report.json` 和 `onboarding-report.json`,再进入业务代码开发。`project-status.json` 只有在项目身份、CodeGraph、基线、团队职责、五个真实角色会话、本地控制面、旧沉淀、宿主能力和敏感扫描全部通过时才可为 `ready`;缺失真实角色会话必须为 `blocked + required-role-session-not-created`。CLI 只创建 `xinyun-ai-init/`,AI 获得授权后才创建项目控制面。
@@ -606,6 +606,10 @@ Skill 分配使用 `assignmentStatus`,使用记录使用 `usageStatus`。固
606
606
 
607
607
  总工维护 `xinyun-ai/technical-landscape.json`。只有 coverageStatus=full、unverifiedScope=[]、核心对象均有有效证据且无未登记冲突时才可 ready;partial/unknown 只能保持 partial/blocked。主会话维护 requirementPacket,总工输出 technicalImpactPacket;两个 packet 最小字段固定为 schemaVersion、packetId、requirementId、taskId、projectRootHash、version、status、content、evidence、sourceRevision、contentHash、createdAt、updatedAt,使用 RFC8785 JCS-SHA-256。需求、影响范围、身份、版本或 sourceRevision 变化时写 blockedReason=packet-stale。
608
608
 
609
+ ## v1.12.1 provider-specific session binding
610
+
611
+ 角色会话的外部身份只能是 provider 返回的 canonical `providerSessionId`。普通线程 ID、taskId、标题、历史摘要或用户口述不能直接绑定。绑定前必须验证项目身份、roleId、taskId、title、cwd、独占占用和真实发送/接收交互证据;证据不全保持 `bindingStatus=pending/blocked`,不得 ready 或 executionEligible。创建回写失败复用原 taskId/roleTaskId、递增 attempt,不创建重复会话;宿主不可用时 `providerSessionId=null`,不得伪造。
612
+
609
613
  数据库默认 databaseAccessMode=sql-only。连接、只读查询、结构变更、数据修改分别授权,四类授权状态固定为 not-requested/requested/authorized/denied/expired/failed/unknown,redactionStatus 固定为 verified/unverified/failed;SQL 执行前校验规范化 SQL、参数、方言、targetEnvironment、授权范围生成的 statementHash。授权或输入变化时回到 needs-confirmation,并追加包含 auditId、action、actorType、actorId、authorizationType、statementHash、targetEnvironment、resultStatus、redactionStatus、evidence、at 的 audit。
610
614
 
611
615
  ## 自我学习
@@ -148,6 +148,8 @@
148
148
  - blockedCount:
149
149
  - localDegradedCount:
150
150
  - bindingsPath:xinyun-ai/sessions/role-session-bindings.json
151
+ - providerBindingsPath:xinyun-ai/sessions/provider-session-bindings.json
152
+ - providerSessionId:null;无宿主 canonical ID 时不得伪造
151
153
  - sessionStatusEnum:pending / creating / created / onboarding / ready / blocked / failed / closed
152
154
  - 角色会话入口:
153
155
  - roleId:
@@ -9,7 +9,7 @@
9
9
  "statusEnum": ["pending", "initializing", "completed", "partial", "blocked", "unknown", "failed", "cancelled"],
10
10
  "statusSource": "xinyun-ai/current-task.md",
11
11
  "currentVersion": null,
12
- "targetVersion": "1.12.0",
12
+ "targetVersion": "1.12.1",
13
13
  "idempotencyKey": null,
14
14
  "createdFiles": [],
15
15
  "updatedFiles": [],
@@ -76,6 +76,15 @@
76
76
  "projectSnapshotReuse": "not-checked",
77
77
  "stageTimingRecorded": false
78
78
  },
79
+ "v1121": {
80
+ "providerSessionBindingsPath": "xinyun-ai/sessions/provider-session-bindings.json",
81
+ "providerSessionBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
82
+ "bindingGateStatus": "blocked",
83
+ "bindingStatusEnum": ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"],
84
+ "realProviderSessionRequired": true,
85
+ "fakeProviderSessionIdProhibited": true,
86
+ "unverifiedScope": ["provider-specific host session evidence"]
87
+ },
79
88
  "v19": {
80
89
  "projectIdentityPath": "xinyun-ai/project-identity.json",
81
90
  "technicalLandscapePath": "xinyun-ai/technical-landscape.json",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "projectName": "",
3
- "xinyunAiVersion": "1.12.0",
3
+ "xinyunAiVersion": "1.12.1",
4
4
  "scriptVersion": "2026.07.23",
5
5
  "schemaVersion": "1",
6
6
  "initializationMode": "fast",
@@ -64,6 +64,7 @@
64
64
  ,"hostCapabilityPreflight": true
65
65
  ,"projectStatusGate": true
66
66
  ,"takeoverBaseline": true
67
+ ,"providerSpecificSessionBinding": true
67
68
  },
68
69
  "tasking": {
69
70
  "currentTask": "xinyun-ai/current-task.md",
@@ -85,6 +86,8 @@
85
86
  "roleExecutionTemplate": "xinyun-ai-init/templates/role-execution.template.md",
86
87
  "roleSessionBindings": "xinyun-ai/sessions/role-session-bindings.json",
87
88
  "roleSessionBindingTemplate": "xinyun-ai-init/templates/role-session-binding.template.json",
89
+ "providerSessionBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
90
+ "providerSessionBindings": "xinyun-ai/sessions/provider-session-bindings.json",
88
91
  "projectStatus": "xinyun-ai/project-status.json",
89
92
  "preflightReport": "xinyun-ai/preflight-report.json",
90
93
  "onboardingReport": "xinyun-ai/onboarding-report.json",
@@ -98,8 +101,10 @@
98
101
  "directory": "xinyun-ai/sessions/roles/",
99
102
  "bindings": "xinyun-ai/sessions/role-session-bindings.json",
100
103
  "bindingTemplate": "xinyun-ai-init/templates/role-session-binding.template.json",
104
+ "providerSessionBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
105
+ "providerSessionBindings": "xinyun-ai/sessions/provider-session-bindings.json",
101
106
  "parentSessionId": null,
102
- "targetVersion": "1.12.0",
107
+ "targetVersion": "1.12.1",
103
108
  "requiredRoleCount": 5,
104
109
  "statusEnum": [
105
110
  "pending",
@@ -270,6 +275,19 @@
270
275
  "projectSnapshotReusePolicy": "reuse-until-business-or-codegraph-hash-changes",
271
276
  "stageTimingRequiredFields": ["stageId", "attempt", "status", "startedAt", "finishedAt", "durationMs", "cacheHit", "failureReason", "bottleneck", "recoveryAction"]
272
277
  },
278
+ "v1121": {
279
+ "status": "implemented-in-package",
280
+ "capability": "providerSpecificSessionBinding",
281
+ "providerBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
282
+ "providerBindings": "xinyun-ai/sessions/provider-session-bindings.json",
283
+ "providerEnum": ["codex"],
284
+ "bindingModeEnum": ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"],
285
+ "bindingStatusEnum": ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"],
286
+ "identityEvidenceRequired": ["providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "source", "verifiedAt", "evidenceHash"],
287
+ "interactionEvidenceRequired": ["sendReceipt", "receiveReceipt", "transcriptHash", "messageCount", "recordedAt", "evidenceHash"],
288
+ "bindingGate": "provider canonical ID + identity evidence + interaction evidence + exclusive occupancy",
289
+ "unsupportedHostPolicy": "blocked-without-fake-provider-session-id"
290
+ },
273
291
  "v111": {
274
292
  "status": "implemented-in-package",
275
293
  "capability": "initializationAcceleration",
@@ -5,12 +5,18 @@
5
5
  "roleTaskId": null,
6
6
  "roleId": null,
7
7
  "sessionId": null,
8
+ "providerSessionId": null,
9
+ "projectRootHash": null,
10
+ "workspaceScope": null,
11
+ "title": null,
12
+ "cwd": null,
8
13
  "sessionIdType": "host-returned-real-session",
9
14
  "provider": "codex",
15
+ "bindingMode": "manual",
10
16
  "boundBy": null,
11
17
  "boundAt": null,
12
18
  "evidence": [],
13
- "evidenceRequiredFields": ["evidenceType", "source", "sessionId", "interactionHash", "beforeSnapshotHash", "afterSnapshotHash", "recordedAt"],
19
+ "evidenceRequiredFields": ["evidenceType", "source", "sessionId", "providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "interactionHash", "beforeSnapshotHash", "afterSnapshotHash", "recordedAt"],
14
20
  "bindingStatus": "pending",
15
21
  "bindingStatusEnum": ["pending", "bound", "rejected", "blocked", "released"],
16
22
  "executionEligible": false,
@@ -168,6 +168,15 @@
168
168
  - 敏感扫描、业务文件 changedFiles 和禁止操作证明是否通过:待填写
169
169
  - `projectStatus=ready` 和 `executionEligible=true` 是否仅在全部门禁通过后出现:待填写
170
170
 
171
+ ## v1.12.1 provider session checks
172
+
173
+ - provider binding uses a host canonical `providerSessionId`: pending
174
+ - ordinary thread IDs, task IDs, titles, and summaries are rejected as provider identity: pending
175
+ - project, role, task, title, cwd, and exclusive occupancy evidence: pending
176
+ - redacted send/receive interaction evidence and transcript hash: pending
177
+ - manual binding without evidence remains pending/blocked: pending
178
+ - writeback recovery reuses task IDs, increments attempt, and creates no duplicate session: pending
179
+
171
180
  ## v1.9 检查
172
181
 
173
182
  - 项目身份是否使用 realpath / lexical-fallback、Unicode NFC、projectRootHash 和 repositoryScopeHash:待填写
@@ -218,6 +218,8 @@
218
218
  - roleSessionIdempotency:RFC8785-JCS-SHA-256(projectRootHash, workspaceScope, repositoryScopeHash, workstream, taskId, roleId, provider, targetVersion);v1.7.3 四字段仅作创建兼容索引,不参与候选选择、复用或跨项目身份判定
219
219
  - parentSessionId:待填写
220
220
  - real sessionId:待填写;不得伪造 sessionId
221
+ - providerSessionId:待填写;只能来自宿主 canonical session API,普通线程 ID 不得直接绑定
222
+ - provider binding:xinyun-ai/sessions/provider-session-bindings.json;必须有 identityEvidence、interactionEvidence 和 exclusive occupancy
221
223
  - onboarding:created 后先只读 onboarding,不能直接 ready
222
224
  - host unsupported:local-degraded-no-fake-session-id
223
225
  - created-but-writeback-failed:待填写恢复线索
@@ -147,6 +147,10 @@
147
147
  "directory": "xinyun-ai/sessions/roles/",
148
148
  "bindings": "xinyun-ai/sessions/role-session-bindings.json",
149
149
  "bindingTemplate": "xinyun-ai-init/templates/role-session-binding.template.json",
150
+ "providerSessionBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
151
+ "providerSessionBindings": "xinyun-ai/sessions/provider-session-bindings.json",
152
+ "providerSessionBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
153
+ "providerSessionBindings": "xinyun-ai/sessions/provider-session-bindings.json",
150
154
  "requiredRoleCount": 5,
151
155
  "statusEnum": [
152
156
  "pending",
@@ -288,6 +292,15 @@
288
292
  "projectSnapshotReusePolicy": "reuse-until-business-or-codegraph-hash-changes",
289
293
  "stageTimingRequiredFields": ["stageId", "attempt", "status", "startedAt", "finishedAt", "durationMs", "cacheHit", "failureReason", "bottleneck", "recoveryAction"]
290
294
  },
295
+ "v1121": {
296
+ "status": "implemented-in-package",
297
+ "providerBindingTemplate": "xinyun-ai-init/templates/provider-session-binding.template.json",
298
+ "providerBindings": "xinyun-ai/sessions/provider-session-bindings.json",
299
+ "providerEnum": ["codex"],
300
+ "bindingModeEnum": ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"],
301
+ "bindingStatusEnum": ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"],
302
+ "bindingGate": "provider canonical ID + identity evidence + interaction evidence + exclusive occupancy"
303
+ },
291
304
  "v111": {
292
305
  "status": "implemented-in-package",
293
306
  "capability": "initializationAcceleration",
@@ -0,0 +1,60 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "bindingId": "provider-session-binding-template",
4
+ "provider": "codex",
5
+ "providerSessionId": null,
6
+ "providerSessionIdType": "provider-canonical-session",
7
+ "roleId": null,
8
+ "taskId": null,
9
+ "projectRootHash": null,
10
+ "workspaceScope": null,
11
+ "repositoryScopeHash": null,
12
+ "workstream": null,
13
+ "title": null,
14
+ "cwd": null,
15
+ "createdAt": null,
16
+ "identityEvidence": {
17
+ "providerSessionId": null,
18
+ "projectRootHash": null,
19
+ "workspaceScope": null,
20
+ "roleId": null,
21
+ "taskId": null,
22
+ "title": null,
23
+ "cwd": null,
24
+ "source": null,
25
+ "verifiedAt": null,
26
+ "evidenceHash": null
27
+ },
28
+ "interactionEvidence": {
29
+ "sendReceipt": null,
30
+ "receiveReceipt": null,
31
+ "transcriptHash": null,
32
+ "messageCount": 0,
33
+ "recordedAt": null,
34
+ "evidenceHash": null
35
+ },
36
+ "bindingMode": "auto-created",
37
+ "bindingStatus": "pending",
38
+ "executionEligible": false,
39
+ "bindingStatusEnum": ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"],
40
+ "boundBy": null,
41
+ "boundAt": null,
42
+ "attempt": 1,
43
+ "recovery": {
44
+ "reuseTaskId": true,
45
+ "reuseRoleTaskId": true,
46
+ "incrementAttempt": true,
47
+ "createdDuplicateSession": false,
48
+ "recoveryReason": null,
49
+ "nextAction": null
50
+ },
51
+ "occupancy": {
52
+ "occupancyStatus": "unknown",
53
+ "occupiedByProjectRootHash": null,
54
+ "occupiedByRoleId": null,
55
+ "checkedAt": null
56
+ },
57
+ "blockedReason": null,
58
+ "audit": [],
59
+ "fakeProviderSessionIdProhibited": true
60
+ }
@@ -44,6 +44,7 @@
44
44
  - 会话创建成功后先进入 `sessionStatus=onboarding`,只读职责范围内资料并生成角色理解记录;不得因会话创建成功直接把任务标为 `ready` 或获得业务代码修改授权。
45
45
  - 只有角色理解完成、职责确认完成、成员/会话绑定满足、确认人关系无冲突且执行门禁满足时,才允许 `sessionStatus=ready` 与 `executionEligible=true`。
46
46
  - Codex 宿主不支持创建子会话、权限不足或创建失败时,必须保留 `sessionId=null`,记录 `sessionStatus=blocked/failed`、失败原因和本地降级说明,不得伪造会话。
47
+ - v1.12.1 起,`providerSessionId` 必须是 Codex 宿主 canonical session API 返回值;普通线程 ID、taskId、标题或历史摘要不得直接绑定。绑定前需验证项目身份、roleId、taskId、title、cwd、独占占用、`identityEvidence` 和 `interactionEvidence`。
47
48
 
48
49
  ## 幂等
49
50
 
@@ -5,8 +5,25 @@
5
5
  "taskId": "role-execution-task-template",
6
6
  "roleId": "project-owner",
7
7
  "sessionId": null,
8
+ "providerSessionId": null,
9
+ "providerSessionIdType": "provider-canonical-session",
8
10
  "parentSessionId": null,
9
11
  "provider": "codex",
12
+ "bindingMode": "auto-created",
13
+ "bindingStatus": "pending",
14
+ "bindingStatusEnum": ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"],
15
+ "boundBy": null,
16
+ "boundAt": null,
17
+ "title": null,
18
+ "cwd": null,
19
+ "interactionEvidence": {
20
+ "sendReceipt": null,
21
+ "receiveReceipt": null,
22
+ "transcriptHash": null,
23
+ "messageCount": 0,
24
+ "recordedAt": null,
25
+ "evidenceHash": null
26
+ },
10
27
  "identityMapping": {
11
28
  "hostThreadId": null,
12
29
  "hostSessionId": null,
@@ -16,7 +33,7 @@
16
33
  "identityEvidence": [],
17
34
  "creationEvidence": []
18
35
  },
19
- "targetVersion": "1.12.0",
36
+ "targetVersion": "1.12.1",
20
37
  "projectRootHash": null,
21
38
  "workspaceScope": {"scopeType": "project-root", "scopePathHashes": [], "scopeRevision": null},
22
39
  "repositoryScopeHash": null,
@@ -66,5 +83,5 @@
66
83
  "roleDisplayName": null,
67
84
  "responsibilityLabel": null,
68
85
  "titleSource": "role-contract",
69
- "titleVersion": "1.12.0"
86
+ "titleVersion": "1.12.1"
70
87
  }
@@ -7,6 +7,7 @@
7
7
  "roleExecutionDirectory": "xinyun-ai/tasks/role-execution/",
8
8
  "roleExecutionTaskIds": [],
9
9
  "roleSessionBindingIds": [],
10
+ "providerSessionBindingsPath": "xinyun-ai/sessions/provider-session-bindings.json",
10
11
  "roleExecutionStatusEnum": ["pending", "assigned", "accepted", "executing", "paused", "blocked", "completed", "cancelled"],
11
12
  "roleSessionStatusEnum": ["pending", "creating", "created", "onboarding", "ready", "blocked", "failed", "closed"],
12
13
  "roleExecutionPriority": {
@@ -36,6 +37,7 @@
36
37
  },
37
38
  "tasks": [],
38
39
  "roleSessionBindings": [],
40
+ "providerSessionBindings": [],
39
41
  "orchestratorSessionId": null,
40
42
  "statusSource": "xinyun-ai/current-task.md",
41
43
  "statusConsistency": {
@@ -18,6 +18,7 @@
18
18
  - 会话状态固定为 `pending/creating/created/onboarding/ready/blocked/failed/closed`。
19
19
  - 创建成功后先进入 `onboarding`,只允许只读理解职责范围和项目资料;职责理解、确认关系和执行门禁满足后才允许 `ready`。
20
20
  - Codex 宿主不支持创建子会话、权限不足或创建失败时,必须进入本地降级:保留 `sessionId=null`,记录 `sessionStatus=blocked/failed`、失败原因和下一步动作,不得伪造会话。
21
+ - v1.12.1 起,canonical 外部会话身份单独记录为 `providerSessionId`;必须有项目/角色/任务身份和真实发送/接收交互证据。普通线程 ID、标题或历史摘要不能直接绑定。
21
22
 
22
23
  ## 默认角色
23
24
 
@@ -11,6 +11,7 @@
11
11
  "taskId",
12
12
  "roleId",
13
13
  "sessionId",
14
+ "providerSessionId",
14
15
  "parentSessionId",
15
16
  "provider",
16
17
  "sessionStatus",
@@ -32,7 +33,7 @@
32
33
  "pausedRule": "status=paused requires pauseReason; other statuses require pauseReason=null.",
33
34
  "blockedRule": "status=blocked requires blockedReason=approver-unavailable or member-conflict.",
34
35
  "executionEligibility": "member bound, role ready, sessionStatus=ready, responsibility confirmed, understanding ready, and executor memberId not equal to final approver member IDs.",
35
- "sessionBindingRule": "sessionId must be a real host-returned value when provider=codex; if the host cannot create sessions, sessionId remains null and sessionStatus=blocked or failed with a local degradation reason."
36
+ "sessionBindingRule": "sessionId remains the project compatibility field; providerSessionId must be a real host-returned value from the provider canonical session API with identityEvidence and interactionEvidence. If unavailable, both remain null and status is blocked/pending with a degradation reason."
36
37
  },
37
38
  "updatedAt": ""
38
39
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "packageName": "xinyun-ai-init",
3
3
  "displayName": "欣芸技术开发 Agent 流初始化包",
4
- "version": "1.12.0",
4
+ "version": "1.12.1",
5
5
  "scriptVersion": "2026.07.23",
6
6
  "schemaVersion": "1",
7
7
  "defaultMode": "fast-init",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pm_zhousl/xinyun-ai-init",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "description": "欣芸技术开发 Agent 流初始化包",
5
5
  "bin": {
6
6
  "xinyun-ai-init": "bin/xinyun-ai-init.js"
@@ -6,7 +6,7 @@ const crypto = require("crypto");
6
6
 
7
7
  const root = path.resolve(__dirname, "..");
8
8
  const initRoot = path.join(root, "init", "xinyun-ai-init");
9
- const CURRENT_VERSION = "1.12.0";
9
+ const CURRENT_VERSION = "1.12.1";
10
10
 
11
11
  const checks = [];
12
12
 
@@ -1973,6 +1973,55 @@ function verifyV112Contracts() {
1973
1973
  addCheck("v1.12 rule contract", readText("init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("available-with-dependency") && readText("init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("shared-project-snapshot.json"), "v1.12 recovery rule is present");
1974
1974
  }
1975
1975
 
1976
+ function verifyV1121Contracts() {
1977
+ const requiredFiles = [
1978
+ "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md",
1979
+ "init/xinyun-ai-init/templates/provider-session-binding.template.json",
1980
+ "test-scenarios/v1.12.1-scenarios.md",
1981
+ "test-scenarios/v1.12.1-behavior-evidence.json",
1982
+ ];
1983
+ for (const file of requiredFiles) requireFile(file);
1984
+
1985
+ let manifest;
1986
+ let projectIndex;
1987
+ let initResult;
1988
+ let binding;
1989
+ let manual;
1990
+ let evidence;
1991
+ try {
1992
+ manifest = JSON.parse(readText("init/xinyun-ai-init/templates/manifest.template.json"));
1993
+ projectIndex = JSON.parse(readText("init/xinyun-ai-init/templates/project-index.template.json"));
1994
+ initResult = JSON.parse(readText("init/xinyun-ai-init/templates/init-result.template.json"));
1995
+ binding = JSON.parse(readText("init/xinyun-ai-init/templates/provider-session-binding.template.json"));
1996
+ manual = JSON.parse(readText("init/xinyun-ai-init/templates/manual-session-binding.template.json"));
1997
+ evidence = JSON.parse(readText("test-scenarios/v1.12.1-behavior-evidence.json"));
1998
+ } catch (error) {
1999
+ addCheck("v1.12.1 template JSON parse", false, error.message);
2000
+ return;
2001
+ }
2002
+
2003
+ const bindingStatuses = ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"];
2004
+ const bindingModes = ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"];
2005
+ const identityFields = ["providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "source", "verifiedAt", "evidenceHash"];
2006
+ const interactionFields = ["sendReceipt", "receiveReceipt", "transcriptHash", "messageCount", "recordedAt", "evidenceHash"];
2007
+ const bindingFields = ["provider", "providerSessionId", "roleId", "taskId", "projectRootHash", "workspaceScope", "title", "cwd", "createdAt", "identityEvidence", "interactionEvidence", "bindingMode", "bindingStatus", "boundBy", "boundAt"];
2008
+ addCheck("v1.12.1 version metadata", manifest.xinyunAiVersion === CURRENT_VERSION && initResult.targetVersion === CURRENT_VERSION && binding.targetVersion === undefined, CURRENT_VERSION);
2009
+ addCheck("v1.12.1 registry paths", manifest.v1121 && projectIndex.v1121 && manifest.v1121.providerBindings === projectIndex.v1121.providerBindings && manifest.v1121.providerBindingTemplate === projectIndex.v1121.providerBindingTemplate && manifest.roleSessions.providerSessionBindings === projectIndex.roleSessions.providerSessionBindings, "manifest/project-index provider binding paths");
2010
+ addCheck("v1.12.1 binding fields", bindingFields.every((field) => Object.prototype.hasOwnProperty.call(binding, field)), "canonical provider binding fields");
2011
+ addCheck("v1.12.1 binding enums", JSON.stringify(binding.bindingStatusEnum) === JSON.stringify(bindingStatuses) && bindingModes.includes(binding.bindingMode), "binding modes and statuses");
2012
+ addCheck("v1.12.1 evidence fields", identityFields.every((field) => Object.prototype.hasOwnProperty.call(binding.identityEvidence, field)) && interactionFields.every((field) => Object.prototype.hasOwnProperty.call(binding.interactionEvidence, field)), "identity and interaction evidence fields");
2013
+ addCheck("v1.12.1 conservative template", binding.providerSessionId === null && binding.bindingStatus === "pending" && binding.executionEligible === false && binding.fakeProviderSessionIdProhibited === true, "provider ID and execution defaults");
2014
+ addCheck("v1.12.1 manual compatibility", manual.providerSessionId === null && manual.bindingMode === "manual" && manual.executionEligible === false && manual.fakeSessionIdProhibited === true && manual.evidenceRequiredFields.includes("providerSessionId"), "manual binding remains gated");
2015
+ addCheck("v1.12.1 init-result link", initResult.v1121 && initResult.v1121.providerSessionBindingsPath === manifest.v1121.providerBindings && initResult.v1121.providerSessionBindingTemplate === manifest.v1121.providerBindingTemplate && initResult.v1121.fakeProviderSessionIdProhibited === true, "init-result provider binding link");
2016
+ const scenarioText = readText("test-scenarios/v1.12.1-scenarios.md");
2017
+ const scenarioIds = Array.from({ length: 13 }, (_, index) => 146 + index);
2018
+ addCheck("v1.12.1 scenarios", scenarioIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("providerSessionId=null"), "scenarios 146-158");
2019
+ addCheck("v1.12.1 honest behavior evidence", evidence.version === CURRENT_VERSION && evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && JSON.stringify(evidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(scenarioIds), "real host evidence status");
2020
+ addCheck("v1.12.1 no fabricated IDs", evidence.scenarios.every((scenario) => scenario.providerSessionId === null && scenario.sessionId === null && scenario.result === "not-verified" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0), "provider session IDs remain null without host evidence");
2021
+ const ruleText = readText("init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md");
2022
+ addCheck("v1.12.1 rule contract", ["providerSessionId", "canonical", "identityEvidence", "interactionEvidence", "exclusive occupancy", "Do not fabricate"].every((term) => ruleText.includes(term)), "provider session rule contract");
2023
+ }
2024
+
1976
2025
  function main() {
1977
2026
  requireFile("bin/xinyun-ai-init.js");
1978
2027
  requireFile("init/xinyun-ai-init/README.md");
@@ -1993,6 +2042,7 @@ function main() {
1993
2042
  verifyV19SessionReuseText();
1994
2043
  verifyV110Contracts();
1995
2044
  verifyV112Contracts();
2045
+ verifyV1121Contracts();
1996
2046
  verifyTestScenarios();
1997
2047
  verifyJsonAndMarkdown();
1998
2048
 
@@ -5,7 +5,7 @@ const os = require("os");
5
5
  const path = require("path");
6
6
  const { spawnSync } = require("child_process");
7
7
 
8
- const VERSION = "1.12.0";
8
+ const VERSION = "1.12.1";
9
9
  const checks = [];
10
10
 
11
11
  function parseArgs(argv) {
@@ -239,6 +239,7 @@ function validatePackageFiles(root, target, isTarball) {
239
239
  "init/xinyun-ai-init/templates/archive-transaction.template.json",
240
240
  "init/xinyun-ai-init/templates/role-execution.template.md",
241
241
  "init/xinyun-ai-init/templates/role-session-binding.template.json",
242
+ "init/xinyun-ai-init/templates/provider-session-binding.template.json",
242
243
  "init/xinyun-ai-init/templates/coordination-project-facts.template.json",
243
244
  "init/xinyun-ai-init/templates/coordination-change-ledger.template.json",
244
245
  "init/xinyun-ai-init/templates/coordination-contract-snapshot.template.json",
@@ -778,6 +779,36 @@ function validateV112Content(root, target) {
778
779
  addCheck(target, "v1.12.rule", "content", readText(root, "init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("available-with-dependency") && readText(root, "init/xinyun-ai-init/rules/v1.12.0-recovery.md").includes("sessionId=null") ? "pass" : "fail", "v1.12.0-recovery.md", "contract", "preflight and no fake IDs", "scanned", "v1.12 rule contract checked.", "Restore the v1.12 rule contract.");
779
780
  }
780
781
 
782
+ function validateV1121Content(root, target) {
783
+ const requiredFiles = [
784
+ "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md",
785
+ "init/xinyun-ai-init/templates/provider-session-binding.template.json",
786
+ "test-scenarios/v1.12.1-scenarios.md",
787
+ "test-scenarios/v1.12.1-behavior-evidence.json",
788
+ ];
789
+ for (const file of requiredFiles) requireFile(root, target, file);
790
+ const manifest = readJson(root, "init/xinyun-ai-init/templates/manifest.template.json");
791
+ const projectIndex = readJson(root, "init/xinyun-ai-init/templates/project-index.template.json");
792
+ const initResult = readJson(root, "init/xinyun-ai-init/templates/init-result.template.json");
793
+ const binding = readJson(root, "init/xinyun-ai-init/templates/provider-session-binding.template.json");
794
+ const manual = readJson(root, "init/xinyun-ai-init/templates/manual-session-binding.template.json");
795
+ const evidence = readJson(root, "test-scenarios/v1.12.1-behavior-evidence.json");
796
+ const statuses = ["pending", "validating", "bound", "blocked", "rejected", "released", "conflict", "recovery-required"];
797
+ const modes = ["auto-created", "auto-reused", "manual", "recovery", "local-degraded"];
798
+ const identityFields = ["providerSessionId", "projectRootHash", "workspaceScope", "roleId", "taskId", "title", "cwd", "source", "verifiedAt", "evidenceHash"];
799
+ const interactionFields = ["sendReceipt", "receiveReceipt", "transcriptHash", "messageCount", "recordedAt", "evidenceHash"];
800
+ const scenarioIds = Array.from({ length: 13 }, (_, index) => 146 + index);
801
+ addCheck(target, "v1.12.1.registry", "registry", manifest.v1121 && projectIndex.v1121 && manifest.v1121.providerBindings === projectIndex.v1121.providerBindings && manifest.v1121.providerBindingTemplate === projectIndex.v1121.providerBindingTemplate ? "pass" : "fail", "manifest/project-index.v1121", "provider binding paths", "same", {manifest: manifest.v1121, projectIndex: projectIndex.v1121}, "Provider binding paths are consistent.", "Synchronize provider binding paths.");
802
+ addCheck(target, "v1.12.1.schema", "schema", statuses.every((status) => binding.bindingStatusEnum.includes(status)) && modes.includes(binding.bindingMode) && identityFields.every((field) => Object.prototype.hasOwnProperty.call(binding.identityEvidence, field)) && interactionFields.every((field) => Object.prototype.hasOwnProperty.call(binding.interactionEvidence, field)) ? "pass" : "fail", "provider-session-binding.template.json", "binding schema", "complete", binding, "Provider binding schema is complete.", "Complete provider binding evidence fields and enums.");
803
+ addCheck(target, "v1.12.1.gated-default", "schema", binding.providerSessionId === null && binding.bindingStatus === "pending" && binding.fakeProviderSessionIdProhibited === true && manual.providerSessionId === null && manual.executionEligible === false ? "pass" : "fail", "provider/manual binding templates", "default gate", "null/pending/false", {binding: binding, manual: manual}, "Bindings default to a conservative state.", "Do not fabricate provider session IDs.");
804
+ addCheck(target, "v1.12.1.init-result", "registry", initResult.v1121 && initResult.v1121.providerSessionBindingsPath === manifest.v1121.providerBindings && initResult.v1121.providerSessionBindingTemplate === manifest.v1121.providerBindingTemplate ? "pass" : "fail", "init-result.template.json", "v1121", "registered provider binding links", initResult.v1121, "Init result links provider binding.", "Synchronize init-result provider links.");
805
+ const scenarioText = readText(root, "test-scenarios/v1.12.1-scenarios.md");
806
+ addCheck(target, "v1.12.1.scenarios", "scenario", scenarioIds.every((id) => scenarioText.includes(`## ${id}.`)) && scenarioText.includes("providerSessionId=null") ? "pass" : "fail", "v1.12.1-scenarios.md", "scenarioIds", "146-158", "scanned", "Provider binding scenarios are registered.", "Add all provider binding scenarios.");
807
+ addCheck(target, "v1.12.1.behavior-evidence", "evidence", evidence.version === VERSION && evidence.evidenceType === "not-verified" && evidence.realAiSessionVerified === false && evidence.publishBlocked === true && JSON.stringify(evidence.scenarios.map((scenario) => scenario.scenarioId)) === JSON.stringify(scenarioIds) && evidence.scenarios.every((scenario) => scenario.providerSessionId === null && scenario.sessionId === null && scenario.result === "not-verified" && scenario.sensitiveScan && scenario.sensitiveScan.status === "pass" && scenario.sensitiveScan.matches.length === 0) ? "pass" : "fail", "v1.12.1-behavior-evidence.json", "realAiSessionVerified/result", "not-verified with null IDs", evidence, "Unavailable host evidence is honest.", "Do not fabricate real provider session evidence.");
808
+ const ruleText = readText(root, "init/xinyun-ai-init/rules/v1.12.1-provider-session-binding.md");
809
+ addCheck(target, "v1.12.1.rule", "content", ["providerSessionId", "canonical", "identityEvidence", "interactionEvidence", "exclusive occupancy", "Do not fabricate"].every((term) => ruleText.includes(term)) ? "pass" : "fail", "v1.12.1-provider-session-binding.md", "contract", "canonical identity and evidence gate", "scanned", "Provider binding rule is present.", "Restore provider binding rules.");
810
+ }
811
+
781
812
  function validateJsonFiles(root, target) {
782
813
  const jsonFiles = [
783
814
  "package.json",
@@ -833,6 +864,7 @@ function validateRoot(root, target, isTarball = false) {
833
864
  validateV110Content(root, target);
834
865
  validateV111Content(root, target);
835
866
  validateV112Content(root, target);
867
+ validateV1121Content(root, target);
836
868
  validateJsonFiles(root, target);
837
869
  }
838
870
 
@@ -0,0 +1,27 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "version": "1.12.1",
4
+ "evidenceType": "not-verified",
5
+ "executionMode": "host-capability-unavailable",
6
+ "realAiSessionVerified": false,
7
+ "publishBlocked": true,
8
+ "provider": "codex",
9
+ "providerSessionIdPolicy": "providerSessionId remains null until a provider canonical session ID and both evidence groups are verified",
10
+ "fixture": "isolated package fixture only; no real business project mutation",
11
+ "forbiddenOperations": ["database-connection", "sql", "business-file-write", "git-write", "dependency-install", "npm-publish"],
12
+ "scenarios": [
13
+ {"scenarioId":146,"sessionId":null,"providerSessionId":null,"input":"Verify canonical provider session identity.","expectedOutput":"not-verified","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
14
+ {"scenarioId":147,"sessionId":null,"providerSessionId":null,"input":"Reject ordinary thread ID as provider session.","expectedOutput":"blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
15
+ {"scenarioId":148,"sessionId":null,"providerSessionId":null,"input":"Reject another project identity.","expectedOutput":"blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
16
+ {"scenarioId":149,"sessionId":null,"providerSessionId":null,"input":"Reject role or task mismatch.","expectedOutput":"blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
17
+ {"scenarioId":150,"sessionId":null,"providerSessionId":null,"input":"Validate title and cwd.","expectedOutput":"blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
18
+ {"scenarioId":151,"sessionId":null,"providerSessionId":null,"input":"Reject missing interaction evidence.","expectedOutput":"pending-or-blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
19
+ {"scenarioId":152,"sessionId":null,"providerSessionId":null,"input":"Verify candidate identity before reuse.","expectedOutput":"blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
20
+ {"scenarioId":153,"sessionId":null,"providerSessionId":null,"input":"Reject occupied session.","expectedOutput":"conflict-or-blocked","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
21
+ {"scenarioId":154,"sessionId":null,"providerSessionId":null,"input":"Record manual binding without evidence.","expectedOutput":"pending-or-unknown","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
22
+ {"scenarioId":155,"sessionId":null,"providerSessionId":null,"input":"Recover without duplicate tasks or sessions.","expectedOutput":"reuses-task-and-increments-attempt","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
23
+ {"scenarioId":156,"sessionId":null,"providerSessionId":null,"input":"Recover provider session after writeback failure.","expectedOutput":"recovery-required","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
24
+ {"scenarioId":157,"sessionId":null,"providerSessionId":null,"input":"Handle unsupported host.","expectedOutput":"local-degraded-with-null-ID","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null},
25
+ {"scenarioId":158,"sessionId":null,"providerSessionId":null,"input":"Check cross-file binding consistency.","expectedOutput":"not-verified","actualOutput":"not-verified","beforeSnapshotHash":"not-recorded","afterSnapshotHash":"not-recorded","changedFiles":[],"forbiddenOperations":[],"evidence":[],"sensitiveScan":{"status":"pass","matches":[]},"result":"not-verified","recordedAt":null}
26
+ ]
27
+ }
@@ -0,0 +1,42 @@
1
+ # v1.12.1 Provider Session Binding Scenarios
2
+
3
+ Scenarios 146-158 are required. A real host session must not be simulated. When the host cannot return a canonical provider session ID, the expected result is blocked/not-verified with providerSessionId=null.
4
+
5
+ ## 146. Canonical provider session ID
6
+ Verify that only a provider API returned canonical ID can enter providerSessionId.
7
+
8
+ ## 147. Ordinary thread ID rejection
9
+ Use an ordinary Codex thread ID and verify it is rejected as provider identity.
10
+
11
+ ## 148. Project identity mismatch
12
+ Use a session from another project root and verify bindingStatus=conflict or blocked.
13
+
14
+ ## 149. Role/task mismatch
15
+ Use a session whose roleId or taskId differs and verify no binding is written.
16
+
17
+ ## 150. Title and cwd validation
18
+ Verify required role title and project cwd before binding.
19
+
20
+ ## 151. Missing interaction evidence
21
+ Verify that missing send or receive receipt keeps the record pending or blocked.
22
+
23
+ ## 152. Candidate reuse verification
24
+ Verify old candidates are read and identity-checked before reuse; title alone is insufficient.
25
+
26
+ ## 153. Exclusive occupancy conflict
27
+ Verify a session occupied by another project or role is blocked and audited.
28
+
29
+ ## 154. Manual binding without evidence
30
+ Verify a user-confirmed manual entry without evidence remains pending/unknown and not executable.
31
+
32
+ ## 155. Recovery idempotency
33
+ Verify recovery reuses taskId and roleTaskId, increments attempt, and creates no duplicate task or session.
34
+
35
+ ## 156. Writeback failure recovery
36
+ Verify a created provider session with failed local writeback enters recovery-required and is queryable.
37
+
38
+ ## 157. Unsupported host degradation
39
+ Verify unsupported host records local-degraded, providerSessionId=null, nextAction, and no fake ID.
40
+
41
+ ## 158. Cross-file binding consistency
42
+ Verify provider binding, role task, assignments, task-index, and init-result agree on identity, status, attempt, and audit.