فهرست منبع

fix: bind workshop accounts to one member and release v3 skill

pengzhikang 2 ساعت پیش
والد
کامیت
ad8a5e90e4
62فایلهای تغییر یافته به همراه8134 افزوده شده و 1009 حذف شده
  1. 4 0
      AGENTS.md
  2. 44 0
      deploy/account-binding-20261112/functions.json
  3. 15 0
      docs/account-binding-fix-20261112/README.md
  4. BIN
      docs/account-binding-fix-20261112/binding-page-1440.png
  5. BIN
      docs/account-binding-fix-20261112/binding-page-320.png
  6. BIN
      docs/account-binding-fix-20261112/binding-page-390.png
  7. 60 0
      docs/account-binding-fix-20261112/browser-verification.json
  8. 45 0
      docs/account-binding-fix-20261112/deployment.json
  9. 38 0
      docs/account-binding-fix-20261112/live-verification.json
  10. BIN
      docs/account-binding-fix-20261112/members-live-1440.png
  11. 14 0
      docs/account-binding-fix-20261112/repair.json
  12. BIN
      docs/account-binding-fix-20261112/workshop-live-1440.png
  13. BIN
      docs/workshop-final-files-20261111/final-康师傅工作坊.skill
  14. 4 4
      docs/workshop-final-files-20261111/skill-package-receipt.json
  15. 3154 565
      docs/workshop-quality-r13-20261110/final-康师傅工作坊操作手册.html
  16. 55 347
      docs/workshop-quality-r13-20261110/manual/workshop-dialogue-prompts.json
  17. 12 0
      docs/workshop-v3-alignment-20261112/manual-sync.json
  18. 3362 0
      docs/workshop-v3-alignment-20261112/source-manual-v3.html
  19. 58 0
      docs/workshop-v3-alignment-20261112/source-prompts-v3.json
  20. 34 0
      docs/workshop-v3-skill-manual-release-20261112/README.md
  21. 268 0
      docs/workshop-v3-skill-manual-release-20261112/release.json
  22. 7 1
      scripts/build-workshop-skill.mjs
  23. 70 0
      scripts/deploy-account-binding.mjs
  24. 50 0
      scripts/repair-guopeng-account-link.mjs
  25. 53 0
      scripts/sync-workshop-manual-v3.mjs
  26. 2 2
      server/scripts/build.mjs
  27. 155 0
      server/src/account-binding.mjs
  28. 9 1
      server/src/bootstrap.mjs
  29. 1 1
      server/src/workshop.mjs
  30. 24 0
      server/test/account-binding-deploy.test.mjs
  31. 70 0
      server/test/account-binding.test.mjs
  32. 35 0
      server/web/account-link.html
  33. 26 21
      skills/ksf-workshop-runtime/FILES.sha256
  34. 14 8
      skills/ksf-workshop-runtime/SKILL.md
  35. 14 8
      skills/ksf-workshop-runtime/final-SKILL.md
  36. 24 12
      skills/ksf-workshop-runtime/references/identity.md
  37. 4 4
      skills/ksf-workshop-runtime/references/workshop-analysis.md
  38. 3 1
      skills/ksf-workshop-runtime/references/workshop-commercial-feasibility.md
  39. 7 3
      skills/ksf-workshop-runtime/references/workshop-concept-presentation.md
  40. 8 6
      skills/ksf-workshop-runtime/references/workshop-course-flow.md
  41. 9 7
      skills/ksf-workshop-runtime/references/workshop-deliverable-contracts.md
  42. 3 1
      skills/ksf-workshop-runtime/references/workshop-delivery.md
  43. 24 0
      skills/ksf-workshop-runtime/references/workshop-evidence-counting.md
  44. 4 2
      skills/ksf-workshop-runtime/references/workshop-feedback.md
  45. 19 5
      skills/ksf-workshop-runtime/references/workshop-opportunity-validation.md
  46. 4 2
      skills/ksf-workshop-runtime/references/workshop-output-navigation.md
  47. 2 0
      skills/ksf-workshop-runtime/references/workshop-report-design.md
  48. 3 1
      skills/ksf-workshop-runtime/references/workshop-report-parity.md
  49. 6 0
      skills/ksf-workshop-runtime/references/workshop-tasks.md
  50. 4 0
      skills/ksf-workshop-runtime/references/workshop-three-source-opportunities.md
  51. 52 0
      skills/ksf-workshop-runtime/references/workshop-v3-outputs.md
  52. 1 1
      skills/ksf-workshop-runtime/references/workshop-voc-clustering.md
  53. 35 0
      skills/ksf-workshop-runtime/scripts/course-assessment.mjs
  54. 44 0
      skills/ksf-workshop-runtime/scripts/course-deliverables.mjs
  55. 30 0
      skills/ksf-workshop-runtime/scripts/ksf-account.mjs
  56. 1 1
      skills/ksf-workshop-runtime/scripts/ksf-identity.mjs
  57. 8 4
      skills/ksf-workshop-runtime/scripts/ksf-secure.mjs
  58. 17 1
      skills/ksf-workshop-runtime/scripts/render-report-html.mjs
  59. 32 0
      skills/ksf-workshop-runtime/scripts/report-statistics.mjs
  60. 4 0
      skills/ksf-workshop-runtime/scripts/save-report.mjs
  61. 29 0
      test/workshop-account.test.js
  62. 60 0
      test/workshop-v3-assessment.test.js

+ 4 - 0
AGENTS.md

@@ -27,6 +27,10 @@
 
 `skills/ksf-workshop-runtime/SKILL.md`是标准加载入口,由`node scripts/build-workshop-skill.mjs`从final-SKILL.md同步生成,不作为独立维护稿。修改Skill细则时同步必要参考文件,再构建并校验指纹。手册提示词与`docs/workshop-quality-r13-20261110/manual/workshop-dialogue-prompts.json`保持一致,更新脚本必须写入上述final手册;页面内容调整也直接针对final手册。员工复制提示词、历史案例和部署记录放在Skill包外;Skill保留流程、方法、规则及必要接口资源。
 
+用户于2026年11月12日确认:[学员手册v3](https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html)就是新的操作手册,Skill和看板以它的流程、提示词及13份环节产出为准,不再要求回到旧14节/42轮手册。本地final手册保持上述文件名,内容由已核验v3原文同步;同步脚本为`scripts/sync-workshop-manual-v3.mjs`,提示词JSON保留v3的13段原文,旧稿在`docs/workshop-v3-alignment-20261112/retired-manual-before-v3/`归档。不要运行旧手册生成器覆盖v3,也不要擅改刘总的教学正文和复制提示词。样例参数的实际适用性、HTML入库、真实来源和员工归属由Skill落实;上线状态仍须凭实际回执。
+
 用户所说的Skill文件是完整`.skill`安装包,不是单独MD入口。当前交付包为`docs/workshop-final-files-20261111/final-康师傅工作坊.skill`;主文档或参考文件修改后,先构建再运行`scripts/package-final-workshop-skill.py`重新打包并核验。包仅包含公开清单资源,不附带本机凭据,包名保持final前缀。
 
 旧名称的手册仅作跳转入口,历史发行包、快照及安装目录不作为当前维护稿。不要用旧单轮生成器或`scripts/organize-workshop-report-site.py`覆盖当前手册。final表示用户确认的维护文件,不表示已部署线上;上线状态仍按真实部署回执说明。
+
+用户于2026年11月12日进一步确认:首次调用工作坊时可以先询问称呼和已开通的账号,完成本人账号绑定;已绑定后直接复用。此为Skill中的成果归属规则,替代此前“Skill不另设身份开场”的限制。自报用户名不等于认证;同一平台注册账号在看板只显示一个成员,旧参与者和成果通过显式关联保留,不按姓名合并、不删报告。首次确认不创建空报告,绑定冲突或未完成时暂缓成果提交。

+ 44 - 0
deploy/account-binding-20261112/functions.json

@@ -0,0 +1,44 @@
+{
+  "ok": true,
+  "readOnly": true,
+  "schemaChanges": 0,
+  "permissionsChanged": false,
+  "staticBoardDeployed": false,
+  "functions": [
+    {
+      "name": "ksfStartWorkshopSession",
+      "objectId": "yKpUay6RDG",
+      "beforeSha256": "08fb43393d88351e50e7b73d296d4675bbc22d266bc73ed22db57446fd702c68",
+      "afterSha256": "c3791b03e1183bdb1373569be0c0ebf99fe4c3b22e4261618bacb379278900c0",
+      "action": "update"
+    },
+    {
+      "name": "ksfSaveWorkshopTask",
+      "objectId": "f0faHuk5Br",
+      "beforeSha256": "5ff81e847857dd869522a065423978fc7744b3a80dad900bd18d58850d3fa531",
+      "afterSha256": "9d506a8777c8d3df918228542e259c5ac0d657f3bd549db656033e133fa8502a",
+      "action": "update"
+    },
+    {
+      "name": "ksfGetPublicBoard",
+      "objectId": "inPfC51rvn",
+      "beforeSha256": "e5067736cd5c5f6d8b2244e2a7757ed23719dc0a85b9b2fba2c0e0b83cc437fb",
+      "afterSha256": "c35cbb4af585f77b4583ae79cb906024bdc92b87fc75d0ec14d2a4d96a5e688a",
+      "action": "update"
+    },
+    {
+      "name": "ksfGetIngestContract",
+      "objectId": "dWSrHp4FfQ",
+      "beforeSha256": "84aa7bfd086308f6d59711c4c4cd6e7a068688f7b98c7b4773ba0ef1580a3586",
+      "afterSha256": "85f3a34d470a37a3b855e8619c5ffa20c69b2b9b0fceb5a6f208ba857c880b71",
+      "action": "update"
+    },
+    {
+      "name": "ksfWorkshopAccount",
+      "objectId": null,
+      "beforeSha256": null,
+      "afterSha256": "c9709c1a30e36011a69adc712d1fbecb824b5c63c6c2dbf3154d6badbe5d65d6",
+      "action": "create"
+    }
+  ]
+}

+ 15 - 0
docs/account-binding-fix-20261112/README.md

@@ -0,0 +1,15 @@
+# 一账号一成员:首次绑定与果鹏旧报告修复
+
+用户要求:首次工作坊调用先确认称呼与账号,绑定本人;同一账号在看板只能显示一位成员,保留已有报告和历史来源。
+
+生产成员/小组成果页与匿名API均已核对为27位成员。果鹏guopeng仅一人,报告JLF4v5MpyR《居家囤货|D1-01 品类全景扫描》保留原记录,关联注册成员尾码c9bf721f,原参与者尾码dc2180c1仅保留作历史提交来源。
+
+首次流程:询问称呼和已开通账号 → 本地档案复用/登记待核对资料 → account-status → 未绑定才account-prepare → 本人打开链接登录确认 → account-status回读bound及memberKey → workshop-start → 保存/精确回读/公开看板核同一memberKey。自报用户名不是认证,不向数字人提供密码或Token;绑定本身不创建报告。
+
+后台新增ksfWorkshopAccount的prepare/status/confirm。只有平台users/me验证过的本人账号可confirm,企业与名册稳定账号编号双核;会话创建与报告保存增加绑定检查。服务端显式memberKey负责统一公开投影;不按姓名合并,不改原报告正文、版本、来源、参与者键。绑定使用现有KsfRuntimeConfig私有记录,无数据库表结构变更。
+
+公开回执:deployment.json、repair.json、live-verification.json、browser-verification.json。浏览器中的成员/成果页使用真实生产数据;绑定页登录版式使用合成响应,未冒充真实员工完成确认。数字人容器新版加载尚待运维回执。
+
+部署脚本scripts/deploy-account-binding.mjs、修复脚本scripts/repair-guopeng-account-link.mjs默认均需明确plan/apply参数;已上线再次plan应全部unchanged。线上函数原包装、附件能力和权限保留。备份位于本地work/account-binding-private,属私有材料,不提交Gogs。
+
+回退须从deployment回执对应私有备份恢复函数code;先确认当前code匹配本次after哈希,再逐项恢复,禁止覆盖他人并发更新。数据回退只恢复该session.meta并移除本次新增alias配置,且仅在当前内容仍匹配本次after时执行;不删除或重建报告。首轮误带无关bootstrap调用曾回退,最终部署已修正并通过公开接口及浏览器复验。

BIN
docs/account-binding-fix-20261112/binding-page-1440.png


BIN
docs/account-binding-fix-20261112/binding-page-320.png


BIN
docs/account-binding-fix-20261112/binding-page-390.png


+ 60 - 0
docs/account-binding-fix-20261112/browser-verification.json

@@ -0,0 +1,60 @@
+{
+  "ok": true,
+  "results": [
+    {
+      "route": "/members",
+      "count": 27,
+      "guopeng": [
+        {
+          "id": "platform-account:bbdeba81de5687b88b54ff70fa1cafdbcdbe12c4d6488e33e253c9ecc9bf721f",
+          "name": "果鹏",
+          "artifactIds": [
+            "JLF4v5MpyR"
+          ]
+        }
+      ],
+      "screenshot": "docs/account-binding-fix-20261112/members-live-1440.png",
+      "realProductionData": true
+    },
+    {
+      "route": "/workshop",
+      "count": 27,
+      "guopeng": [
+        {
+          "id": "platform-account:bbdeba81de5687b88b54ff70fa1cafdbcdbe12c4d6488e33e253c9ecc9bf721f",
+          "name": "果鹏",
+          "artifactIds": [
+            "JLF4v5MpyR"
+          ]
+        }
+      ],
+      "screenshot": "docs/account-binding-fix-20261112/workshop-live-1440.png",
+      "realProductionData": true
+    },
+    {
+      "route": "binding-page",
+      "width": 1440,
+      "overflow": 0,
+      "screenshot": "docs/account-binding-fix-20261112/binding-page-1440.png",
+      "syntheticLoginUI": true,
+      "realBindingConfirmed": false
+    },
+    {
+      "route": "binding-page",
+      "width": 390,
+      "overflow": 0,
+      "screenshot": "docs/account-binding-fix-20261112/binding-page-390.png",
+      "syntheticLoginUI": true,
+      "realBindingConfirmed": false
+    },
+    {
+      "route": "binding-page",
+      "width": 320,
+      "overflow": 0,
+      "screenshot": "docs/account-binding-fix-20261112/binding-page-320.png",
+      "syntheticLoginUI": true,
+      "realBindingConfirmed": false
+    }
+  ],
+  "errors": []
+}

+ 45 - 0
docs/account-binding-fix-20261112/deployment.json

@@ -0,0 +1,45 @@
+{
+  "ok": true,
+  "readOnly": false,
+  "schemaChanges": 0,
+  "permissionsChanged": false,
+  "staticBoardDeployed": false,
+  "functions": [
+    {
+      "name": "ksfStartWorkshopSession",
+      "objectId": "yKpUay6RDG",
+      "beforeSha256": "08fb43393d88351e50e7b73d296d4675bbc22d266bc73ed22db57446fd702c68",
+      "afterSha256": "c3791b03e1183bdb1373569be0c0ebf99fe4c3b22e4261618bacb379278900c0",
+      "action": "update"
+    },
+    {
+      "name": "ksfSaveWorkshopTask",
+      "objectId": "f0faHuk5Br",
+      "beforeSha256": "5ff81e847857dd869522a065423978fc7744b3a80dad900bd18d58850d3fa531",
+      "afterSha256": "9d506a8777c8d3df918228542e259c5ac0d657f3bd549db656033e133fa8502a",
+      "action": "update"
+    },
+    {
+      "name": "ksfGetPublicBoard",
+      "objectId": "inPfC51rvn",
+      "beforeSha256": "e5067736cd5c5f6d8b2244e2a7757ed23719dc0a85b9b2fba2c0e0b83cc437fb",
+      "afterSha256": "c35cbb4af585f77b4583ae79cb906024bdc92b87fc75d0ec14d2a4d96a5e688a",
+      "action": "update"
+    },
+    {
+      "name": "ksfGetIngestContract",
+      "objectId": "dWSrHp4FfQ",
+      "beforeSha256": "84aa7bfd086308f6d59711c4c4cd6e7a068688f7b98c7b4773ba0ef1580a3586",
+      "afterSha256": "85f3a34d470a37a3b855e8619c5ffa20c69b2b9b0fceb5a6f208ba857c880b71",
+      "action": "update"
+    },
+    {
+      "name": "ksfWorkshopAccount",
+      "objectId": "bTjPEnHYWF",
+      "beforeSha256": null,
+      "afterSha256": "c9709c1a30e36011a69adc712d1fbecb824b5c63c6c2dbf3154d6badbe5d65d6",
+      "action": "create"
+    }
+  ],
+  "readbackVerified": true
+}

+ 38 - 0
docs/account-binding-fix-20261112/live-verification.json

@@ -0,0 +1,38 @@
+{
+  "ok": true,
+  "at": "2026-11-12T05:52:02.994Z",
+  "memberCount": 27,
+  "publicGroupMemberCount": 27,
+  "guopengMemberCount": 1,
+  "guopengReportId": "JLF4v5MpyR",
+  "guopengReportTitle": "居家囤货|D1-01 品类全景扫描",
+  "canonicalMemberKey": "platform-account:bbdeba81de5687b88b54ff70fa1cafdbcdbe12c4d6488e33e253c9ecc9bf721f",
+  "reportMemberKey": "platform-account:bbdeba81de5687b88b54ff70fa1cafdbcdbe12c4d6488e33e253c9ecc9bf721f",
+  "originalArtifactByteEquivalent": true,
+  "reportSha256": "bd75b04b814b4843825177693e082c04f3fba6499b23ca776bf991d0c943e5e8",
+  "originalParticipantKeyPreserved": true,
+  "accountBindingContract": {
+    "schema": "ksf.workshop-account-binding.v1",
+    "enabled": true,
+    "requiredFor": [
+      "fmode"
+    ],
+    "function": "ksfWorkshopAccount",
+    "firstUse": "confirm-display-name-and-account",
+    "proof": "platform-session",
+    "canonicalMember": "platform-account",
+    "oneMemberPerAccount": true,
+    "unboundSubmission": "reject",
+    "historicalAttributionPreserved": true
+  },
+  "confirmationPage": {
+    "status": 200,
+    "contentType": "text/html; charset=utf-8",
+    "csp": "default-src 'none'; script-src 'nonce-DVAu0+yEcUyzJcoJWxZ6P10g5qkjFAGZ'; style-src 'unsafe-inline'; connect-src 'self' https://server.fmode.cn; base-uri 'none'; form-action 'self'; frame-ancestors 'none'",
+    "nonceInjected": true
+  },
+  "anonymousConfirmStatus": 401,
+  "staticBoardDeployed": false,
+  "employeeInteractiveConfirmation": "pending-real-first-use",
+  "containerSkillLoaded": "not-accessible-from-this-session"
+}

BIN
docs/account-binding-fix-20261112/members-live-1440.png


+ 14 - 0
docs/account-binding-fix-20261112/repair.json

@@ -0,0 +1,14 @@
+{
+  "ok": true,
+  "readOnly": false,
+  "sessionId": "z-nFIa3y5m",
+  "artifactId": "JLF4v5MpyR",
+  "memberKey": "platform-account:bbdeba81de5687b88b54ff70fa1cafdbcdbe12c4d6488e33e253c9ecc9bf721f",
+  "participantKeyPreserved": true,
+  "reportContentHash": "ffc7bc0fc57f297c0df07f82c7961a6bbddb1dc30dc13da1ab062bb9e0082cbf",
+  "reportWrites": 0,
+  "accountChanges": 0,
+  "sessionChange": true,
+  "aliasChange": true,
+  "readbackVerified": true
+}

BIN
docs/account-binding-fix-20261112/workshop-live-1440.png


BIN
docs/workshop-final-files-20261111/final-康师傅工作坊.skill


+ 4 - 4
docs/workshop-final-files-20261111/skill-package-receipt.json

@@ -1,10 +1,10 @@
 {
   "ok": true,
   "file": "final-康师傅工作坊.skill",
-  "bytes": 353775,
-  "sha256": "298b61f280425b07a547082518c9507e188bcbcf24ddb4c93fd60ebc815779e3",
-  "publicFilesVerified": 50,
-  "entrySha256": "183b5b8248cf4e7d45b3f62a8cae67dd85b9c86dda22b1e19dadffff2dd4fa12",
+  "bytes": 374834,
+  "sha256": "c7fc15321281064deec680f30451757218b393796de8085650f7def178c6764d",
+  "publicFilesVerified": 55,
+  "entrySha256": "b798b417de70c0d9c15d1eefe72ca069179bb3d2686402399f3aa4e3830c103b",
   "canonicalEntry": "skills/ksf-workshop-runtime/final-SKILL.md",
   "archiveEntry": "ksf-workshop-runtime/SKILL.md",
   "format": "zip-compatible .skill",

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 3154 - 565
docs/workshop-quality-r13-20261110/final-康师傅工作坊操作手册.html


+ 55 - 347
docs/workshop-quality-r13-20261110/manual/workshop-dialogue-prompts.json

@@ -1,351 +1,59 @@
 {
-  "schema": "ksf.workshop-dialogue-prompts.v1",
-  "revision": "r13-report-html-review-20261111",
-  "usage": "按当前环节只取对应段落。shared通用约定只在确定课题的开场与收尾展示,后续各轮持续沿用,不再拼接到提示词。各轮在同一对话内接续;员工可直接反馈,不要求逐字发送。段落是推荐互动节奏,不覆盖员工已授权的连续执行范围。",
-  "shared": {
-    "opening": "使用康师傅产品创新工作坊Skill,沿用当前员工本人的课题、前序成果及已给条件。已有信息不要重复问;只问会改变本轮路线且必须由我回答的问题,同时继续可独立完成的工作。",
-    "continuation": "继续同一员工、同一课题的当前环节,承接上轮结果和我的实际反馈;未给的选择不代填,只回核受影响内容。",
-    "evidence": "先结合已有数据取证,自查会改变判断的缺口,按实际接入能力调用VOC或其他可用通道补证。以同一使用任务比较我方现品、直接竞品和真实替代办法,分别呈现品牌宣称、用户实际体验与研究解释;满意收益与痛点并看。关键判断旁展示逐字原句、具体产品对照及相反材料,注明来源链接、对象、时间、有效样本和适用范围;比例注明n/N,不把互动热度或提及率当销量、人数或总体需求强度。解释依据如何影响产品取舍,事实、推断、产品设定与实测分开;相反材料足以削弱判断时要修订推荐。",
-    "stop": "完成本轮有用结果后停下,说明下一轮要解决什么;不自动执行下一轮,不替我生成反馈。已有实质成果按Skill及时保存,单纯澄清不建空报告。",
-    "delivery": "先按本环节细则自检实质内容、关键依据、产品取舍和待验证问题,不合格先补研究或修正文;HTML排版和保存成功不代表内容达标。后续每份有实质内容的报告默认交独立可读、美观的HTML,聊天中先给关键判断、取舍与下一项判别,再发实际HTML预览/文件和看板链接供我核对;不要只发文字摘要或让员工另行要求出报告。HTML与入库rawText/report使用同版内容:首屏关键判断与成立条件,正文按当前环节展开;原话用自适应高度卡片,来源、正文、原始链接分段并以细线分隔,产品对照和适用范围紧邻判断,完整口径后置。沿当前员工本人、原课题及报告系列核分类、正文、来源、版本和文件字节,同步看板;小组只组织展示。标清课堂稿与本版待核点,等待我的真实反馈,实质修订更新同系列版本及HTML;打开链接、保存成功或普通“继续”不算确认,也不代表正式批准。单纯澄清不建空报告;保存/文件/展示未接通分别说明,不编造编号或链接。更新七类个人交付清单,不重复新建已有成果;最终方案出图仍须明确确认具体方案及版本。"
-  },
-  "steps": {
-    "topic": {
-      "title": "确定本组研究课题",
-      "references": [
-        "workshop-intake.md"
-      ],
-      "rounds": [
-        {
-          "title": "确认称呼与登录账号",
-          "purpose": "account-binding",
-          "task": "使用康师傅产品创新工作坊Skill。本轮先确认我的称呼与账号,不开始课题研究。组织者已预先创建员工账号,登录用户名为姓名拼音小写。\n\n请先只问我:\"希望我怎么称呼你?你用于登录fmode企业网站的账号是什么?请按‘称呼:王静;账号:wangjing’这样的格式回复,不要提供密码或验证码。\" 问完等我回答。若我已明确提供两项则直接处理,只缺一项就只问缺项,不自行按姓名生成账号,不追加手机号、部门、岗位等个人问题。\n\n收到回答后,用当前环境实际提供的可信登录上下文核对账号与康师傅企业归属,将我提供的称呼关联到本人账号;后续研究和成果沿用同一员工归属。账号名册只用于核存在性,不能替代本人登录核验。自报账号与当前登录账号冲突时先说明,不切换或覆盖他人归属。\n\n区分账号核对与称呼保存:有适用的受控接口时保存并回读同一账号的称呼;只有聊天记忆或本地记录时说明‘称呼仅在当前对话使用,待同步至看板’,取不到可信身份时说明‘账号归属待核对’,不宣称绑定成功。不要为称呼创建工作坊会话或空报告,也不修改平台账号姓名。\n\n最后简短反馈称呼、账号及实际核对/同步结果,然后停下,等我发送下一轮;已提供的信息后续不再问。",
-          "feedback": "回复本人希望使用的称呼及实际登录账号,不提供密码;看完核对结果,再复制第二轮开始课题。"
-        },
-        {
-          "title": "把课题变成可研究的问题",
-          "task": "从我已提供的本组课题与材料中提取:要支持的产品决策、目标人群及使用任务、包含/排除的面类范围、已知企业约束。先给一个清晰的问题表述,说明研究结果要帮助比较或决定什么、哪些条件会改变选材;信息不足时只问决定性的缺项,不自设价格、产线或公司标准。未提供课题时先请我给出课题原文,不虚构研究对象。",
-          "feedback": "看研究范围是否偏题;可直接补充课题,或指出必须保留/排除的对象与条件。"
-        },
-        {
-          "title": "按反馈固定研究范围",
-          "task": "根据我的实际反馈整理研究简报:本题业务问题、范围、真实约束、我已作出的选择、尚未确定的条件及首节要比较的对象。标清每项条件来自员工输入、已有资料还是待证假设,给简短可接续摘要。仅我明确给出的条件才固定;其余未知保留,不虚构确认。本轮不进入品类分析,也不建空报告或虚构学员/小组。",
-          "feedback": "核对简报是否准确;可直接改一句范围,再进入品类全景。"
-        }
-      ]
-    },
-    "category": {
-      "title": "建立品类全景",
-      "references": [
-        "workshop-category-scan.md"
-      ],
-      "rounds": [
-        {
-          "title": "先看品类与代表对象",
-          "task": "从本题范围出发,先宽查再核代表商品与用户材料,按实现方式、使用条件与实际替代的差异选材,说明关键分支选入或缺失的原因。给出供给树初稿(产品形态—实现条件—风味/规格)和需求树初稿(人群任务—触发场景—期望与代价)。列代表商品及原话/场景证据,解释分类依据、交叉标签及排除对象。不要只交检索计划;库内记录量不当市场规模,没有跨期测量不声称增长。",
-          "feedback": "看是否漏掉实际替代品或混入不该研究的对象;可指出要补的分支或使用条件。"
-        },
-        {
-          "title": "连接供需并比较取舍",
-          "task": "按反馈修正两棵树,核商品、规格、准备方式、时间与来源,补会改变判断的缺口。做供需连接表:使用任务—代表供给—当前满足—用户代价—依据及反例。比较同一任务下不同实现方式为何更适合某种条件、又牺牲什么,解释竞争发生在哪些选择之间,提出有证据的结构判断与值得继续验证的问题;未覆盖范围与市场空白分开。选出最能改变本题认识的结构差异,用同任务的代表对象解释,不能只把供需重新分类。",
-          "feedback": "看连接是否符合真实使用;可纠正供需关系,指出下一节最值得验证的结构判断。"
-        },
-        {
-          "title": "形成品类图谱报告",
-          "task": "根据实际反馈形成独立可读的品类全景报告,包含有定义与层级的供给树、需求树、代表商品、供需连接表、影响后续研究的结构判断及未覆盖范围。核图谱关键分支有实际对象、供需连接有材料支持,结构判断能指向下一节具体比较。保留关键依据和限制;规模/跨期资料不足时交清楚的结构分析,未完成的市场测量另列。将实际章节对应市场分析交付物,给下一节需复核的主张。 首屏提炼本题最有用的品类结构判断;图谱分支连真实对象,选能解释差异的代表产品对照,说明结构怎样改变后续研究方向。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。打开报告检查图谱与正文;有误可指出具体分支,不必重跑整节。"
-        }
-      ]
-    },
-    "rules": {
-      "title": "固定证据与判断规则",
-      "references": [
-        "workshop-verification.md"
-      ],
-      "rounds": [
-        {
-          "title": "先查会影响判断的证据问题",
-          "task": "回读前序图谱及关键原件,优先核会改变分类、比较或后续取舍的主张,实际查对象/规格、时间、来源、去重和统计分母。给出原主张—核验依据—发现—对判断的影响,说明哪些可以沿用,哪些需修正;来源间是否独立也要核实。按实际入口核工具能力,不用泛化检查表代替对本题的检查。",
-          "feedback": "看证据问题是否影响你关心的判断;可补充企业认可的资料标准或必须复核的主张。"
-        },
-        {
-          "title": "做可复用的配置与提示词",
-          "task": "结合实际核查结果制定本题验证配置卡,明确主张所需证据、对象身份、时效、去重、分母、引用、冲突处理及复核方法。给检索、编码、反证审查、修订四段可直接复制的本题提示词,带实际输入与回传结构。若有真实第二模型入口,用同版材料独立复核;无入口则标待执行,继续原件和计算核查,不把同一模型扮演两角当独立验证。",
-          "feedback": "看规则是否适合课题;可指出过严/过松的资格条件或补充真实复核意见。"
-        },
-        {
-          "title": "修正前序并交验证配置报告",
-          "task": "按反馈定稿验证配置卡与四类提示词资产,写清版本及适用范围;将实际发现的错误修回前序图谱,保存受影响报告的真实修订。交配置、核查结果、实质修订和第二模型执行/分歧状态;检查本题材料代入后可直接执行,关键规则能说明接受、降级或排除的理由,不用空白模板冒充已核。后续沿用本卡,不要求员工每节重述规则。 用本题一项真实判断示范规则怎样接受、降级或排除证据,让配置卡可执行;核查前后改变了哪条图谱认识要并列可读。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看规则及前序修订是否对应;正常技术核查由数字人自行完成。"
-        }
-      ]
-    },
-    "competitors": {
-      "title": "比较竞品与产品取舍",
-      "references": [
-        "workshop-competitor-landscape.md"
-      ],
-      "rounds": [
-        {
-          "title": "核对具体商品与比较基准",
-          "task": "依据本题供需图谱与验证配置,先查我方相关系列、直接竞品及用户实际替代品;按会影响选择的差异选对象,不只选记录最多或最好取得的品牌。以真实商品ID连接规格、风味、准备方式、包装/组合件数、观察价及单位、原始卖点顺序和用户回应,给可比商品初表与选择理由。不同规格、价格条件分列,不拼接不存在的SKU;新品需首发依据。",
-          "feedback": "看是否漏了关键竞品或比较条件不公平;可补具体商品或替代方式。"
-        },
-        {
-          "title": "解释优劣并提出可验证假设",
-          "task": "按反馈补齐关键对照,围绕相同使用任务比较各方案在什么条件下更合适、收益和代价是什么、哪些证据会推翻建议,不能只列参数或通用优缺点;区分商品宣称、用户原话与研究推断。核我方已有覆盖,指出值得研究的具体改动及代价;为痛点假设保留稳定键、支持、反例、替代解释和最小判别问题。风味结构不当增长,样本未覆盖不当市场空白。优先面对最有力的现售替代,说明它在哪些条件下已经足够;没有比较依据的改动只列假设,不直接推荐新品。",
-          "feedback": "看取舍是否贴近业务;可指出假设不成立的条件或需要保留的体验。"
-        },
-        {
-          "title": "完成竞品报告与假设初稿",
-          "task": "按实际反馈交竞品图谱/比较报告:完整商品对照、风味与卖点组合、使用及购买条件、用户利弊、我方覆盖、关键判断和稳定假设清单。关键差异须落到具体商品及对应依据,讲清相对我方现品/替代品的增量或局限。将假设标为待证,给后续验证问题。同步完善市场分析中的竞品与趋势章节,只有可比跨期依据才能写趋势。 按真实使用任务比较直接竞品、我方现品和替代办法;定位自述与用户感知分列,满意收益与失败条件配对,说明哪些差异只是宣称、哪些已获体验证据。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看具体商品和假设是否可追溯;下一节再收敛假设与任务。"
-        }
-      ]
-    },
-    "tasks": {
-      "title": "定稿假设与研究任务",
-      "references": [
-        "workshop-research-tasking.md"
-      ],
-      "rounds": [
-        {
-          "title": "收敛假设与研究先后",
-          "task": "接续竞品报告和稳定假设键,逐项建议保留、重写、合并或暂缓,说明依据及对产品选择的影响;优先识别得到不同答案就会改变产品方向的未知,区分当前判断与研究优先级。保留全池与反对证据,指出哪些取舍确实需业务方回答,给建议和影响,不把所有假设原样转成待办。",
-          "feedback": "可调整最重要的研究问题、合并假设,或说明暂不研究的范围。"
-        },
-        {
-          "title": "落实为可以执行的研究任务",
-          "task": "依据实际反馈为保留假设生成任务卡:要判别的问题、目标对象/场景、所需字段、已有可复用材料、查询与同义词、支持/反证路径、资格规则、停止条件和回传结构,绑定验证配置版本。说明何种观察支持、削弱或区分假设;停止条件围绕判断所需的新信息,不以凑采集条数替代。按实际能力分可执行与受阻项;技术查询与选材由你完成,只向我核必须由企业提供的限制。优先补建议中最弱的论证关系,写明不同结果将改变哪项判断;不是把空字段逐个变成调研任务。",
-          "feedback": "看任务能否回答假设;可修正对象或停止条件,不必代写检索词。"
-        },
-        {
-          "title": "交任务包和市场阶段报告",
-          "task": "完成假设清单、增强AI自驱任务包及市场阶段汇总报告,保留原假设键、变更原因、任务对应和待交接材料。核每项任务都有明确判别目标,返回材料能改变或确认哪项产品判断,先后顺序有理由;市场报告整合实际发现,不只重列待办。说明任务卡已保存、实际投递、排程及真实运行各自状态;保存任务不称后台已启动,不擅自创建夜间调度。本轮停在任务包,下一环节再实际执行研究。 市场汇总先呈现已知结构、任务矛盾及其产品含义,再交逐假设判别任务;每项说明哪种返回结果会改变路线,不把任务表当研究结论。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。核对研究先后与交接内容;准备好后进入实际补证。"
-        }
-      ]
-    },
-    "research": {
-      "title": "按假设补证与预聚类",
-      "references": [
-        "workshop-autonomous-research.md"
-      ],
-      "rounds": [
-        {
-          "title": "执行首批研究并看证据方向",
-          "task": "接续已定任务包和验证配置,实际回读原件并执行当前可用的研究,先给足以判断方向的一批材料与逐假设初步回应。按假设覆盖关键商品/替代、场景及满意/不满/分歧,说明已读范围与偏差,不能只堆易取得的短评。复用与本轮新增分开,核商品/规格、平台、时间及真实原话;关键缺口按现有权限自主补证,不只交研究计划。单项受阻时继续不依赖它的工作,不编采集结果。",
-          "feedback": "看证据是否对题;可指出要增加的场景、错误解释或与你经验冲突的材料。"
-        },
-        {
-          "title": "补反证并形成预聚类",
-          "task": "按反馈定向补会改变假设的支持、反证及替代解释,不重复已完成的查询。按假设/场景预聚类,保留实际成员、原话、来源和稳定主题键;从声明的合格集合计算n/N,区分提及与需求强弱。给逐假设支持/修正/反驳/未知及原因,说明信息资格、覆盖边界与需验收的问题。涉及产品机制时检索适用的技术原文、标准或具体产品说明,交代对象和条件;消费者体验不代证工艺因果。",
-          "feedback": "可纠正主题合并/拆分,指出是否遗漏满意者或重要反例。"
-        },
-        {
-          "title": "交调研报告与证言材料",
-          "task": "整合实际研究为调研报告、用户证言池、社媒场景初稿、预聚类及提及率初表;逐假设说明得到什么、改变了什么、尚不能判断什么。每个关键回应连到实际材料、反例及对后续选择的影响;核提及率可由合格成员回算,定性线索不写成总体需求率。给源记录/原件索引和缺口,不用采集条数代替洞察。大批明细留可追溯位置,主文交关键原话与产品含义,供下一节验收。 关键假设用“支持材料—相反材料—本轮修订—产品含义”展开,原话卡与解释相邻;采集范围和未覆盖范围明确,不以样本多代替论证。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看研究报告与原话是否对应;未补齐项保留限制,进入验收。"
-        }
-      ]
-    },
-    "accept": {
-      "title": "验收调研材料",
-      "references": [
-        "workshop-research-acceptance.md"
-      ],
-      "rounds": [
-        {
-          "title": "实际核查材料与关键结论",
-          "task": "对调研报告逐假设核回应,优先回读决定性主张的原件,查来源、对象/规格、时间、去重、分母及支持/反例。特别检查原句是否真的支持报告解释、反例是否改变适用范围。给实际查到的问题和对结论的影响,将材料分可用、有限可用、排除,并提出修订;文件齐全不等于内容合格,计划或模拟材料不当真实研究。同时检查材料与结论之间是否跳步,原话存在不等于所推方案成立;把会影响候选去向的问题修回正文。",
-          "feedback": "可补真实原件、纠正材料资格,或指出必须继续核查的结论。"
-        },
-        {
-          "title": "修订受影响报告并交验收结果",
-          "task": "按实际反馈修复错误或补决定性证据,回算受影响统计、修正假设回应,并保存相应报告版本。交战报/调研验收报告、可用材料索引、限制与缺口以及进入需求分析的证据集合;注明关键问题修正前后如何影响判断,有效分析继续保留。结构完整、内容合格、保存展示和真实业务验证分别说明;不把验收记录替代原调研正文,也不为通过而删去不利证据。 以受影响的业务判断组织验收:哪些可用、哪些降级及其具体原因,最重要修订前后并列,完整技术核查后置。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看可引用范围与待核项;可以沿合格材料进入用户需求分析。"
-        }
-      ]
-    },
-    "voc": {
-      "title": "识别用户任务与痛点",
-      "references": [
-        "workshop-voc-clustering.md"
-      ],
-      "rounds": [
-        {
-          "title": "从原话还原真实使用事件",
-          "task": "使用验收可用集合,按真实使用任务选证言并保留语境,按人群、触发场景、任务、现有办法、期望、行为后果和情绪还原事件;未说出的身份、动机及后果不代填。给初步主题与原话对应,保留满意样本、反例和不符合解释的成员,电商体验与社媒场景分层。关键词相同不代表同一需求,用户抱怨也不直接等于新品机会。",
-          "feedback": "看事件和主题是否符合实际;可纠正使用任务或指出不同情境不应合并。"
-        },
-        {
-          "title": "比较主题、场景与需求强弱",
-          "task": "根据反馈修订四层编码、主题成员与稳定键,比较人群×场景下的任务、痛点、替代办法和取舍。解释同一表达背后是否有不同问题,以及满意者为何不受影响;说明哪些重要是基于发生条件、后果及行为,哪些仅是提及,资料不能判断强弱时保留未知。适用比例写清n/N和集合。KANO只有真实正反配对问卷才能计实测类别;否则交候选属性及问卷问题,不能冒称测得必备/魅力属性。对最关键的任务矛盾比较不同解释,说明哪些事件能区分,避免从一个抱怨直接指定配方或包装。",
-          "feedback": "可调整主题拆合与研究先后,指出哪些收益值得改、哪些体验不能牺牲。"
-        },
-        {
-          "title": "交需求报告与痛点库",
-          "task": "形成独立用户需求/社媒场景报告、可回查用户证言池、痛点库、人群×场景矩阵及真实状态的KANO表。核心主题须能沿成员原话核到任务矛盾、现有办法和产品含义,不能只列“方便/好吃”等词;解释优先研究什么、适用人群/场景、证据与反例,区别研究优先级与已验证商机。证言池与社媒场景分别对应七类交付,不用一段聊天摘要替代。 围绕真实场景中的核心矛盾组织主题,以典型事件、满意/不满对照及反例解释用户为什么选择、调整或放弃;综合画像明确为归纳,不能伪装成单个用户原话。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看原话、主题和产品含义是否连得上;下一节与实际供给对照。"
-        }
-      ]
-    },
-    "matrix": {
-      "title": "连接需求与风味供给",
-      "references": [
-        "workshop-opportunity-discovery.md"
-      ],
-      "rounds": [
-        {
-          "title": "看需求是否已被供给满足",
-          "task": "接续需求主题和具体竞品/我方商品,以会影响本题选择的需求作行、实际供给差异作列,构建需求×风味/形态/准备条件矩阵,逐格标已满足、部分满足、未知及实际依据。区分用户想要、现有产品宣称和实际体验;先查我方已有覆盖,不把样本未覆盖当行业空白。给当前有意义的比较和问题,不只画空矩阵。",
-          "feedback": "可补已有解决方案,纠正误判为空白的格子,指出关键体验约束。"
-        },
-        {
-          "title": "推演具体改动与代价",
-          "task": "按反馈重点分析需求与供给的错位,对照现有办法提出可比较的具体产品改动、用户收益、需保留体验和代价;解释改动通过什么机制改善任务、什么条件下增量不成立。风味结构与真实跨期趋势分开;比较指标须单位/时间/对象一致,跨人群或平台的独立比例不能拼成转化漏斗。对关键连接补证或降级,保留现品已能满足的反例。把目标体验落到本题相关的面体、酱料、投放、容器或选购变量,按适用机理比较收益和副作用,不只罗列“更好吃、更方便”。",
-          "feedback": "看改动是否有用且可比较;可指出应保留的方案或不接受的代价。"
-        },
-        {
-          "title": "交供需矩阵与机会初表",
-          "task": "形成需求—供给矩阵报告、适用的风味变化判断、独立指标初表与产品机会初表。每条机会线索带需求、现有替代、具体改动、预期收益、取舍及支持/反证;核线索确实来自需求与具体供给的比较,交代现品已满足的部分和仍未知的部分。未覆盖格与已证市场机会分开,给下一节三源推演所需输入。 对重点错位给“现有办法—已满足部分—剩余问题—拟改产品变量—收益与代价”的可比小表,说明矩阵空格是样本缺口还是有证据的需求错位。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看矩阵与机会线索是否有可追溯连接;下一节再形成候选卡。"
-        }
-      ]
-    },
-    "opportunities": {
-      "title": "形成候选机会池",
-      "references": [
-        "workshop-three-source-opportunities.md"
-      ],
-      "rounds": [
-        {
-          "title": "提出可比较的候选方向",
-          "task": "接续机会初表,沿S×U×C实际含义与材料交叉推演候选:具体服务谁/何时、解决什么、现有替代、产品改动、收益、保留体验和代价。候选应在服务任务、实现方式或收益机制上有实质差异,只差文案或细节的合并。核三源真实出处及共用/转引关系,不能把同一材料包装成独立交叉证据。给有内容的候选比较,不为凑数强造机会。每条说明现品为何不足、证据直接支持到哪一步、哪部分是新设想;组合调整和技术改动都须解释具体增量,不靠新颖命名。",
-          "feedback": "可合并重复方向、指出遗漏的选项或不可接受的体验损失。"
-        },
-        {
-          "title": "找最弱关系与竞争压力",
-          "task": "按反馈修订候选,逐卡核最弱的证据连接、反例、替代解释与最小判别方法。按本候选实际行业关系分析波特五力,说明哪项会影响采用、渠道、供应或竞争,复用有效公共分析但不复制泛化套话。保留暂缓和不支持方向及原因,不把研究设想称验证成功。让最强现有替代和相反材料实际挑战候选;若足以解释需求或削弱增量,就修改候选去向,不只附免责声明。",
-          "feedback": "可指出关键竞争条件、需要回核的连接,或值得保留但暂不推荐的方向。"
-        },
-        {
-          "title": "保存独立机会卡与V1候选池",
-          "task": "形成完整V1候选机会池及逐张独立机会卡,保留稳定候选键、产品设定、三源出处、共用关系、最弱环节、竞争压力及待验证问题。核每卡能说清拟改变的产品及相对现有办法的增量,最弱关系有可证伪的问题,研究任务不冒充产品机会。独立卡与汇总报告分别保存回读,未保存成功不伪填卡号;报告中设完整机会卡实质章节,不能用后台独立机会记录替代个人报告交付。证据仅够提出设想时保留探索状态,不为交报告强选主推方向;关键依据以原句和现品对照就近展示。 每条候选以问题、现有替代、具体改动、关键依据、最强反例、代价及下一判别组成可独立阅读的卡;说明候选间的依赖与互斥,推荐有条件,不能只做名称列表。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看全池是否完整、独立卡和汇总能否打开;下一节做验证与排序。"
-        }
-      ]
-    },
-    "priority": {
-      "title": "验证机会与安排优先级",
-      "references": [
-        "workshop-opportunity-validation.md"
-      ],
-      "rounds": [
-        {
-          "title": "逐候选审查证据闭环",
-          "task": "回读V1完整候选池和来源,逐项判断需求、产品改动、收益、现有替代、反证及最弱关系,优先核可能改变排序的主张和条件,交实际核查结果。真实第二模型可用时冻结同版材料独立审查并处理分歧;不可用标待执行,继续原件与逻辑核查。未做实验不写实测通过,不遗漏低优先级或未知候选。",
-          "feedback": "可补实际验证反馈,纠正证据误读或指出最重要的决策条件。"
-        },
-        {
-          "title": "比较排序与设计判别验证",
-          "task": "依据核查和实际反馈给可解释的S/A/B初排,说明排在前面的候选比其他候选强在哪里、哪些未知会使顺序反转;证据接近时可并列,未能评估的给具体待评原因。业务推进优先级、研究优先级及企业审批分开。设计最小原型对照:基准、变量、招募/条件、观察指标及决定保留/修改/否定的判别规则。仅设计时标待执行,真实已做测试按版本和条件呈现结果。验证设计细化到样品/原型版本、唯一或主要改动、操作/呈现条件、记录办法及各结果对应的决定;缺依据的门槛标待确认,不编成功指标。",
-          "feedback": "可调整真实业务约束或取舍;没有实测结果时可讨论验证方案,不虚构已测。"
-        },
-        {
-          "title": "交验证评估与优先级报告",
-          "task": "形成机会验证评估报告和完整优先级清单,每候选都有等级或待评原因、支持/反对、条件、验证设计及真实执行状态。核等级理由与证据一致,重点验证能区分候选或改变去向,不能仅写“再做调研”。记录相对V1改变了什么,区分研究建议与企业批准;与机会验证交付章节对应,承接到商业与生产回推。 重点解释排序差异来自哪项证据及什么未知会反转顺序;无真实量表不画精确雷达,测试设计与已测结果分开展示。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看等级理由与原型判别是否清楚;下一节核收入、成本与生产条件。"
-        }
-      ]
-    },
-    "feasibility": {
-      "title": "回推商业与生产条件",
-      "references": [
-        "workshop-commercial-feasibility.md"
-      ],
-      "rounds": [
-        {
-          "title": "拆实际收入、成本与工艺条件",
-          "task": "对完整候选池比较维持现状、小改、大改,精确核基准SKU规格、观察价及企业净收入路径。围绕各方案实际改动拆BOM/包材、制造换线、良率、物流、模具/一次投入、损耗退货与渠道代价,查实际设备/报价和适用官方标准。输入带来源、日期、单位、批量与适用条件,口径可比再算。先交可核输入及工艺依赖;未知不填0,公开机理不当本厂能力,零售价不当净收入。先用可取得的产品与适用技术资料分析实现条件和路线差异,再区分必须由本厂确认的能力,不把公开可研究内容全部后置。",
-          "feedback": "可提供真实净收入、报价、产线或必须满足的标准;不知道的条件直接保留未知。"
-        },
-        {
-          "title": "算可行条件并比较改动规模",
-          "task": "按实际输入和反馈建立可重算的基准情景、敏感性与盈亏临界,毛利和贡献利润分开,核单包/整箱及销量周期一致、成本无重复计项。逐方案解释什么条件下值得做、最敏感的输入及其变化如何改变建议;缺真实参数则给带单位/公式的可重算模型和决定性报价清单,算术示例隔离且不得当测算结论。比较小改/大改收益与成本/工艺/合规风险,不能只有公式没有条件判断。先给已知条件下能成立的方案对照;每个决定性未知写清取值怎样改变路线,不能用空成本表与通用公式代替分析。",
-          "feedback": "可修改真实参数或可接受的取舍;不用替数字人计算,缺参数不代表方案已不可行。"
-        },
-        {
-          "title": "交可行性回推报告与V2全池",
-          "task": "形成收入/成本/工艺/供应/合规回推表、可重算情景/临界与敏感性及待核文件清单。核关键计算能沿输入回算,结论说明具体哪项改动、哪组条件值得继续,以及最先要核哪份报价/产线资料。将V1完整候选逐项映射V2:保留、修改、暂缓或排除及原因,未知不自动淘汰也不称可量产。更新受影响的验证评估,写清买点和提案可采用的真实条件。正文给有理由的条件式建议和技术/经营取舍,待核项带取得方式及取得后如何决策。 把关键净收入/成本/产线条件与对应方案放在同一对照中,说明哪个输入变化会让小改、大改或维持现状更合适;缺报价保留条件判断,不用空表替代分析。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看全池去向与关键条件;下一节把产品设定转成用户价值。"
-        }
-      ]
-    },
-    "value": {
-      "title": "提炼价值主张与买点",
-      "references": [
-        "workshop-value-proposition.md"
-      ],
-      "rounds": [
-        {
-          "title": "先说清对谁有什么价值",
-          "task": "接续V2和可行性条件,给目标人群/场景—任务矛盾—具体产品设定—收益—可信理由—现有替代与代价的价值主张初稿。选能解释使用或选择的用户材料及相应产品依据,说明为什么不直接用现售方案、增量在哪里、必须保留什么体验;把用户想要、现品事实和新品待证属性分开,需求证据不能当性能已证。",
-          "feedback": "看价值是否具体且值得选;可修正目标情境、产品设定或不能牺牲的体验。"
-        },
-        {
-          "title": "比较卖点表达与证明条件",
-          "task": "按反馈生成不同表达角度的卖点、Slogan与短文案,每项对应需求—产品要素—收益—可信理由—表达;比较用户能否读懂具体收益、与替代品有何差别以及表达代价。逐条标可引用事实、内部待测表达、当前不可声称与所需验证,不自行新增功效或未经确认的性能。给适用的文案对照测试问题,研究者判断与实际用户反馈分开,解释舍弃空泛/不实表述的原因。核心表达必须说清具体改善及证明条件,不能靠“创新、健康、高品质”等形容词制造优势。",
-          "feedback": "可选择表达方向或指出夸大、听不懂的词;选择文案不等于确认最终方案。"
-        },
-        {
-          "title": "交价值主张与买点方案",
-          "task": "形成独立价值主张/买点报告:人群与场景、替代对照、具体产品要素及收益、可信理由、表达方案与取舍、可说/待测/不可说清单及验证办法。核核心买点能回连产品设定和证明条件,读者能理解为何选择及须接受的代价。保留实际选择和未决项,与买点方案交付章节对应;下一节整合为概念提案,不把文案定稿称产品已验证。 以“使用任务—具体产品要素—用户收益—可信理由—可用表达”对照说明每条核心买点,同时列最强替代与必须接受的代价;未经验证的性能不得包装为卖点事实。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。查看买点与产品设定、证据是否一致;准备进入提案评审。"
-        }
-      ]
-    },
-    "proposal": {
-      "title": "完成概念提案与评审汇总",
-      "references": [
-        "workshop-concept-presentation.md"
-      ],
-      "rounds": [
-        {
-          "title": "先交独立可读的提案供评审",
-          "task": "回读市场至买点的实际成果、V2全池与条件,整合独立可读的产品概念提案供我评审。开篇讲清建议推进/修改/暂缓什么、相对现品的增量及成立条件,不把建议当我的选择。正文包含机会与目标情境、关键洞察、现有替代、具体形态/规格/风味/包装及使用/购买路径、价值与可信理由、商业/工艺条件、最关键反证及下一项验证。产品目标可具体但标为设定,不以未知为由只交框架。保留前序依据和限制,本轮不生成概念图,也不声称方案已确认。以最强现售替代检验提案增量,把已有发现、合理机制、原型设定与实证结果分别讲清;证据不足以主推时明确推荐先验证什么,不强行包装成已成立商机。 本轮即交可打开的HTML初稿与版本供我评审,不能等后面整理清单才出报告。",
-          "feedback": "先读完整提案,指出需要修改的产品设定、建议或依据;这一轮只供评审。"
-        },
-        {
-          "title": "处理质询并修订提案",
-          "task": "按我实际反馈修订提案及受影响的价值/可行性判断,说明变更和理由,核原有真实约束及须保留体验是否仍满足。真实评审反馈与准备的质询题分开,给5分钟分享顺序、拟答复和决定性待验证问题;V2→V3保留全池去向。交当前完整修订稿及可定位版本供核对,明确需我最终确认的具体方案与设定,不自动出图,不伪造客户/学员意见。质询优先问“现有产品为何不够、为何是此改动、什么结果会推翻建议”,答复引用实际依据或明确待验证关系。",
-          "feedback": "核对具体方案与版本;有改动继续反馈,满意后再明确确认该版本。"
-        },
-        {
-          "title": "整理报告与个人交付清单",
-          "task": "将当前修订稿整理成完整概念提案报告、V3全池去向和分享材料,按真实反馈标已确认或待确认;本段本身不代表我的确认。先核评审者不翻完整对话也能说清产品、适用情境、选择理由、代价和决定性验证,关键设定与前序结论一致。再核七类个人成果的实质正文、分类、版本和打开位置,缺项给准确停点。确认若尚缺,报告按当前状态保存;下一轮仅在我明确确认了可定位的具体方案/版本后才生成示意图。报告中就近展示关键原句、产品/路线对照、出处和适用范围,解释相反材料如何影响建议;引文数和页面美观不作质量证明。 HTML首屏应让评审者立即看懂建议、产品增量和成立条件;主文串起关键用户事件、竞品/路线对照、商业生产取舍及最能推翻建议的验证,准备明确的本版核对点。",
-          "deliver": true,
-          "feedback": "打开本版HTML报告核对内容后反馈。打开报告与七类交付清单。确认时可回复“确认当前报告中的××方案及所列产品设定,可以按此出图”;不满意继续修改。"
-        },
-        {
-          "title": "按已确认方案生成示意图",
-          "prerequisite": "先在对话中明确确认具体方案及版本。仅回复“继续”、复制本段或点击下一页均不等于确认。",
-          "task": "先核对话中是否有我对可定位具体方案/版本的明确确认;没有则只请我确认,不调用出图。确认已具备时,调用平台已配置的image技能及指定image 2.6,按表达需要生成产品外观、包装或使用场景示意图。严格依该版本的形态、规格、风味、包装、文字与场景,不擅增功能/卖点,明确标为概念示意图。关联对应报告真实编号和版本,经实际图片保存通道回读并核看板;工具/指定模型/保存通道不可用如实列待接入,不擅自换模型或虚报已出图。",
-          "feedback": "检查示意图与已确认设定是否一致;图片关联、报告打开和展示状态分别核对。"
-        }
-      ]
+  "schema": "ksf.workshop-prompts.v3",
+  "source": "https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html",
+  "sourceSha256": "e8ed9dbd979c17f5caa88fb820f64f94a2e54518f810d7482b6b82f39d88041d",
+  "prompts": {
+    "d101": {
+      "name": "D1-01 品类全景扫描",
+      "text": "【D1-01 品类全景扫描】\n承接:本组课题是「(粘贴本组课题:使用情境 + 产品范围)」,本组要支持的产品决定是「(粘贴练习四写下的决定)」。\n\n先看我下面填的认知盘点(不要跳过、不要替我改):\n1. 我已经知道的:\n2. 我还不知道的:\n3. 我希望搞清楚的:\n4. 我的真实限制:\n\n本节请建立「品类全景图谱」,它是后面所有环节的底座:\n- 供给树:按形态、工艺、价格带、地域风味四个维度,说明本组课题涉及的格子分别有什么商品(带计数);\n- 需求树:按人群(G1–G6)、场景、需求,说明本组课题的人群在哪一格里说过什么;\n- 供需缺口:左右两栏对照,指出「有商品、没需求原话」和「有需求原话、没商品」的格子;\n- 每个分支标注来源(数据文件 / 商品链接 / 笔记 ID)和覆盖范围(样本条数、平台、关键词)。\n\n要求:\n- 不虚构市场规模、销量或份额;数据里没有的,写「待确认」;\n- 「未标注」不等于「没有」,分清楚;\n- 先复用资料库已有材料;只有当缺口会改变图谱结构时,再说明需要补什么;\n- 「我还不知道的」那几条优先回答,并标出哪些已回答、哪些仍是缺口。\n\n最后输出:一张三栏图谱 + 一段 100 字以内的话,说明「本组所在的格子里,哪一格证据最薄」。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-02 的具体缺口)\n【下一步】接下来要做 D1-02 验证纪律。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d102": {
+      "name": "D1-02 验证纪律",
+      "text": "【D1-02 验证纪律】\n承接:本组 D1-01 的品类全景图谱(引用保存编号或粘贴表格)。\n\n本节请为本题定制一张「本题验证配置卡」,之后所有环节都按这张卡执行:\n1. 资料资格:哪些数据可以用、什么条件下可引用、什么情况下必须换口径;\n2. 统计与引文口径:分母怎么写、中位数用哪一种、价格用哪个口径(125 条与 71 条双报)、原文引用规范;\n3. 模型分工:哪些判断由你给证据、哪些必须由本组人来拍板;\n4. 分歧处理:两种说法冲突时怎么判,判不了怎么写;\n5. 回查记录:拿上面 1–4 回查 D1-01 图谱,挑出最容易被反驳的 3 条主张,说明换口径后结论变不变。\n\n企业标准(成本、产线、配方、价格政策)一律标「待确认」,不要替我猜。\n词典打标词(辣、贵、量大等)未抽读原文的,一律降级为「假设」。\n\n最后输出:一张配置卡(不超过一页)+ 一张回查记录。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-03 的具体缺口)\n【下一步】接下来要做 D1-03 竞品格局。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d103": {
+      "name": "D1-03 竞品格局",
+      "text": "【D1-03 竞品格局】\n承接:D1-01 品类全景图谱 + D1-02 验证配置卡。\n本组课题:(粘贴)。本组最关心的竞品 / 品牌:___。\n\n本节请按验证配置卡的口径,做「竞品图谱 + 待验证痛点假设」。\n\n一、商品层面(同格商品矩阵)\n对与本组课题同一格子的商品,比较:品牌、商品链接、规格(克重/件数)、价格条件(单价、百克价、整箱/单份)、形态、定位、卖点组合(哪些卖点叠加)、风味。\n每个卖点格子只标三种之一:【宣称】(标题/详情)、【回应】(用户原话所说)、【推断】(你的判断)。\n找不到新品时间字段就写「无字段,无法判断」,不要用标题推测。\n\n二、社媒层面\n- 每个竞品提取卖点组合,严格区分宣称 / 回应 / 推断;\n- 找出「正反都有」的原话:同一主题上有人说好、有人说不好,各给原文;\n- 对本组最关心的 2–3 个问题,提出可证伪的痛点假设(编号 H1、H2、H3),每条写清:凭什么怀疑、什么情况推翻它。\n\n口径要求:\n- 竞品社媒样本是每品牌一个关键词、约 20 篇,写明这个样本能代表什么、不能代表什么;\n- 不要用总赞排品牌声量;单条点赞特别高的,先检查是不是活动帖、表情包或重复抓取;\n- 碰到「辣」这类口味词,抽读原文再判断是正面还是负面。\n\n最后输出:一张竞品矩阵 + 一张假设清单。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-04 的具体缺口)\n【下一步】接下来要做 D1-04 假设定稿与任务下达。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d104": {
+      "name": "D1-04 假设定稿与任务下达",
+      "text": "【D1-04 假设定稿与任务下达】\n承接:D1-01 图谱、D1-02 配置卡、D1-03 竞品图谱与 H1–H3 待验证痛点假设。\n本组要支持的决定:(粘贴)。今晚最想得到答案的一条:(粘贴)。\n\n请把它们整理成「增强 AI 自驱任务卡」,每条主线假设一行,字段固定:\n- 假设键(H1 起编号,之后所有成果都用它引用)\n- 原假设(一句话,可被证伪)\n- 现有支持(带来源与编号)\n- 支持路径(查什么能支持它)\n- 反证路径(查什么能推翻它)\n- 停止条件(必须是程序可判定的东西,例如「找到 N 条反例」「读完某组全部笔记」)\n- 数据来源与权限(先复用资料库;外部补证是否授权、去哪里补)\n\n今晚的任务边界:\n- 只执行这张任务卡里的假设,不扩展新方向;\n- 最多 3 条主线假设,其余放「备查」;\n- 资料库不够、且缺口会改变结论时,才调用外部补证;不需要补证就直接成报;\n- 没查到、没权限、数据确实不存在,三类分开报。\n\n先给我一版任务卡草稿,并指出:哪些字段你拿不准、需要我回答?(只问会改变结论的问题)\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出今晚执行前还差什么)\n【下一步】今晚执行 D1-N 第二轮调研。请在交卡前回答:___(只问一个会改变结论的问题)"
+    },
+    "d1n": {
+      "name": "D1-N 第二轮调研(晚间执行)",
+      "text": "【D1-N 第二轮调研 · 晚间执行】\n按 D1-04 的任务卡执行今晚的调研。任务卡:(引用编号)验证配置卡:(引用编号)\n\n执行顺序:\n1. 先复用资料库原件:已有的商品、用户笔记、工艺知识、竞品资料;\n2. 检查覆盖与资格:每条假设被支持到什么程度,哪些是缺口;\n3. 只对「会改变判断的真实缺口」决定是否外部补证,并说明补什么、去哪里补;\n4. 按假设键做 VOC 预聚类,每条原话带笔记标题 / ID;提及率初表写清分母;\n5. 资料够用、不需要补证时,直接成报,不要为凑形式机械采集;\n6. 缺口清单分三类:没查到 / 没权限 / 数据确实不存在;\n7. 达到停止条件就停,并在战报中写明停在哪个条件;\n8. 保存后用真实编号回读,确认正文一致。\n\n最后输出:调研战报(按假设键一页)+ 缺口清单 + VOC 预聚类。\n\n【推送格式】战报生成时,在最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(明早最值得先读的缺口)\n【下一步】明早先做 D2-01 调研验收。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d201": {
+      "name": "D2-01 调研验收",
+      "text": "【D2-01 调研验收】\n承接:D1-N 的调研战报与缺口清单(引用编号)。\n\n请从战报中抽取「战报验收记录」,三列检查:\n1. 假设回应率:H1–H3 每条回应程度(支持 / 部分支持 / 推翻 / 未回应),并说明依据;\n2. 原件覆盖:支撑每条结论的原件是否能点开读到(附笔记 ID / 商品链接);读不到的标「待补证」;\n3. 分母口径:所有比例是否写明分母;没有的,补上或降级;\n另外:\n- 词典打标词是否抽读原文(辣 / 贵 / 量大等);未读的结论降到「假设」;\n- 缺口是否分了「没查到 / 没权限 / 不存在」三类;\n- 「AI 推断」是否与「原件证据」分开写。\n\n最后输出:一张验收记录 + 一份「可用资料集合」(合格的、能回读的原件清单)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-02 的具体缺口)\n【下一步】先听大课二,然后做 D2-02 VOC 证词聚类。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d202": {
+      "name": "D2-02 VOC 证词聚类",
+      "text": "【D2-02 VOC 证词聚类】\n承接:D2-01 战报验收记录 + 可用资料集合(附笔记 ID)。\n本组人群与场景范围:(粘贴)。\n\n请把可用资料的原话按四层拆开,四层不能混:\n1. 人群(G1–G6 或更细);\n2. 场景(具体时间、地点、行为);\n3. JTBD(用户要完成的事);\n4. 痛点(具体不满)。\n对每个打标痛点词(辣、贵、量大等),抽读原文,标注态度:正 / 负 / 读不出。\n\n输出四张表:\n- 聚类表:每条原话落在哪一层、哪一格;\n- 痛点库:痛点、原话(带 ID)、频次、态度分布;\n- KANO 表:每条痛点的需求类型(基本型 / 期望型 / 兴奋型),标明「频次先验」;\n- 人群 × 场景矩阵:每一格写原话条数与代表原话。\n\n禁止:按打标频次直接排名次;把「读不出态度」的原话删除。\n最后输出:四张表 + 3 个「有原话、没产品」的格子。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-03 的具体缺口)\n【下一步】接下来要做 D2-03 风味趋势与矩阵空白。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d203": {
+      "name": "D2-03 风味趋势与矩阵空白",
+      "text": "【D2-03 风味趋势与矩阵空白】\n承接:D2-02 四张表 + D1-01 品类全景图谱。\n\n请把「需求矩阵」和「供给矩阵」叠在一起,按三类列出空白:\n1. 结构:现在长什么样(价格带、工艺、形态、地域的分布);\n2. 变化:本批数据是单次快照,不能判涨跌;如要判「在变」,必须说明时间序列来源,没有就写「本次不验证」;\n3. 未覆盖:该有的东西还没有——但每个「未覆盖」都必须先查同格竞品,写明「同格已有 N 个,其中谁」。\n\n每个空白格给一行「机会指标」:要验证什么、用什么数据能验证、本次能不能验证。\n禁止把三类放在同一张排序表里比较;禁止把「搜索页找不到」写成「市场空白」。\n\n最后输出:产品机会及指标初表(一行一个机会,五列:空白格 / 类别 / 供给证据 / 需求证据 / 需要验证的指标)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-04 的具体缺口)\n【下一步】接下来要做 D2-04 三源交叉推理。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d204": {
+      "name": "D2-04 三源交叉推理",
+      "text": "【D2-04 三源交叉推理】\n承接:D2-03 机会及指标初表 + D2-02 四张表 + 本组研发侧对工艺的判断。\n本组最想先认证的 2 个空白格:(粘贴)。\n\n对每个空白格做三源交叉:\n- 源一 商品事实:同格有哪些商品、价格带、卖点组合(带商品链接);\n- 源二 用户原声:有哪些原话直接指向这一格(带笔记 ID 与态度);\n- 源三 工艺条件:这一格做不做得出来(参数、成本、稳定性)——你写你判断的,其余标「待工艺确认」。\n\n每张「机会卡」固定 6 个字段:\n1. 一句话结论(可被推翻的判断);\n2. 三源证据(每条带来源与编号);\n3. 反例(什么情况下这个结论不成立);\n4. 还缺什么(写成「待确认:……」并说明影响哪个结论);\n5. 下一步验证(先补哪一条证据);\n6. 工艺注释(研发侧亲手写:参数、条件、风险;AI 不得代写为「可行」)。\n\n评级:三源齐全 → 候选;两条线 → 候选(弱);一条线 → 线索。\n最后输出:候选机会清单 V1.0(2–3 张机会卡)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出下午 D2-05 排序前还差什么)\n【下一步】先听大课三,然后做 D2-05 机会验证与排序。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d205": {
+      "name": "D2-05 机会验证与排序",
+      "text": "【D2-05 机会验证与排序】\n承接:候选机会清单 V1.0(2–3 张机会卡)。\n\n请对每张机会卡打三个维度分(1–3):\n- 证据强度:三源各有多少条证据;\n- 可做性:现有产线 / 工艺 / 供应商能不能做;\n- 商业价值:价格带、毛利、量级(这一项标注「需本组复核」)。\n每个分数后写一句话依据,并标注依据是「课堂证据」还是「本组经验」。\n\n排序规则:任何一维得 1 分的机会,不得排进前三。\n无法打分的,单独列入「未知项表」:缺什么数据、能用什么方式补、本次能不能补。未知项不是低分项。\n\n最后输出:优先级机会清单(含分值、依据、排序理由)+ 未知项单列。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-06 的具体缺口)\n【下一步】接下来要做 D2-06 商业及供应链回推。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d206": {
+      "name": "D2-06 商业及供应链回推",
+      "text": "【D2-06 商业及供应链回推】\n承接:D2-05 优先级机会清单,本组主攻机会:(粘贴)工艺路径:改现有配比(B0)/ 新增并行产品线(O1)/ 两者对比。\n\n请对主攻机会做「回推表 + 候选机会清单 V2.0」:\n1. 两条路:B0 现状、O1 目标方案;只有收入、渠道费用、损耗比例都相同时,两者才可直接比较,否则写明差异;\n2. 三条费用分开:一次费用 / 资本投入 / 营运资金;\n3. 成本结构:按知识库行业通行值拆(面饼 34–38% / 调料 24–30% / 包材 12–13%……),换算到单位成本与目标价格带;\n4. 供应商:代工价 2.1–3.2 元/袋、验厂比例 42%、区域分工;缺装箱/外箱/配送/损耗的标「待确认」;\n5. 工艺与合规:工艺参数、GB 17400-2015(水分 ≤10%、酸价 ≤1.8、过氧化值 ≤0.25)、GB 2760-2024 添加剂限量;以标准正文为准。\n\n所有估算标「课堂估算」;本组经验值标「经验值」;缺的标「待确认」。\n最后输出:回推表 + V2.0 机会卡(在 V1.0 六字段外增加:成本区间 / 目标价格带 / 两条路对比 / 合规条件)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-07 的具体缺口)\n【下一步】接下来要做 D2-07 价值主张与核心卖点。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d207": {
+      "name": "D2-07 价值主张与核心卖点",
+      "text": "【D2-07 价值主张与核心卖点】\n承接:候选机会清单 V2.0 + D2-02 痛点库原话。\n本组主推版本面向的价格带 / 人群 / 场景:(粘贴)。\n\n第一步:写价值主张卡\n- 一句主主张(不超过 20 字,用户能复述);\n- 三条收益(用户能感知到的好处,不是工艺参数);\n- 三条证据(对应组件 / 原话 / 商品事实,带 ID);\n- 证据边界:能说什么 / 不能说什么 / 合规标示。\n\n第二步:卖点清单,按价格带 × 人群 × 场景各 2–3 个版本。\n要求:\n- 每一句卖点都要对到一条原话或一个商品事实;\n- 研发术语(非油炸、热风三段控温、含水 8–12%)翻译成市场语言,必要时保留一个“技术背书”小注;\n- 「健康 / 减脂 / 养胃」等功效宣称在无合规依据时一律不写;\n- 标出让本组删掉的那些版本,并说明为什么删(例如「技术上说得过去但做不到」)。\n\n最后输出:价值主张卡 + 卖点清单(主推版 + 备选版 + 不能说的话)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-08 的具体缺口)\n【下一步】接下来要做 D2-08 概念提案与分享。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d208": {
+      "name": "D2-08 概念提案与分享",
+      "text": "【D2-08 概念提案与分享】\n承接:候选机会清单 V2.0 + 回推表 + 价值主张卡 + 卖点清单。\n\n请按「结论 → 依据 → 风险 → 行动」串成一份提案,并生成三个版本:\n- 一句话版(决策圈用,不超过 40 字,说清做什么、为什么现在、要什么资源);\n- 一页版(协同圈用,5 页以内);\n- 全案版(归档用)。\n\n同时输出:\n1. 质询清单:决策圈 / 协同圈 / 生态圈各 3 个最可能问到的问题,标出哪些本组能答、哪些答不出;\n2. 矛盾清单:三段分析互相打架的地方,都保留下来,不要删;\n3. 候选清单 V3.0:质询后更新版本,记录每处修改理由;\n4. 成果导航:13 份产出物各自的保存位置、一句话用途、结营后第一周先看哪一份。\n\n要求:只做减法,每条留给结论的都是支撑结论的那几条证据。示意图类内容标注「生成示意,需设计确认」,不出现任何真实品牌 Logo。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出结营后第一周最该补的那个缺口)\n【下一步】结营后第一周陪练:拿 V3.0 回来先补一个「答不出」的问题。请先回答:___(只问一个会改变结论的问题)"
     }
   }
 }

+ 12 - 0
docs/workshop-v3-alignment-20261112/manual-sync.json

@@ -0,0 +1,12 @@
+{
+  "ok": true,
+  "source": "https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html",
+  "sourceSha256": "e8ed9dbd979c17f5caa88fb820f64f94a2e54518f810d7482b6b82f39d88041d",
+  "finalManualSha256": "51d182e50b97143e196e60e62fcc289380abb013d2899239912876f0db18521b",
+  "finalManualBytes": 303679,
+  "promptCount": 13,
+  "teachingContentChanged": false,
+  "adjustment": "absolute overview links and scroll wrappers for unwrapped tables; all teaching text and prompts preserved",
+  "oldManualArchived": true,
+  "deployed": false
+}

+ 3362 - 0
docs/workshop-v3-alignment-20261112/source-manual-v3.html

@@ -0,0 +1,3362 @@
+<!DOCTYPE html>
+<html lang="zh-CN" data-theme="light">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
+<meta name="description" content="康师傅产品创新工作坊学员手册 v3:三个半天、3 份大课详案、13 个环节、13 份产出物规范。产品经理 = 未来品类负责人。">
+<title>康师傅 · 产品创新工作坊 学员手册 v3</title>
+<style>
+/* 康师傅工作坊学员手册 v3 —— 样式
+   主色 #C8102E 只做强调;暖白底 #FAFAF8;正文 15.5px,行高 1.7;信息密度高、排版紧凑。
+   v3 新增:产出物规范板、推送语、大课分段、三层架构、对照表、话术对照、缩放条 */
+:root {
+  --red: #C8102E;
+  --red-soft: rgba(200, 16, 46, .07);
+  --red-line: rgba(200, 16, 46, .22);
+  --amber: #A86A12;
+  --amber-soft: rgba(168, 106, 18, .08);
+  --teal: #0E6E5C;
+  --teal-soft: rgba(14, 110, 92, .08);
+  --green: #2E7D32;
+  --bg: #FAFAF8;
+  --bg-2: #F2F1EC;
+  --card: #FFFFFF;
+  --ink: #1F1F1F;
+  --ink-2: #5E5E5A;
+  --ink-3: #8E8C86;
+  --line: #E7E5DF;
+  --line-2: #D9D6CE;
+  --shadow: 0 1px 2px rgba(31, 31, 31, .04), 0 4px 14px rgba(31, 31, 31, .04);
+  --code-bg: #F6F5F1;
+  --side-w: 276px;
+  --maxw: 920px;
+  --sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", sans-serif;
+  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", "Noto Sans Mono CJK SC", monospace;
+}
+[data-theme="dark"] {
+  --red: #E8425C;
+  --red-soft: rgba(232, 66, 92, .12);
+  --red-line: rgba(232, 66, 92, .32);
+  --amber: #E2A44C;
+  --amber-soft: rgba(226, 164, 76, .1);
+  --teal: #4FB8A3;
+  --teal-soft: rgba(79, 184, 163, .1);
+  --green: #6FCF7B;
+  --bg: #141414;
+  --bg-2: #1C1C1B;
+  --card: #1E1E1D;
+  --ink: #ECEAE4;
+  --ink-2: #B0ADA6;
+  --ink-3: #85837D;
+  --line: #2E2D2A;
+  --line-2: #3A3935;
+  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 4px 14px rgba(0, 0, 0, .25);
+  --code-bg: #242422;
+}
+* { box-sizing: border-box; }
+html { -webkit-text-size-adjust: 100%; }
+body {
+  margin: 0; background: var(--bg); color: var(--ink);
+  font: 15.5px/1.7 var(--sans);
+  -webkit-font-smoothing: antialiased;
+}
+a { color: var(--red); text-decoration: none; }
+a:hover { text-decoration: underline; }
+b, strong { font-weight: 650; }
+h1, h2, h3, h4 { line-height: 1.35; margin: 0; }
+p { margin: 0 0 .7em; }
+ul, ol { margin: .4em 0 .9em; padding-left: 1.3em; }
+li { margin: .25em 0; }
+.muted { color: var(--ink-2); font-size: 13.5px; }
+.mt { margin-top: 26px; }
+.num { font-variant-numeric: tabular-nums; }
+
+/* ---------- 布局 ---------- */
+.app { display: flex; min-height: 100vh; }
+.side {
+  position: fixed; top: 0; left: 0; bottom: 0; width: var(--side-w);
+  background: var(--card); border-right: 1px solid var(--line);
+  display: flex; flex-direction: column; z-index: 40;
+}
+.side-top { padding: 16px 18px 12px; border-bottom: 1px solid var(--line); }
+.brand { display: flex; align-items: center; gap: 9px; }
+.brand-logo { width: 26px; height: 26px; border-radius: 6px; background: var(--red); color: #fff; display: grid; place-items: center; font-weight: 800; font-size: 13px; flex: none; }
+.brand-name { font-weight: 700; font-size: 14.5px; letter-spacing: .2px; }
+.brand-sub { font-size: 12px; color: var(--ink-2); margin-top: 1px; }
+.side-tools { display: flex; gap: 6px; margin-top: 12px; }
+.tool-btn {
+  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
+  height: 32px; border: 1px solid var(--line-2); background: transparent; color: var(--ink);
+  border-radius: 7px; font: inherit; font-size: 12.5px; cursor: pointer; white-space: nowrap;
+}
+.tool-btn:hover { border-color: var(--red); color: var(--red); text-decoration: none; }
+.search-box { margin-top: 10px; }
+.search-box input {
+  width: 100%; height: 32px; border: 1px solid var(--line-2); border-radius: 7px;
+  background: var(--bg); color: var(--ink); padding: 0 10px; font: inherit; font-size: 13px;
+}
+.search-box input:focus { outline: none; border-color: var(--red); }
+.toc { flex: 1; overflow-y: auto; padding: 8px 8px 24px; overscroll-behavior: contain; }
+.toc-group { margin: 12px 0 2px; padding: 0 10px; font-size: 11px; color: var(--ink-3); letter-spacing: .08em; font-weight: 650; }
+.toc a {
+  display: block; padding: 5px 10px; border-radius: 6px; color: var(--ink-2);
+  font-size: 13px; line-height: 1.45; border-left: 2px solid transparent; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+}
+.toc a:hover { background: var(--bg-2); color: var(--ink); text-decoration: none; }
+.toc a.active { color: var(--red); background: var(--red-soft); border-left-color: var(--red); font-weight: 600; }
+.toc a.toc-big { font-weight: 650; color: var(--ink); }
+.toc a.hide { display: none; }
+.progress { border-top: 1px solid var(--line); padding: 12px 16px 14px; background: var(--card); }
+.progress .ptitle { font-size: 11px; color: var(--ink-3); letter-spacing: .08em; margin-bottom: 8px; font-weight: 650; }
+.pg-row { display: flex; gap: 6px; align-items: flex-start; }
+.pg { flex: 1; display: block; }
+.pg:hover { text-decoration: none; }
+.pg-bar { display: block; height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }
+.pg-bar i { display: block; height: 100%; width: 0; background: var(--red); transition: width .3s ease; }
+.pg.done .pg-bar i { width: 100% !important; background: var(--ink-3); }
+.pg-label { display: block; font-size: 11.5px; color: var(--ink-2); margin-top: 5px; text-align: center; }
+.pg.active .pg-label { color: var(--red); font-weight: 650; }
+.pg-count { display: block; font-size: 11.5px; color: var(--ink-3); text-align: right; margin-top: 6px; font-variant-numeric: tabular-nums; }
+
+.main { margin-left: var(--side-w); flex: 1; min-width: 0; }
+.content { max-width: var(--maxw); margin: 0 auto; padding: 0 36px 90px; }
+
+.mobile-bar {
+  display: none; position: sticky; top: 0; z-index: 30; height: 52px;
+  background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(8px);
+  border-bottom: 1px solid var(--line); align-items: center; gap: 10px; padding: 0 14px;
+}
+.mobile-bar .brand-name { font-size: 14px; }
+.mobile-bar .tool-btn { flex: none; width: auto; padding: 0 12px; margin-left: auto; }
+.icon-btn { width: 36px; height: 36px; border-radius: 8px; border: 1px solid var(--line-2); background: transparent; color: var(--ink); font-size: 16px; cursor: pointer; display: grid; place-items: center; flex: none; }
+.scrim { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.35); z-index: 39; }
+.nav-open .scrim { display: block; }
+#drawer-close { display: none; }
+
+/* ---------- 封面 ---------- */
+.cover {
+  padding: 64px 0 38px; border-bottom: 1px solid var(--line);
+  background:
+    radial-gradient(900px 300px at 110% -10%, var(--red-soft), transparent 60%),
+    radial-gradient(700px 260px at -10% 110%, var(--amber-soft), transparent 60%);
+}
+.cover-mark { font-size: 12.5px; letter-spacing: .14em; color: var(--red); font-weight: 700; }
+.cover h1 { font-size: clamp(28px, 4.4vw, 44px); letter-spacing: -.01em; margin: 14px 0 6px; font-weight: 800; }
+.cover-sub { font-size: 17px; color: var(--ink-2); margin-bottom: 18px; }
+.cover-lead { font-size: 16.5px; max-width: 680px; }
+.cover-thesis { margin: 18px 0 0; padding: 12px 16px; border-left: 3px solid var(--red); background: var(--card); border-radius: 0 10px 10px 0; font-size: 15.5px; box-shadow: var(--shadow); }
+.cover-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 22px 0 26px; }
+.cover-facts div { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px; box-shadow: var(--shadow); }
+.cover-facts span { display: block; font-size: 12px; color: var(--ink-3); margin-bottom: 2px; }
+.cover-facts b { font-size: 14px; font-weight: 600; }
+.cover-cta { display: flex; gap: 10px; flex-wrap: wrap; }
+.btn { display: inline-flex; align-items: center; height: 40px; padding: 0 18px; border-radius: 9px; border: 1px solid var(--line-2); color: var(--ink); font-weight: 600; font-size: 14.5px; }
+.btn:hover { text-decoration: none; border-color: var(--red); color: var(--red); }
+.btn.primary { background: var(--red); border-color: var(--red); color: #fff; }
+.btn.primary:hover { color: #fff; opacity: .92; }
+
+/* ---------- 通用段 ---------- */
+.seg { padding: 42px 0 10px; border-bottom: 1px solid var(--line); scroll-margin-top: 60px; }
+.seg:last-of-type { border-bottom: 0; }
+.seg-title { font-size: clamp(22px, 3vw, 28px); font-weight: 800; margin-bottom: 10px; letter-spacing: -.01em; }
+.lead { font-size: 15.5px; color: var(--ink); background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--red); padding: 12px 16px; border-radius: 8px; margin: 14px 0 20px; }
+.block { margin: 22px 0; }
+.block > h3 { font-size: 17px; font-weight: 700; margin: 0 0 10px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
+.block > h4 { font-size: 15px; margin: 14px 0 8px; }
+.step-no { display: inline-grid; place-items: center; min-width: 28px; height: 22px; padding: 0 7px; border-radius: 6px; background: var(--red-soft); color: var(--red); font-size: 12px; font-weight: 700; }
+.block.note { background: var(--bg-2); border: 1px dashed var(--line-2); border-radius: 10px; padding: 12px 16px; font-size: 14px; }
+.block.note > h3 { font-size: 15px; }
+.block.accent { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 14px 18px; box-shadow: var(--shadow); }
+.block.accent > h3 { font-size: 16px; }
+.block.industry { background: var(--amber-soft); border: 1px solid color-mix(in srgb, var(--amber) 22%, transparent); border-radius: 12px; padding: 14px 18px; }
+.block.industry > h3 { color: var(--amber); }
+.block.industry .step-no { background: color-mix(in srgb, var(--amber) 16%, transparent); color: var(--amber); }
+.roles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 12px 0 18px; }
+.role { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; box-shadow: var(--shadow); }
+.role b { font-size: 13.5px; color: var(--red); }
+.role p { font-size: 13.5px; color: var(--ink-2); margin: 4px 0 0; }
+
+/* ---------- 表格 ---------- */
+.tbl-scroll { max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; border: 1px solid var(--line); border-radius: 10px; margin: 10px 0 14px; background: var(--card); }
+.tbl-scroll table.tbl { border: 0; border-radius: 0; margin: 0; }
+table.tbl { width: 100%; border-collapse: collapse; font-size: 13.8px; line-height: 1.6; background: var(--card); }
+table.tbl th, table.tbl td { padding: 8px 12px; text-align: left; vertical-align: top; border-top: 1px solid var(--line); word-break: break-word; overflow-wrap: anywhere; }
+table.tbl thead th { background: var(--bg-2); font-size: 12.5px; color: var(--ink-2); font-weight: 650; border-top: 0; white-space: nowrap; }
+.tbl-scroll table.tbl.wide { min-width: 680px; }
+.tbl-scroll table.tbl.compact { min-width: 540px; }
+table.clock td { font-variant-numeric: tabular-nums; white-space: nowrap; }
+table.tbl tr.hl td { background: var(--red-soft); }
+table.tbl td.zero { color: var(--red); font-weight: 750; }
+table.tbl .up { color: var(--green); }
+table.tbl .down { color: var(--red); }
+
+/* ---------- 总览 ---------- */
+.halves { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 18px 0; }
+.half-card { background: var(--card); border: 1px solid var(--line); border-top: 3px solid var(--acc); border-radius: 10px; padding: 14px 16px; box-shadow: var(--shadow); }
+.hc-head { display: flex; justify-content: space-between; align-items: baseline; gap: 6px; }
+.hc-head b { font-size: 14px; color: var(--acc); }
+.hc-head span { font-size: 12px; color: var(--ink-3); }
+.half-card h4 { font-size: 15px; margin: 6px 0 8px; }
+.half-card ol { padding-left: 1.2em; font-size: 13px; color: var(--ink-2); margin: 0 0 10px; }
+.half-card ol a { color: var(--ink); }
+.hc-out { font-size: 13px; margin: 0; padding-top: 8px; border-top: 1px dashed var(--line-2); }
+.hc-out span { display: block; font-size: 11.5px; color: var(--ink-3); margin-bottom: 2px; }
+
+/* ---------- 四步闭环 ---------- */
+.loop4 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 16px 0; }
+.loop-step { position: relative; background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px 18px 12px; box-shadow: var(--shadow); }
+.ls-no { position: absolute; top: 12px; right: 14px; font-size: 28px; font-weight: 800; color: color-mix(in srgb, var(--red) 22%, transparent); line-height: 1; }
+.loop-step h3 { font-size: 16px; }
+.ls-sub { font-size: 13px; color: var(--ink-2); margin: 2px 0 6px; }
+.loop-step ul { font-size: 13.5px; margin: 0; }
+
+/* ---------- 规则 ---------- */
+.rules { display: grid; gap: 10px; }
+.rule { display: grid; grid-template-columns: 36px 1fr; gap: 12px; background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 12px 16px; box-shadow: var(--shadow); }
+.r-no { width: 30px; height: 30px; border-radius: 50%; background: var(--red); color: #fff; font-weight: 800; display: grid; place-items: center; font-size: 14px; }
+.r-body h3 { font-size: 15px; margin-bottom: 4px; }
+.r-body p { font-size: 14px; margin: 0 0 6px; color: var(--ink); }
+.r-body .r-how { color: var(--ink-2); }
+.r-how b { color: var(--ink); font-weight: 600; }
+
+/* ---------- 速查 ---------- */
+.jump-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 14px 0; }
+.jump { display: grid; grid-template-columns: 64px 1fr; grid-template-rows: auto auto auto; column-gap: 10px; background: var(--card); border: 1px solid var(--line); border-radius: 9px; padding: 10px 12px; color: var(--ink); }
+.jump:hover { text-decoration: none; border-color: var(--red-line); background: var(--red-soft); }
+.jump b { grid-row: span 3; font-size: 13px; color: var(--red); align-self: center; }
+.jump span { font-size: 14px; font-weight: 650; }
+.jump em { font-style: normal; font-size: 12.5px; color: var(--ink-2); }
+.jump i { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
+
+/* ---------- 产品经理定位 ---------- */
+.pm-hero { background: var(--ink); color: var(--bg); border-radius: 14px; padding: 20px 24px; margin: 16px 0; }
+[data-theme="dark"] .pm-hero { background: var(--card); border: 1px solid var(--line-2); }
+.pm-hero .pm-tag { font-size: 12px; letter-spacing: .14em; font-weight: 800; color: #fff; background: var(--red); padding: 2px 10px; border-radius: 99px; }
+.pm-hero h3 { font-size: clamp(18px, 2.6vw, 23px); margin: 12px 0 6px; color: inherit; }
+.pm-hero p { font-size: 14.5px; opacity: .88; margin: 0; }
+.caps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 12px 0; }
+.cap { background: var(--card); border: 1px solid var(--line); border-radius: 11px; padding: 14px 16px; box-shadow: var(--shadow); position: relative; }
+.cap::before { content: ''; position: absolute; left: 0; top: 12px; bottom: 12px; width: 3px; border-radius: 2px; background: var(--acc); }
+.cap h4 { font-size: 15px; margin: 0 0 2px; }
+.cap .cap-lv { font-size: 11.5px; font-weight: 700; color: #fff; background: var(--acc); padding: 1px 8px; border-radius: 99px; display: inline-block; margin-bottom: 8px; }
+.cap ul { font-size: 13.5px; margin: 0; padding-left: 1.1em; }
+.cap .cap-q { font-size: 12.5px; color: var(--ink-2); margin: 8px 0 0; padding-top: 8px; border-top: 1px dashed var(--line-2); }
+
+/* ---------- 八步 SOP ---------- */
+.sop { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 12px 0 6px; }
+.sop-step { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; position: relative; box-shadow: var(--shadow); }
+.sop-step b { display: block; font-size: 14px; }
+.sop-step .sop-no { font-size: 11px; color: var(--red); font-weight: 800; letter-spacing: .08em; }
+.sop-step .sop-q { font-size: 12.5px; color: var(--ink-2); margin: 2px 0 6px; }
+.sop-step .sop-d { font-size: 12px; padding: 2px 8px; border-radius: 99px; background: var(--bg-2); border: 1px solid var(--line); display: inline-block; }
+.sop-step .sop-d.d1 { background: var(--red-soft); border-color: var(--red-line); color: var(--red); }
+.sop-step .sop-d.d2a { background: var(--amber-soft); border-color: color-mix(in srgb, var(--amber) 25%, transparent); color: var(--amber); }
+.sop-step .sop-d.d2p { background: var(--teal-soft); border-color: color-mix(in srgb, var(--teal) 25%, transparent); color: var(--teal); }
+.sop-legend { display: flex; flex-wrap: wrap; gap: 8px; font-size: 12.5px; color: var(--ink-2); margin: 4px 0 0; }
+.sop-legend span { display: inline-flex; align-items: center; gap: 6px; }
+.sop-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 3px; }
+.sop-legend .l1 { background: var(--red); }
+.sop-legend .l2 { background: var(--amber); }
+.sop-legend .l3 { background: var(--teal); }
+.chain { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 12px 0 16px; }
+.chain span { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px; font-weight: 650; font-size: 14px; box-shadow: var(--shadow); }
+.chain i { font-style: normal; color: var(--red); font-weight: 800; }
+
+/* ---------- 半天头 ---------- */
+.half { margin: 48px 0 0; scroll-margin-top: 60px; }
+.half-head { background: var(--ink); color: var(--bg); border-radius: 14px; padding: 22px 24px; }
+[data-theme="dark"] .half-head { background: var(--card); color: var(--ink); border: 1px solid var(--line-2); }
+.half-top { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
+.half-label { font-size: 12px; letter-spacing: .16em; font-weight: 800; color: #fff; background: var(--red); padding: 2px 10px; border-radius: 99px; }
+.half-time { font-size: 13px; opacity: .75; font-variant-numeric: tabular-nums; }
+.half-head h2 { font-size: clamp(20px, 3vw, 26px); margin: 12px 0 6px; }
+.half-head > p { font-size: 14.5px; opacity: .85; margin-bottom: 14px; }
+.half-goal { background: rgba(255,255,255,.06); border-radius: 10px; padding: 10px 14px; }
+[data-theme="dark"] .half-goal { background: var(--bg-2); }
+.half-goal b { font-size: 13px; }
+.half-goal ol { margin: 4px 0 0; font-size: 13.5px; opacity: .9; }
+.band-note { margin-top: 10px; font-size: 13px; opacity: .8; }
+
+/* ---------- 大课 ---------- */
+.big { background: linear-gradient(180deg, var(--red-soft), transparent 240px); padding-top: 34px; }
+.big-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
+.big-no { font-size: 12.5px; font-weight: 800; letter-spacing: .12em; color: #fff; background: var(--red); padding: 3px 10px; border-radius: 6px; }
+.big-head h2 { font-size: clamp(24px, 3.6vw, 32px); font-weight: 800; }
+.meta-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
+.chip { font-size: 12.5px; padding: 3px 9px; border-radius: 6px; background: var(--bg-2); color: var(--ink-2); border: 1px solid var(--line); }
+.chip.tag { background: var(--red-soft); color: var(--red); border-color: var(--red-line); font-weight: 600; }
+.chip.deliver { background: var(--red); color: #fff; border-color: var(--red); font-weight: 650; }
+.segments { display: grid; gap: 6px; margin: 16px 0 6px; }
+.seg-row { display: grid; grid-template-columns: 78px 1fr 1fr; gap: 12px; align-items: center; background: var(--card); border: 1px solid var(--line); border-radius: 9px; padding: 9px 14px; font-size: 13.5px; }
+.seg-row b { font-size: 14px; }
+.seg-row .sr-t { color: var(--red); font-weight: 700; font-variant-numeric: tabular-nums; }
+.seg-row .sr-q { color: var(--ink-2); }
+.seg-row.onair { border-color: var(--red-line); background: linear-gradient(90deg, var(--red-soft), var(--card) 60%); }
+.lecture { border: 1px solid var(--line-2); border-radius: 12px; background: var(--card); margin: 16px 0; overflow: hidden; box-shadow: var(--shadow); scroll-margin-top: 64px; }
+.lecture-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 16px; background: var(--bg-2); border-bottom: 1px solid var(--line); }
+.lecture-no { font-size: 11.5px; font-weight: 800; letter-spacing: .1em; color: #fff; background: var(--red); padding: 2px 9px; border-radius: 6px; }
+.lecture-head h3 { font-size: 17px; flex: 1; min-width: 200px; }
+.lecture-body { padding: 6px 18px 14px; }
+.lp { margin: 14px 0; }
+.lp-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
+.lp-time { font-size: 12px; font-weight: 700; color: var(--red); background: var(--red-soft); border: 1px solid var(--red-line); padding: 1px 8px; border-radius: 99px; font-variant-numeric: tabular-nums; }
+.lp-head h4 { font-size: 15.5px; }
+.script { border-left: 3px solid var(--line-2); padding: 2px 0 2px 12px; font-size: 14.5px; color: var(--ink); }
+.script p { margin: 0 0 .55em; }
+.script p:last-child { margin-bottom: 0; }
+.script .say { color: var(--ink); }
+.two-col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 10px 0; }
+.col { border-radius: 10px; padding: 12px 14px; border: 1px solid var(--line); background: var(--card); }
+.col h4 { font-size: 14px; margin: 0 0 6px; }
+.col ul, .col p { font-size: 13.5px; margin-bottom: 0; }
+.col.ok { border-top: 3px solid var(--green); }
+.col.ok h4 { color: var(--green); }
+.col.bad { border-top: 3px solid var(--red); }
+.col.bad h4 { color: var(--red); }
+
+/* 三层架构 */
+.layers { display: grid; gap: 0; margin: 14px 0; }
+.layer { border: 1px solid var(--line); background: var(--card); padding: 14px 18px; position: relative; }
+.layer:first-child { border-radius: 12px 12px 0 0; }
+.layer:last-child { border-radius: 0 0 12px 12px; }
+.layer + .layer { border-top: 0; }
+.layer .ly { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
+.layer .ly b { font-size: 16px; }
+.layer .ly .ly-k { font-size: 11.5px; font-weight: 700; color: #fff; background: var(--acc, var(--red)); padding: 2px 9px; border-radius: 99px; }
+.layer .ly .ly-who { font-size: 13px; color: var(--ink-2); }
+.layer p { font-size: 13.8px; margin: 6px 0 0; }
+.layer-down { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 6px 0; margin: -1px 0; position: relative; z-index: 1; font-size: 12.5px; color: var(--red); }
+.layer-down::before { content: '↓'; font-size: 16px; font-weight: 800; }
+
+/* 责任制的五项 */
+.resp { display: grid; gap: 6px; margin: 10px 0; }
+.resp-row { display: grid; grid-template-columns: 44px 1.1fr 1.3fr 1.1fr; gap: 10px; align-items: center; background: var(--card); border: 1px solid var(--line); border-radius: 9px; padding: 8px 12px; font-size: 13.5px; }
+.resp-row .rh { background: var(--ink); color: var(--bg); border-radius: 6px; text-align: center; font-weight: 700; font-size: 12.5px; padding: 4px 0; }
+[data-theme="dark"] .resp-row .rh { background: var(--bg-2); color: var(--ink); }
+.resp-row .rk { color: var(--ink-3); font-size: 12px; }
+.resp-row b { font-size: 13.5px; }
+.rings { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 12px 0; position: relative; }
+.ring { border-radius: 12px; padding: 12px 12px 12px 14px; border: 1px solid var(--line); background: var(--card); }
+.ring b { font-size: 14px; display: block; }
+.ring span { font-size: 12.5px; color: var(--ink-2); }
+.ring.c1 { border-left: 4px solid var(--red); }
+.ring.c2 { border-left: 4px solid var(--amber); }
+.ring.c3 { border-left: 4px solid var(--teal); }
+.ring.c4 { border-left: 4px solid var(--ink-3); }
+.ladder { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 10px 0 14px; }
+.ladder div { background: var(--card); border: 1px solid var(--line); border-top: 3px solid var(--red); border-radius: 9px; padding: 10px 12px; font-size: 13.5px; }
+.ladder div b { display: block; font-size: 14.5px; margin-bottom: 2px; }
+.ladder div span { color: var(--ink-2); font-size: 12.5px; }
+.ladder div.lv2 { border-top-color: color-mix(in srgb, var(--red) 75%, var(--amber)); }
+.ladder div.lv3 { border-top-color: var(--amber); }
+.ladder div.lv4 { border-top-color: var(--teal); }
+
+/* 三类创新与两张对照表 */
+.kind3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 10px 0; }
+.kind { background: var(--card); border: 1px solid var(--line); border-radius: 11px; padding: 12px 14px; }
+.kind h4 { font-size: 14.5px; margin: 0 0 6px; color: var(--red); }
+.kind dl { margin: 0; font-size: 13px; display: grid; grid-template-columns: 52px 1fr; gap: 2px 8px; }
+.kind dt { color: var(--ink-3); }
+.kind dd { margin: 0; }
+table.tbl.compare td:first-child { font-weight: 650; color: var(--ink-2); }
+
+/* 案例框 */
+.case { background: linear-gradient(180deg, var(--red-soft), transparent 140px); border: 1px solid var(--red-line); border-radius: 12px; padding: 14px 18px; margin: 14px 0; }
+.case h4 { font-size: 15px; margin: 0 0 6px; color: var(--red); }
+.case p, .case li { font-size: 14px; }
+.case .case-foot { margin: 8px 0 0; font-size: 13.5px; padding-top: 8px; border-top: 1px dashed var(--red-line); }
+.moments { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 10px 0; }
+.moment { background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--amber); border-radius: 8px; padding: 8px 12px; font-size: 13.5px; }
+.moment b { color: var(--amber); font-size: 12px; display: block; }
+
+/* ---------- 环节 ---------- */
+.sec-head { display: grid; grid-template-columns: 80px 1fr; gap: 14px; align-items: start; }
+.sec-no { font-size: 18px; font-weight: 800; color: var(--red); padding-top: 2px; font-variant-numeric: tabular-nums; }
+.sec-head h2 { font-size: clamp(21px, 3vw, 26px); font-weight: 800; }
+.from { font-size: 13px; color: var(--ink-2); margin: 12px 0 0; padding: 7px 12px; background: var(--bg-2); border-radius: 8px; border: 1px dashed var(--line-2); }
+.pillars { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
+.pillar { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; box-shadow: var(--shadow); }
+.pillar.key { border-color: var(--red-line); background: linear-gradient(180deg, var(--red-soft), var(--card) 60%); }
+.p-head { display: flex; justify-content: space-between; align-items: center; }
+.p-head b { font-size: 14.5px; }
+.p-flag { font-size: 11px; font-weight: 700; color: #fff; background: var(--red); padding: 1px 7px; border-radius: 99px; }
+.p-tip { font-size: 12.5px; color: var(--ink-2); margin: 4px 0 6px; }
+.p-sample { font-size: 13px; margin: 0; color: var(--ink); }
+.p-sample span { font-size: 11px; color: var(--ink-3); margin-right: 6px; }
+.p-lines { margin-top: 8px; display: grid; gap: 6px; }
+.p-lines i { display: block; height: 1px; border-bottom: 1px dashed var(--line-2); }
+
+/* 提示词 */
+.prompt { border: 1px solid var(--line-2); border-radius: 10px; overflow: hidden; margin: 12px 0 14px; background: var(--code-bg); }
+.prompt-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 10px 7px 14px; background: var(--bg-2); border-bottom: 1px solid var(--line); }
+.prompt-label { font-size: 12.5px; color: var(--ink-2); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.copy { flex: none; height: 30px; padding: 0 14px; border-radius: 7px; border: 1px solid var(--red); background: var(--red); color: #fff; font: inherit; font-size: 12.5px; font-weight: 650; cursor: pointer; }
+.copy:hover { opacity: .9; }
+.copy.ok { background: var(--green); border-color: var(--green); }
+.prompt-body { margin: 0; padding: 12px 14px; font: 12.8px/1.75 var(--mono); white-space: pre-wrap; word-break: break-word; color: var(--ink); max-height: 420px; overflow: auto; }
+
+/* 产出物规范板 */
+.spec { border: 1px solid var(--red-line); border-radius: 14px; overflow: hidden; margin: 12px 0 16px; background: var(--card); box-shadow: 0 2px 18px rgba(200,16,46,.06); }
+.spec-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 16px; background: linear-gradient(90deg, var(--red), color-mix(in srgb, var(--red) 80%, #000)); color: #fff; }
+.spec-head .spec-k { font-size: 11px; font-weight: 800; letter-spacing: .16em; opacity: .85; }
+.spec-head h3 { font-size: 17px; color: #fff; }
+.spec-head .spec-meta { margin-left: auto; font-size: 12px; background: rgba(255,255,255,.16); padding: 2px 10px; border-radius: 99px; white-space: nowrap; }
+.spec-body { padding: 4px 16px 14px; }
+.spec-block { padding: 12px 0; border-bottom: 1px dashed var(--line-2); }
+.spec-block:last-child { border-bottom: 0; }
+.spec-block > h4 { font-size: 14.5px; margin: 0 0 8px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
+.spec-n { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: var(--red); color: #fff; font-size: 12px; font-weight: 800; flex: none; }
+.spec-form { font-size: 12px; color: var(--ink-2); font-weight: 500; }
+.spec-legend { display: flex; flex-wrap: wrap; gap: 10px; font-size: 12px; color: var(--ink-2); margin: 4px 0 0; }
+.spec-legend span { display: inline-flex; align-items: center; gap: 5px; }
+.spec-legend em { font-style: normal; width: 12px; height: 12px; border-radius: 3px; display: inline-block; }
+
+/* 真实样卡(1:1 复刻的产物样例) */
+.doc { border: 1px solid var(--line-2); border-radius: 10px; background: #fff; color: #1F1F1F; overflow: hidden; font-size: 13px; line-height: 1.6; margin: 8px 0 10px; }
+[data-theme="dark"] .doc { background: #F7F6F2; }
+.doc-scroll { overflow-x: auto; }
+.doc-scroll > .doc { min-width: 620px; }
+.doc-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 7px 12px; background: #1F1F1F; color: #fff; font-size: 12.5px; }
+.doc-bar b { font-size: 13px; }
+.doc-bar .doc-tag { margin-left: auto; font-size: 11px; background: rgba(255,255,255,.14); padding: 1px 8px; border-radius: 99px; }
+.doc-h { padding: 6px 12px; background: #F2F1EC; color: #5E5E5A; font-size: 11.5px; font-weight: 700; letter-spacing: .06em; border-bottom: 1px solid #E7E5DF; }
+.doc-body { padding: 10px 12px; }
+.doc-body.mark > p:first-child, .doc-body > table td.mark { background: rgba(200,16,46,.07); }
+.doc table { width: 100%; border-collapse: collapse; font-size: 12.8px; line-height: 1.55; color: #1F1F1F; }
+.doc th, .doc td { padding: 6px 8px; border-top: 1px solid #ECEAE4; text-align: left; vertical-align: top; }
+.doc thead th { background: #F4F3EF; color: #5E5E5A; font-size: 11.5px; border-top: 0; white-space: nowrap; }
+.doc caption { caption-side: top; text-align: left; font-weight: 700; font-size: 12.5px; padding: 2px 0 6px; color: #1F1F1F; }
+.doc .c { text-align: center; }
+.doc .r { text-align: right; font-variant-numeric: tabular-nums; }
+.doc .zero { color: #C8102E; font-weight: 800; }
+.doc .good { color: #2E7D32; font-weight: 700; }
+.doc .warn { color: #A86A12; font-weight: 700; }
+.doc-micro { font-size: 11.5px; color: #6B6B6B; margin: 6px 0 0; }
+.doc-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
+.doc-box { border: 1px solid #E7E5DF; border-radius: 8px; padding: 8px 10px; background: #FCFCFA; }
+.doc-box h5 { margin: 0 0 4px; font-size: 12px; color: #C8102E; }
+.doc-box ul { margin: 0; padding-left: 1.1em; font-size: 12.6px; }
+.doc-title { font-weight: 800; font-size: 14px; margin: 0 0 4px; }
+.doc-kv { display: grid; grid-template-columns: 88px 1fr; gap: 3px 8px; font-size: 12.8px; }
+.doc-kv dt { color: #6B6B6B; }
+.doc-kv dd { margin: 0; }
+.doc-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
+.doc-meta span { font-size: 11px; border: 1px solid #D9D6CE; border-radius: 99px; padding: 0 8px; color: #5E5E5A; }
+.flow-mini { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 12.8px; }
+.flow-mini b { background: #C8102E; color: #fff; padding: 2px 9px; border-radius: 6px; font-size: 12px; }
+.flow-mini span { background: #F2F1EC; border: 1px solid #E7E5DF; padding: 2px 9px; border-radius: 6px; }
+.flow-mini i { font-style: normal; color: #C8102E; font-weight: 800; }
+.rulerow { display: grid; grid-template-columns: 30px 1fr; gap: 8px; padding: 6px 0; border-top: 1px dashed #E7E5DF; font-size: 12.8px; }
+.rulerow:first-child { border-top: 0; }
+.rulerow b { color: #C8102E; }
+.rule-ok::before { content: '✓'; color: #2E7D32; font-weight: 800; }
+.rule-no::before { content: '✗'; color: #C8102E; font-weight: 800; }
+.rule-warn::before { content: '!'; color: #A86A12; font-weight: 800; }
+.score { display: inline-block; min-width: 22px; text-align: center; border-radius: 4px; font-weight: 700; font-size: 11.5px; padding: 0 4px; background: #F2F1EC; }
+.s3 { background: rgba(46,125,50,.14); color: #2E7D32; }
+.s2 { background: rgba(168,106,18,.14); color: #A86A12; }
+.s1 { background: rgba(200,16,46,.10); color: #C8102E; }
+.okdot { color: #2E7D32; font-weight: 800; }
+.nodot { color: #C8102E; font-weight: 800; }
+.halfdot { color: #A86A12; font-weight: 800; }
+
+/* 用途 / 流转 */
+.uses { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 0; }
+.use { border: 1px solid var(--line); border-radius: 9px; padding: 9px 12px; background: var(--bg); font-size: 13.5px; }
+.use b { color: var(--red); font-size: 12px; display: block; margin-bottom: 2px; }
+.handoff-box { margin: 8px 0 0; padding: 10px 14px; border-radius: 9px; background: var(--bg-2); border: 1px dashed var(--line-2); font-size: 13.5px; }
+.handoff-box ol { margin: 4px 0 0; }
+.handoff-box .hb { font-size: 12px; font-weight: 800; color: var(--red); letter-spacing: .06em; }
+
+/* 推送语 */
+.push { border: 1px solid var(--ink); border-radius: 12px; margin: 14px 0; overflow: hidden; background: var(--card); }
+[data-theme="dark"] .push { border-color: var(--line-2); }
+.push-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 8px 14px; background: var(--ink); color: var(--bg); font-size: 12.5px; }
+[data-theme="dark"] .push-bar { background: var(--bg-2); color: var(--ink); }
+.push-bar b { font-size: 13px; color: #fff; }
+[data-theme="dark"] .push-bar b { color: var(--ink); }
+.push-bar span { opacity: .75; }
+.push-rows { display: grid; }
+.push-row { display: grid; grid-template-columns: 92px 1fr; gap: 10px; padding: 9px 14px; border-top: 1px dashed var(--line-2); font-size: 14px; }
+.push-row:first-child { border-top: 0; }
+.push-row b { font-size: 12.5px; color: var(--red); padding-top: 2px; }
+.push-row p { margin: 0; }
+.push-row .ask { font-weight: 650; }
+
+/* 自检 / 对错 */
+.block.check { background: var(--card); border: 1px solid var(--line-2); border-radius: 12px; padding: 14px 18px; box-shadow: var(--shadow); }
+.check ol { list-style: none; padding: 0; margin: 6px 0; counter-reset: chk; }
+.check li { counter-increment: chk; }
+.check label { display: flex; gap: 10px; align-items: flex-start; padding: 7px 8px; border-radius: 8px; cursor: pointer; font-size: 14.5px; }
+.check label:hover { background: var(--bg-2); }
+.check label::before { content: counter(chk); flex: none; width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid var(--red); color: var(--red); font-size: 12px; font-weight: 700; display: grid; place-items: center; margin-top: 1px; }
+.check input { position: absolute; opacity: 0; pointer-events: none; }
+.check input:checked + span { text-decoration: line-through; color: var(--ink-3); }
+.check label:has(input:checked)::before { content: '✓'; background: var(--green); border-color: var(--green); color: #fff; }
+.check .muted { margin: 6px 0 0; }
+.right-wrong { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 18px 0; }
+.rw { border-radius: 10px; padding: 10px 16px; border: 1px solid var(--line); background: var(--card); }
+.rw h3 { font-size: 14.5px; margin: 0 0 4px; }
+.rw ul { font-size: 13.5px; margin: 0; padding-left: 1.15em; }
+.rw.ok { border-top: 3px solid var(--green); }
+.rw.ok h3 { color: var(--green); }
+.rw.bad { border-top: 3px solid var(--red); }
+.rw.bad h3 { color: var(--red); }
+.handoff { display: flex; gap: 12px; align-items: baseline; background: var(--ink); color: var(--bg); border-radius: 10px; padding: 12px 16px; margin: 4px 0 30px; }
+[data-theme="dark"] .handoff { background: var(--card); color: var(--ink); border: 1px solid var(--line-2); }
+.handoff span { flex: none; font-size: 12px; font-weight: 800; letter-spacing: .08em; color: #fff; background: var(--red); padding: 2px 10px; border-radius: 99px; }
+.handoff p { margin: 0; font-size: 14px; }
+
+/* ---------- 速查表 / 18 格 ---------- */
+.mat { display: grid; grid-template-columns: 40px repeat(4, minmax(0, 1fr)); gap: 4px; margin: 10px 0; font-size: 12.5px; }
+.mat div { padding: 6px 6px; border-radius: 6px; background: var(--card); border: 1px solid var(--line); }
+.mat .mh { background: var(--bg-2); font-weight: 700; text-align: center; color: var(--ink-2); }
+.mat .mh.corner { background: transparent; border: 0; }
+.mat .k { font-weight: 700; background: var(--bg-2); color: var(--ink-2); display: grid; place-items: center; }
+.mat .z0 { border-color: var(--red-line); background: var(--red-soft); }
+.mat .z0 b { color: var(--red); }
+.mat small { display: block; color: var(--ink-3); font-size: 11px; }
+
+/* ---------- 附录 ---------- */
+.traps { display: grid; gap: 16px; margin: 18px 0; }
+.trap { background: var(--card); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); overflow: hidden; }
+.trap-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); background: var(--bg-2); }
+.trap-no { font-size: 12px; font-weight: 800; color: #fff; background: var(--red); padding: 2px 8px; border-radius: 6px; }
+.trap-head h3 { font-size: 16px; flex: 1; min-width: 200px; }
+.trap-tag { font-size: 12px; color: var(--ink-2); }
+.trap-cols { display: grid; grid-template-columns: minmax(0, 1fr) 28px minmax(0, 1fr); gap: 8px; padding: 14px 16px 6px; align-items: stretch; }
+.tc { border-radius: 9px; padding: 10px 12px; border: 1px solid var(--line); min-width: 0; overflow-wrap: anywhere; }
+.tc h4 { font-size: 12px; letter-spacing: .06em; margin: 0 0 4px; }
+.tc p { font-size: 13.5px; margin: 0 0 6px; }
+.tc table { font-size: 12.3px; width: 100%; border-collapse: collapse; }
+.tc th, .tc td { padding: 3px 5px; border-top: 1px solid var(--line); text-align: left; }
+.tc.ai { background: var(--bg-2); }
+.tc.ai h4 { color: var(--ink-3); }
+.tc.human { background: var(--card); border-color: var(--red-line); }
+.tc.human h4 { color: var(--red); }
+.trap-cols .arrow { display: grid; place-items: center; color: var(--red); font-weight: 800; }
+.trap-foot { padding: 4px 16px 14px; }
+.trap-foot p { font-size: 13px; margin: 4px 0; }
+.trap-foot b { color: var(--ink-2); font-size: 12px; margin-right: 6px; }
+.faq-group { margin: 20px 0; }
+.faq-group h3 { font-size: 16px; margin-bottom: 8px; color: var(--red); }
+details.q { background: var(--card); border: 1px solid var(--line); border-radius: 9px; margin-bottom: 6px; }
+details.q summary { cursor: pointer; padding: 10px 14px; font-weight: 600; font-size: 14.5px; list-style: none; }
+details.q summary::-webkit-details-marker { display: none; }
+details.q summary::after { content: '+'; float: right; color: var(--red); font-weight: 700; }
+details.q[open] summary::after { content: '−'; }
+details.q p { padding: 0 14px 12px; margin: 0; font-size: 14px; color: var(--ink-2); }
+.tips { background: var(--ink); color: var(--bg); border-radius: 12px; padding: 16px 20px; margin: 24px 0; }
+[data-theme="dark"] .tips { background: var(--card); color: var(--ink); border: 1px solid var(--line-2); }
+.tips h3 { color: #fff; font-size: 15px; margin-bottom: 6px; }
+[data-theme="dark"] .tips h3 { color: var(--red); }
+.tips ol { margin: 0; font-size: 14px; }
+
+/* 话术对照 */
+.say-table td.no { color: var(--ink-3); text-decoration: line-through; text-decoration-color: var(--red-line); }
+.say-table td.yes { font-weight: 600; }
+
+/* ---------- 页脚 ---------- */
+.foot { padding: 28px 0 60px; font-size: 13px; color: var(--ink-2); border-top: 1px solid var(--line); margin-top: 30px; }
+.foot p { margin: 2px 0; }
+
+/* ---------- 响应式 ---------- */
+@media (max-width: 1100px) {
+  .content { padding: 0 24px 70px; }
+  .halves { grid-template-columns: 1fr; }
+  .roles, .caps, .kind3, .rings, .ladder { grid-template-columns: 1fr; }
+  .sop { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+  .resp-row { grid-template-columns: 40px 1fr; }
+  .resp-row .rk { grid-column: 2; }
+}
+@media (max-width: 860px) {
+  .side { width: min(86vw, 320px); transform: translateX(-102%); transition: transform .25s ease; box-shadow: 0 10px 40px rgba(0,0,0,.25); }
+  .nav-open .side { transform: none; }
+  .main { margin-left: 0; }
+  .mobile-bar { display: flex; }
+  #drawer-close { display: grid; margin-left: auto; }
+  .content { padding: 0 16px 60px; }
+  .seg { padding-top: 30px; }
+  body { font-size: 15px; }
+  .cover { padding: 36px 0 28px; }
+  .cover-facts { grid-template-columns: 1fr; gap: 8px; }
+  .cover-facts div { padding: 8px 12px; }
+  .cover-cta .btn { flex: 1; justify-content: center; }
+  .lead { padding: 10px 12px; }
+  .loop4, .pillars, .jump-grid, .two-col, .right-wrong, .uses, .moments { grid-template-columns: 1fr; }
+  .sec-head { grid-template-columns: 1fr; gap: 4px; }
+  .sec-no { padding-top: 0; }
+  .trap-cols { grid-template-columns: 1fr; }
+  .trap-cols .arrow { transform: rotate(90deg); height: 18px; }
+  .half-head { padding: 16px 16px; border-radius: 12px; }
+  .rule { grid-template-columns: 30px 1fr; padding: 10px 12px; }
+  .handoff { flex-direction: column; gap: 6px; }
+  .prompt-body { max-height: 320px; }
+  .seg-row { grid-template-columns: 64px 1fr; }
+  .seg-row .sr-q { grid-column: 2; }
+  .spec-body { padding: 2px 12px 10px; }
+  .spec-head .spec-meta { margin-left: 0; }
+  .push-row { grid-template-columns: 1fr; gap: 2px; }
+  .doc-grid2 { grid-template-columns: 1fr; }
+  .lp-head h4 { font-size: 15px; }
+  .mat { grid-template-columns: 34px repeat(4, minmax(0, 1fr)); font-size: 11.5px; }
+  .mat div { padding: 4px 4px; }
+}
+@media (prefers-reduced-motion: reduce) { .pg-bar i { transition: none; } }
+
+</style>
+</head>
+<body>
+<div class="app">
+  <aside class="side" id="drawer" aria-label="目录">
+    <div class="side-top">
+      <div class="brand">
+        <span class="brand-logo">康</span>
+        <div><div class="brand-name">学员手册 v3</div><div class="brand-sub">产品创新工作坊 · 智研先锋计划</div></div>
+        <button class="icon-btn" id="drawer-close" type="button" aria-label="关闭目录">✕</button>
+      </div>
+      <div class="side-tools">
+        <a class="tool-btn" href="../overview/index.html">总览图</a>
+        <button class="tool-btn" id="theme-toggle" type="button" aria-label="切换深色/浅色主题"><span aria-hidden="true">◐</span> 深浅色</button>
+      </div>
+      <div class="search-box"><input id="search" type="search" placeholder="搜索环节,如 竞品、卖点、推送" aria-label="搜索目录"></div>
+    </div>
+    <nav class="toc" id="toc-list"></nav>
+    <div class="progress" aria-label="进度">
+      <div class="ptitle">进度 · 环节产出</div>
+      <div class="pg-row" id="progress"></div>
+    </div>
+  </aside>
+  <div class="scrim" id="scrim"></div>
+  <div class="main">
+    <div class="mobile-bar">
+      <button class="icon-btn" id="menu-btn" type="button" aria-label="打开目录">☰</button>
+      <div class="brand"><span class="brand-logo">康</span><span class="brand-name">学员手册 v3</span></div>
+      <a class="tool-btn" href="../overview/index.html">总览图</a>
+    </div>
+    <main class="content" id="content"></main>
+  </div>
+</div>
+<script>
+// x1 · 提示词库:每个提示词都以【推送格式】三段结尾;正文里用 {PROMPT:id} 引用(现由 app.js 按环节 id 直接渲染)
+window.PROMPTS = {
+
+d101: {
+name: 'D1-01 品类全景扫描',
+text: `【D1-01 品类全景扫描】
+承接:本组课题是「(粘贴本组课题:使用情境 + 产品范围)」,本组要支持的产品决定是「(粘贴练习四写下的决定)」。
+
+先看我下面填的认知盘点(不要跳过、不要替我改):
+1. 我已经知道的:
+2. 我还不知道的:
+3. 我希望搞清楚的:
+4. 我的真实限制:
+
+本节请建立「品类全景图谱」,它是后面所有环节的底座:
+- 供给树:按形态、工艺、价格带、地域风味四个维度,说明本组课题涉及的格子分别有什么商品(带计数);
+- 需求树:按人群(G1–G6)、场景、需求,说明本组课题的人群在哪一格里说过什么;
+- 供需缺口:左右两栏对照,指出「有商品、没需求原话」和「有需求原话、没商品」的格子;
+- 每个分支标注来源(数据文件 / 商品链接 / 笔记 ID)和覆盖范围(样本条数、平台、关键词)。
+
+要求:
+- 不虚构市场规模、销量或份额;数据里没有的,写「待确认」;
+- 「未标注」不等于「没有」,分清楚;
+- 先复用资料库已有材料;只有当缺口会改变图谱结构时,再说明需要补什么;
+- 「我还不知道的」那几条优先回答,并标出哪些已回答、哪些仍是缺口。
+
+最后输出:一张三栏图谱 + 一段 100 字以内的话,说明「本组所在的格子里,哪一格证据最薄」。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响下一环 D1-02 的具体缺口)
+【下一步】接下来要做 D1-02 验证纪律。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d102: {
+name: 'D1-02 验证纪律',
+text: `【D1-02 验证纪律】
+承接:本组 D1-01 的品类全景图谱(引用保存编号或粘贴表格)。
+
+本节请为本题定制一张「本题验证配置卡」,之后所有环节都按这张卡执行:
+1. 资料资格:哪些数据可以用、什么条件下可引用、什么情况下必须换口径;
+2. 统计与引文口径:分母怎么写、中位数用哪一种、价格用哪个口径(125 条与 71 条双报)、原文引用规范;
+3. 模型分工:哪些判断由你给证据、哪些必须由本组人来拍板;
+4. 分歧处理:两种说法冲突时怎么判,判不了怎么写;
+5. 回查记录:拿上面 1–4 回查 D1-01 图谱,挑出最容易被反驳的 3 条主张,说明换口径后结论变不变。
+
+企业标准(成本、产线、配方、价格政策)一律标「待确认」,不要替我猜。
+词典打标词(辣、贵、量大等)未抽读原文的,一律降级为「假设」。
+
+最后输出:一张配置卡(不超过一页)+ 一张回查记录。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响下一环 D1-03 的具体缺口)
+【下一步】接下来要做 D1-03 竞品格局。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d103: {
+name: 'D1-03 竞品格局',
+text: `【D1-03 竞品格局】
+承接:D1-01 品类全景图谱 + D1-02 验证配置卡。
+本组课题:(粘贴)。本组最关心的竞品 / 品牌:___。
+
+本节请按验证配置卡的口径,做「竞品图谱 + 待验证痛点假设」。
+
+一、商品层面(同格商品矩阵)
+对与本组课题同一格子的商品,比较:品牌、商品链接、规格(克重/件数)、价格条件(单价、百克价、整箱/单份)、形态、定位、卖点组合(哪些卖点叠加)、风味。
+每个卖点格子只标三种之一:【宣称】(标题/详情)、【回应】(用户原话所说)、【推断】(你的判断)。
+找不到新品时间字段就写「无字段,无法判断」,不要用标题推测。
+
+二、社媒层面
+- 每个竞品提取卖点组合,严格区分宣称 / 回应 / 推断;
+- 找出「正反都有」的原话:同一主题上有人说好、有人说不好,各给原文;
+- 对本组最关心的 2–3 个问题,提出可证伪的痛点假设(编号 H1、H2、H3),每条写清:凭什么怀疑、什么情况推翻它。
+
+口径要求:
+- 竞品社媒样本是每品牌一个关键词、约 20 篇,写明这个样本能代表什么、不能代表什么;
+- 不要用总赞排品牌声量;单条点赞特别高的,先检查是不是活动帖、表情包或重复抓取;
+- 碰到「辣」这类口味词,抽读原文再判断是正面还是负面。
+
+最后输出:一张竞品矩阵 + 一张假设清单。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响下一环 D1-04 的具体缺口)
+【下一步】接下来要做 D1-04 假设定稿与任务下达。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d104: {
+name: 'D1-04 假设定稿与任务下达',
+text: `【D1-04 假设定稿与任务下达】
+承接:D1-01 图谱、D1-02 配置卡、D1-03 竞品图谱与 H1–H3 待验证痛点假设。
+本组要支持的决定:(粘贴)。今晚最想得到答案的一条:(粘贴)。
+
+请把它们整理成「增强 AI 自驱任务卡」,每条主线假设一行,字段固定:
+- 假设键(H1 起编号,之后所有成果都用它引用)
+- 原假设(一句话,可被证伪)
+- 现有支持(带来源与编号)
+- 支持路径(查什么能支持它)
+- 反证路径(查什么能推翻它)
+- 停止条件(必须是程序可判定的东西,例如「找到 N 条反例」「读完某组全部笔记」)
+- 数据来源与权限(先复用资料库;外部补证是否授权、去哪里补)
+
+今晚的任务边界:
+- 只执行这张任务卡里的假设,不扩展新方向;
+- 最多 3 条主线假设,其余放「备查」;
+- 资料库不够、且缺口会改变结论时,才调用外部补证;不需要补证就直接成报;
+- 没查到、没权限、数据确实不存在,三类分开报。
+
+先给我一版任务卡草稿,并指出:哪些字段你拿不准、需要我回答?(只问会改变结论的问题)
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出今晚执行前还差什么)
+【下一步】今晚执行 D1-N 第二轮调研。请在交卡前回答:___(只问一个会改变结论的问题)`
+},
+
+d1n: {
+name: 'D1-N 第二轮调研(晚间执行)',
+text: `【D1-N 第二轮调研 · 晚间执行】
+按 D1-04 的任务卡执行今晚的调研。任务卡:(引用编号)验证配置卡:(引用编号)
+
+执行顺序:
+1. 先复用资料库原件:已有的商品、用户笔记、工艺知识、竞品资料;
+2. 检查覆盖与资格:每条假设被支持到什么程度,哪些是缺口;
+3. 只对「会改变判断的真实缺口」决定是否外部补证,并说明补什么、去哪里补;
+4. 按假设键做 VOC 预聚类,每条原话带笔记标题 / ID;提及率初表写清分母;
+5. 资料够用、不需要补证时,直接成报,不要为凑形式机械采集;
+6. 缺口清单分三类:没查到 / 没权限 / 数据确实不存在;
+7. 达到停止条件就停,并在战报中写明停在哪个条件;
+8. 保存后用真实编号回读,确认正文一致。
+
+最后输出:调研战报(按假设键一页)+ 缺口清单 + VOC 预聚类。
+
+【推送格式】战报生成时,在最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(明早最值得先读的缺口)
+【下一步】明早先做 D2-01 调研验收。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d201: {
+name: 'D2-01 调研验收',
+text: `【D2-01 调研验收】
+承接:D1-N 的调研战报与缺口清单(引用编号)。
+
+请从战报中抽取「战报验收记录」,三列检查:
+1. 假设回应率:H1–H3 每条回应程度(支持 / 部分支持 / 推翻 / 未回应),并说明依据;
+2. 原件覆盖:支撑每条结论的原件是否能点开读到(附笔记 ID / 商品链接);读不到的标「待补证」;
+3. 分母口径:所有比例是否写明分母;没有的,补上或降级;
+另外:
+- 词典打标词是否抽读原文(辣 / 贵 / 量大等);未读的结论降到「假设」;
+- 缺口是否分了「没查到 / 没权限 / 不存在」三类;
+- 「AI 推断」是否与「原件证据」分开写。
+
+最后输出:一张验收记录 + 一份「可用资料集合」(合格的、能回读的原件清单)。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-02 的具体缺口)
+【下一步】先听大课二,然后做 D2-02 VOC 证词聚类。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d202: {
+name: 'D2-02 VOC 证词聚类',
+text: `【D2-02 VOC 证词聚类】
+承接:D2-01 战报验收记录 + 可用资料集合(附笔记 ID)。
+本组人群与场景范围:(粘贴)。
+
+请把可用资料的原话按四层拆开,四层不能混:
+1. 人群(G1–G6 或更细);
+2. 场景(具体时间、地点、行为);
+3. JTBD(用户要完成的事);
+4. 痛点(具体不满)。
+对每个打标痛点词(辣、贵、量大等),抽读原文,标注态度:正 / 负 / 读不出。
+
+输出四张表:
+- 聚类表:每条原话落在哪一层、哪一格;
+- 痛点库:痛点、原话(带 ID)、频次、态度分布;
+- KANO 表:每条痛点的需求类型(基本型 / 期望型 / 兴奋型),标明「频次先验」;
+- 人群 × 场景矩阵:每一格写原话条数与代表原话。
+
+禁止:按打标频次直接排名次;把「读不出态度」的原话删除。
+最后输出:四张表 + 3 个「有原话、没产品」的格子。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-03 的具体缺口)
+【下一步】接下来要做 D2-03 风味趋势与矩阵空白。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d203: {
+name: 'D2-03 风味趋势与矩阵空白',
+text: `【D2-03 风味趋势与矩阵空白】
+承接:D2-02 四张表 + D1-01 品类全景图谱。
+
+请把「需求矩阵」和「供给矩阵」叠在一起,按三类列出空白:
+1. 结构:现在长什么样(价格带、工艺、形态、地域的分布);
+2. 变化:本批数据是单次快照,不能判涨跌;如要判「在变」,必须说明时间序列来源,没有就写「本次不验证」;
+3. 未覆盖:该有的东西还没有——但每个「未覆盖」都必须先查同格竞品,写明「同格已有 N 个,其中谁」。
+
+每个空白格给一行「机会指标」:要验证什么、用什么数据能验证、本次能不能验证。
+禁止把三类放在同一张排序表里比较;禁止把「搜索页找不到」写成「市场空白」。
+
+最后输出:产品机会及指标初表(一行一个机会,五列:空白格 / 类别 / 供给证据 / 需求证据 / 需要验证的指标)。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-04 的具体缺口)
+【下一步】接下来要做 D2-04 三源交叉推理。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d204: {
+name: 'D2-04 三源交叉推理',
+text: `【D2-04 三源交叉推理】
+承接:D2-03 机会及指标初表 + D2-02 四张表 + 本组研发侧对工艺的判断。
+本组最想先认证的 2 个空白格:(粘贴)。
+
+对每个空白格做三源交叉:
+- 源一 商品事实:同格有哪些商品、价格带、卖点组合(带商品链接);
+- 源二 用户原声:有哪些原话直接指向这一格(带笔记 ID 与态度);
+- 源三 工艺条件:这一格做不做得出来(参数、成本、稳定性)——你写你判断的,其余标「待工艺确认」。
+
+每张「机会卡」固定 6 个字段:
+1. 一句话结论(可被推翻的判断);
+2. 三源证据(每条带来源与编号);
+3. 反例(什么情况下这个结论不成立);
+4. 还缺什么(写成「待确认:……」并说明影响哪个结论);
+5. 下一步验证(先补哪一条证据);
+6. 工艺注释(研发侧亲手写:参数、条件、风险;AI 不得代写为「可行」)。
+
+评级:三源齐全 → 候选;两条线 → 候选(弱);一条线 → 线索。
+最后输出:候选机会清单 V1.0(2–3 张机会卡)。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出下午 D2-05 排序前还差什么)
+【下一步】先听大课三,然后做 D2-05 机会验证与排序。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d205: {
+name: 'D2-05 机会验证与排序',
+text: `【D2-05 机会验证与排序】
+承接:候选机会清单 V1.0(2–3 张机会卡)。
+
+请对每张机会卡打三个维度分(1–3):
+- 证据强度:三源各有多少条证据;
+- 可做性:现有产线 / 工艺 / 供应商能不能做;
+- 商业价值:价格带、毛利、量级(这一项标注「需本组复核」)。
+每个分数后写一句话依据,并标注依据是「课堂证据」还是「本组经验」。
+
+排序规则:任何一维得 1 分的机会,不得排进前三。
+无法打分的,单独列入「未知项表」:缺什么数据、能用什么方式补、本次能不能补。未知项不是低分项。
+
+最后输出:优先级机会清单(含分值、依据、排序理由)+ 未知项单列。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-06 的具体缺口)
+【下一步】接下来要做 D2-06 商业及供应链回推。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d206: {
+name: 'D2-06 商业及供应链回推',
+text: `【D2-06 商业及供应链回推】
+承接:D2-05 优先级机会清单,本组主攻机会:(粘贴)工艺路径:改现有配比(B0)/ 新增并行产品线(O1)/ 两者对比。
+
+请对主攻机会做「回推表 + 候选机会清单 V2.0」:
+1. 两条路:B0 现状、O1 目标方案;只有收入、渠道费用、损耗比例都相同时,两者才可直接比较,否则写明差异;
+2. 三条费用分开:一次费用 / 资本投入 / 营运资金;
+3. 成本结构:按知识库行业通行值拆(面饼 34–38% / 调料 24–30% / 包材 12–13%……),换算到单位成本与目标价格带;
+4. 供应商:代工价 2.1–3.2 元/袋、验厂比例 42%、区域分工;缺装箱/外箱/配送/损耗的标「待确认」;
+5. 工艺与合规:工艺参数、GB 17400-2015(水分 ≤10%、酸价 ≤1.8、过氧化值 ≤0.25)、GB 2760-2024 添加剂限量;以标准正文为准。
+
+所有估算标「课堂估算」;本组经验值标「经验值」;缺的标「待确认」。
+最后输出:回推表 + V2.0 机会卡(在 V1.0 六字段外增加:成本区间 / 目标价格带 / 两条路对比 / 合规条件)。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-07 的具体缺口)
+【下一步】接下来要做 D2-07 价值主张与核心卖点。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d207: {
+name: 'D2-07 价值主张与核心卖点',
+text: `【D2-07 价值主张与核心卖点】
+承接:候选机会清单 V2.0 + D2-02 痛点库原话。
+本组主推版本面向的价格带 / 人群 / 场景:(粘贴)。
+
+第一步:写价值主张卡
+- 一句主主张(不超过 20 字,用户能复述);
+- 三条收益(用户能感知到的好处,不是工艺参数);
+- 三条证据(对应组件 / 原话 / 商品事实,带 ID);
+- 证据边界:能说什么 / 不能说什么 / 合规标示。
+
+第二步:卖点清单,按价格带 × 人群 × 场景各 2–3 个版本。
+要求:
+- 每一句卖点都要对到一条原话或一个商品事实;
+- 研发术语(非油炸、热风三段控温、含水 8–12%)翻译成市场语言,必要时保留一个“技术背书”小注;
+- 「健康 / 减脂 / 养胃」等功效宣称在无合规依据时一律不写;
+- 标出让本组删掉的那些版本,并说明为什么删(例如「技术上说得过去但做不到」)。
+
+最后输出:价值主张卡 + 卖点清单(主推版 + 备选版 + 不能说的话)。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出影响 D2-08 的具体缺口)
+【下一步】接下来要做 D2-08 概念提案与分享。请先回答:___(只问一个会改变结论的问题)`
+},
+
+d208: {
+name: 'D2-08 概念提案与分享',
+text: `【D2-08 概念提案与分享】
+承接:候选机会清单 V2.0 + 回推表 + 价值主张卡 + 卖点清单。
+
+请按「结论 → 依据 → 风险 → 行动」串成一份提案,并生成三个版本:
+- 一句话版(决策圈用,不超过 40 字,说清做什么、为什么现在、要什么资源);
+- 一页版(协同圈用,5 页以内);
+- 全案版(归档用)。
+
+同时输出:
+1. 质询清单:决策圈 / 协同圈 / 生态圈各 3 个最可能问到的问题,标出哪些本组能答、哪些答不出;
+2. 矛盾清单:三段分析互相打架的地方,都保留下来,不要删;
+3. 候选清单 V3.0:质询后更新版本,记录每处修改理由;
+4. 成果导航:13 份产出物各自的保存位置、一句话用途、结营后第一周先看哪一份。
+
+要求:只做减法,每条留给结论的都是支撑结论的那几条证据。示意图类内容标注「生成示意,需设计确认」,不出现任何真实品牌 Logo。
+
+【推送格式】结束本环节时,在回复最后用这三行总结:
+【本轮产出】你手上有:___
+【还缺什么】___(指出结营后第一周最该补的那个缺口)
+【下一步】结营后第一周陪练:拿 V3.0 回来先补一个「答不出」的问题。请先回答:___(只问一个会改变结论的问题)`
+}
+
+};
+
+// m1 · 开场:封面 / 怎么读这本手册 / 三个半天总览 / 产品经理定位 / 八步 SOP / 产出物速查
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'cover',
+title: '产品创新工作坊 学员手册',
+sub: '智研先锋计划 · AI 赋能产品研发实战营 · 学员手册 v3',
+lead: '三个半天,3 份大课详案,13 个研究环节,13 份写死的产出物。从「我觉得」走到「能讲清楚为什么选它」。',
+thesis: '这次坐在教室里的,是<b>产品经理</b>——未来的<b>品类负责人</b>。三个半天练的,是同一个产品经理在<b>研发侧、市场侧、经营侧</b>三种视角之间来回切换的能力。',
+facts: [
+  ['学员', '研发中心产品经理 · 每组 5–6 人 · 按课题方向分组'],
+  ['节奏', 'D1 下午 13:30–17:30 · D2 上午 09:00–12:20 · D2 下午 13:30–17:30'],
+  ['大课', '大课一 90 分钟(战略层 → 组织层 → 个人层)· 大课二 50 分钟 · 大课三 50 分钟'],
+  ['产出', '13 个环节 = 13 份产出物,每份写明:长什么样 / 干什么用 / 交给谁'],
+  ['数据', '电商 400 SKU · 用户笔记 260 篇 · 竞品社媒 120 篇 · 工艺知识库 49 条']
+],
+note: '本手册引用的所有数字都来自课堂数据包(2026-11-01 单次快照),并已按原始文件复核;平台实时数据以当天实际连接为准。'
+},
+
+{
+kind: 'meta', id: 'setup', title: '怎么看这本手册', group: '开始之前',
+lead: '每个环节按同一套七步写:<b>先想清楚 → 这一节要解决什么 → 怎么做 → 拿到什么(产出物规范)→ 小组讨论 → 进度自检 → AI 推送</b>。产出物规范是这一版的重心:名称、真实样卡、用途、流转,四件事缺一不可。',
+blocks: [
+{t: '一、这一版新增了什么', html: `
+<table class="tbl"><thead><tr><th>v2 时的情况</th><th>v3 怎么写</th></tr></thead><tbody>
+<tr><td>只说「产出机会点卡片」</td><td>每个环节一张<b>产出物规范板</b>:名称 + 形态 + 一张用真实数字写的样卡 + 三块用途 + 交给谁、下一环怎么用</td></tr>
+<tr><td>大课只讲方法</td><td>大课一扩成 90 分钟四段:宏观趋势 → 战略层 / 组织层 / 个人层 → 新秀与老品牌、市场侧与研发侧 → SOP 与链路</td></tr>
+<tr><td>环节结束靠学员自己往下推</td><td>每个提示词结尾都带<b>推送格式</b>;每个环节结尾有<b>AI 推送</b>:本轮产出 / 还缺什么 / 下一步</td></tr>
+<tr><td>按岗位写「研发、市场、供应链分别做什么」</td><td>只有一个角色:<b>产品经理</b>。同一个人要在研发侧、市场侧、经营侧切换视角</td></tr>
+</tbody></table>`},
+{t: '二、产出物规范板怎么读', html: `
+<div class="card-format">
+<div><b>1 它长什么样</b><span>一张 1:1 复刻的样卡,字段位置与真实交付一致,数字来自课堂数据包</span></div>
+<div><b>2 它是用来干什么的</b><span>三块用途:支持什么决定 / 拦住什么错 / 沉淀成什么资产</span></div>
+<div><b>3 它交给谁</b><span>上一环节的哪个产出、下一环节的哪个字段、谁来签字放行</span></div>
+</div>
+<p>样卡里的判断对错不重要,<b>格式和证据位置</b>才重要。你组填出来的卡,字段一个都不能少;内容必须来自本组课题,不能用样卡的结论。</p>`},
+{t: '三、AI 推送怎么读', html: `
+<p>每个环节结束时,数字分身会主动交回三段,不用你去问:</p>
+<div class="push"><div class="push-bar"><b>AI 推送</b><span>格式示例</span></div><div class="push-rows">
+<div class="push-row"><b>【本轮产出】</b><p>你现在手上有:品类全景图谱 v1,三棵树都画完了,但需求树有 2 个分支只有 1 条原话。</p></div>
+<div class="push-row"><b>【还缺什么】</b><p>缺「≤4 元 × 非油炸」这一格的需求原话;不补上,D2 交叉时这格只能标「待确认」。</p></div>
+<div class="push-row"><b>【下一步】</b><p class="ask">接下来要做 D1-02 验证纪律。请先回答:本组的价格结论,能不能引用康师傅 ≤4 元 22 个这一说法?</p></div>
+</div></div>
+<p>推送的作用是让流程自己往前走:AI 总结你已经做到哪、点出卡在哪、把下一个问题递到你手上。你要做的只有一件事——<b>回答那个问题</b>。</p>`},
+{t: '四、三种标记', html: `
+<table class="tbl"><thead><tr><th>标记</th><th>含义</th><th>怎么处理</th></tr></thead><tbody>
+<tr><td><span class="chip tag">待确认</span></td><td>缺真实数据、企业标准或产品条件,AI 不能编造</td><td>列进缺口清单,能补则补,补不到就带着走</td></tr>
+<tr><td><span class="chip">未经正式确认</span></td><td>课堂过程成果,不是正式报告</td><td>结营后走正式流程才能对外使用</td></tr>
+<tr><td><span class="chip">示例</span></td><td>手册给的样卡,不是本组调研结果</td><td>只理解格式,不能当本组证据</td></tr>
+</tbody></table>`},
+{t: '五、为什么每节开头都要先填「我还不知道的」', html: `
+<p>AI 的规则是<b>先复用上下文、能查的自行查,只在会改变结论时才提问</b>。它不会上来问你一堆问题,会先往下走。</p>
+<p>你填「我不知道」的部分,决定 AI 往哪里使劲补证据,也决定你自己在小组讨论时盯哪里。填不出来,就把「我不知道我该问什么」原样写进提示词,让 AI 帮你把问题列出来。</p>`},
+{t: '六、Skill 的八条硬规则', html: `
+<p class="muted">这八条是流程规则,不是注意事项。读懂它,你就知道 AI 什么时候停下来问你、什么时候自己查。</p>
+<table class="tbl"><thead><tr><th>#</th><th>规则</th><th>你会看到什么</th></tr></thead><tbody>
+<tr><td>1</td><td>先复用上下文,能查的自行查</td><td>AI 读完本组前序产出才开口</td></tr>
+<tr><td>2</td><td>只在「会改变结论」时才提问</td><td>问题少而尖,答不上来它先往下走</td></tr>
+<tr><td>3</td><td>不许编造企业标准、用户选择或产品条件</td><td>缺就写「待确认」</td></tr>
+<tr><td>4</td><td>资料库不是研究范围的上限</td><td>缺口会改变判断时,可以外部补证</td></tr>
+<tr><td>5</td><td>没查到 ≠ 没权限 ≠ 数据不存在</td><td>缺口清单分三类报</td></tr>
+<tr><td>6</td><td>不需要补证时直接成报</td><td>不为凑格式机械采集</td></tr>
+<tr><td>7</td><td>课堂成果 ≠ 正式成果</td><td>产出物抬头标注「未经正式确认」</td></tr>
+<tr><td>8</td><td>保存、回读、看板核对、浏览器核对是四个步骤</td><td>四条分开报,不能互相代替</td></tr>
+</tbody></table>`}
+]
+},
+
+{
+kind: 'meta', id: 'overview', title: '三个半天总览', group: '开始之前',
+lead: '一条链路:<b>定课题 → 看供给 → 看需求 → 找交叉 → 验机会 → 算可行 → 定卖点 → 出方案</b>。每个半天的出口,就是下一个半天的入口。<a href="../overview/index.html">总览图</a>把 13 个环节、3 份大课、13 份产出物和它们之间的箭头画在同一页。',
+blocks: [],
+render: function () {
+  var halves = [
+    { n: 'D1 下午', t: '13:30–17:30', th: '从「我觉得」到「有证据」', c: 'var(--red)',
+      steps: [['big1', '大课一 · 产品创新的完整架构(90 分钟)'], ['d101', 'D1-01 品类全景扫描'], ['d102', 'D1-02 验证纪律'], ['d103', 'D1-03 竞品格局'], ['d104', 'D1-04 假设定稿与任务下达'], ['d1n', 'D1-N 第二轮调研(晚间)']],
+      out: '一个决定 + 三个待答问题 + 一份交给 AI 过夜的任务卡' },
+    { n: 'D2 上午', t: '09:00–12:20', th: '从「有证据」到「有机会」', c: 'var(--amber)',
+      steps: [['d201', 'D2-01 调研验收'], ['big2', '大课二 · 机会发现(50 分钟)'], ['d202', 'D2-02 VOC 证词聚类'], ['d203', 'D2-03 风味趋势与矩阵空白'], ['d204', 'D2-04 三源交叉推理']],
+      out: '候选机会清单 V1.0(2–3 个方向,各带三条证据)' },
+    { n: 'D2 下午', t: '13:30–17:30', th: '从「有机会」到「能落地」', c: 'var(--teal)',
+      steps: [['big3', '大课三 · 收敛与表达(50 分钟)'], ['d205', 'D2-05 机会验证与排序'], ['d206', 'D2-06 商业及供应链回推'], ['d207', 'D2-07 价值主张与核心卖点'], ['d208', 'D2-08 概念提案与分享']],
+      out: '概念提案 + 候选清单 V3.0 + 一份能过会的材料' }
+  ];
+  var s = '<h3>三个半天的分工</h3><div class="halves">' + halves.map(function (v) {
+    return '<div class="half-card" style="--acc:' + v.c + '"><div class="hc-head"><b>' + v.n + '</b><span>' + v.t + '</span></div><h4>' + v.th + '</h4><ol>' +
+      v.steps.map(function (x) { return '<li><a href="#' + x[0] + '">' + x[1] + '</a></li>'; }).join('') + '</ol><p class="hc-out"><span>离场时</span>' + v.out + '</p></div>';
+  }).join('') + '</div>';
+  s += '<h3>课表(时间以现场为准)</h3><div class="tbl-scroll"><table class="tbl compact"><thead><tr><th>时段</th><th>时间</th><th>内容</th><th>类型</th></tr></thead><tbody>' +
+    [['D1', '13:30–15:00', '开场 + 大课一 · 产品创新的完整架构', '大课'],
+     ['D1', '15:00–15:40', 'D1-01 品类全景扫描', '练习'],
+     ['D1', '15:40–16:05', 'D1-02 验证纪律', '练习'],
+     ['D1', '16:05–16:45', 'D1-03 竞品格局', '练习'],
+     ['D1', '16:45–17:20', 'D1-04 假设定稿与任务下达', '练习'],
+     ['D1', '17:20–17:30', '交任务卡、D1 收尾推送', '收尾'],
+     ['D1 晚', '过夜', 'D1-N 第二轮调研:AI 按任务卡跑', 'AI 自驱'],
+     ['D2', '09:00–09:25', 'D2-01 调研验收', '练习'],
+     ['D2', '09:25–10:15', '大课二 · 机会发现', '大课'],
+     ['D2', '10:15–11:05', 'D2-02 VOC 证词聚类', '练习'],
+     ['D2', '11:05–11:45', 'D2-03 风味趋势与矩阵空白', '练习'],
+     ['D2', '11:45–12:20', 'D2-04 三源交叉推理 → 候选清单 V1.0', '练习'],
+     ['D2', '13:30–14:20', '大课三 · 收敛与表达', '大课'],
+     ['D2', '14:20–15:05', 'D2-05 机会验证与排序', '练习'],
+     ['D2', '15:05–15:50', 'D2-06 商业及供应链回推', '练习'],
+     ['D2', '15:50–16:30', 'D2-07 价值主张与核心卖点', '练习'],
+     ['D2', '16:30–17:30', 'D2-08 概念提案与分享', '练习 + 展演']
+    ].map(function (r) { return '<tr><td>' + r[0] + '</td><td class="num">' + r[1] + '</td><td>' + r[2] + '</td><td>' + r[3] + '</td></tr>'; }).join('') +
+    '</tbody></table></div>';
+  s += '<h3>每个环节的标准节奏</h3><div class="loop4">' +
+    [['认知盘点', '3 分钟', ['自己填四栏,尤其「我还不知道的」']],
+     ['AI 跑任务', '10–25 分钟', ['提示词 + 四栏一起发', 'AI 执行期间,老师讲一个真实数据的反常识发现']],
+     ['讨论与收尾', '5–10 分钟', ['对照产出物规范补字段', '答 AI 推送里的那个问题', '把卡交给下一环']],
+     ['展演', '每半天 1 次', ['一组上台讲它手上的产出物', '其他组按产出物规范挑毛病']]
+    ].map(function (x, i) { return '<div class="loop-step"><div class="ls-no">' + (i + 1) + '</div><h3>' + x[0] + '</h3><p class="ls-sub">' + x[1] + '</p><ul>' + x[2].map(function (y) { return '<li>' + y + '</li>'; }).join('') + '</ul></div>'; }).join('') + '</div>';
+  s += '<h3>分组:按课题方向,不按部门</h3><p>这次参与的都是研发中心的人,按部门分没有意义。每组 5–6 人,<b>每组自选一个课题方向</b>(例如:居家囤货 × 常备、宿舍夜宵、户外出行、健康轻负担、地域风味、一人食)。方向一旦选定,三个半天都在这个方向上走。</p>' +
+    '<p class="muted">参考:D1-01 里的六大人群就是六个候选方向——G1 上班族工作餐与加班餐、G2 学生宿舍与夜宵、G3 户外露营与出行、G4 健康控卡、G5 一人食与家庭囤货、G6 地域风味与高端尝鲜。课题卡在课前确认。</p>';
+  return s;
+}
+},
+
+{
+kind: 'meta', id: 'pm', title: '你是谁:产品经理 = 未来品类负责人', group: '开始之前',
+lead: '这不是一句口号。它决定了三件事:你为什么要学市场侧和经营侧、每个环节为什么追问「卖给谁、卖多少、值不值」,以及这个流程最后会把你放到什么位置上。',
+blocks: [
+{t: '一、只有一个角色:产品经理', html: `
+<div class="pm-hero"><span class="pm-tag">角色定位</span><h3>你不是「只做研发的人」,你是「对这个品类生意负责的人」</h3><p>研发是你的本行。这一轮要补齐的是另外两块:能像市场一样想清楚卖给谁、怎么说;能像经营者一样算清楚毛利、价格带、渠道和生命周期。三块能力长在同一个人身上,各有侧重,不是分工给三个部门。</p></div>
+<p>所以本手册里不会出现「请市场同事补充」「研发和市场怎么分工」这种说法——那都是同一个你在不同环节切换的视角。常见的切换点:</p>
+<table class="tbl"><thead><tr><th>环节</th><th>研发侧视角(你的本行)</th><th>市场侧视角(要补的)</th><th>经营侧视角(要建立的)</th></tr></thead><tbody>
+<tr><td>D1-01 品类全景</td><td>工艺、形态、成本结构</td><td>人群、场景</td><td>价格带分层</td></tr>
+<tr><td>D1-03 竞品格局</td><td>同一工艺路线做得怎么样</td><td>卖点组合、正反原话</td><td>同一条价格带里谁占位</td></tr>
+<tr><td>D2-04 三源交叉</td><td>工艺条件支持吗</td><td>用户原话指向吗</td><td>空白格有没有生意</td></tr>
+<tr><td>D2-06 商业回推</td><td>做不做得出来</td><td>消费者接受吗</td><td>划不划算</td></tr>
+<tr><td>D2-07 卖点</td><td>证据允许说到哪</td><td>用户听得懂吗</td><td>价格带撑不撑得起这个说法</td></tr>
+</tbody></table>`},
+{t: '二、产品经理要具备的三块能力', html: `
+<div class="caps">
+<div class="cap" style="--acc:var(--red)"><h4>研发侧</h4><span class="cap-lv">本行</span><ul><li>配方</li><li>工艺</li><li>形态</li><li>成本</li></ul><p class="cap-q">判断问题:这个方案在产线上做不做得出来?成本落在哪个区间?</p></div>
+<div class="cap" style="--acc:var(--amber)"><h4>市场侧</h4><span class="cap-lv">要补</span><ul><li>人群</li><li>场景</li><li>卖点</li><li>传播</li></ul><p class="cap-q">判断问题:谁在什么场景下买?他听得懂、记得住这句卖点吗?</p></div>
+<div class="cap" style="--acc:var(--teal)"><h4>经营侧</h4><span class="cap-lv">要建立</span><ul><li>毛利</li><li>价格带</li><li>渠道</li><li>生命周期</li></ul><p class="cap-q">判断问题:这条价格带值不值得进?这个产品活多久、能不能升级?</p></div>
+</div>
+<p>三个半天就是练这三块的<b>整合</b>:D1 用研发侧的眼睛看供给、用市场侧的眼睛看竞品;D2 上午把两块拼成机会;D2 下午把经营侧加进来,变成一份算得过账的提案。</p>`},
+{t: '三、这条能力线通向哪里', html: `
+<p>品类经营需要一个对全局负责的人,这个人通常叫品类经理或品牌经理。产品经理就是这个位置上的人选——两者的差别不在会不会做研发,而在<b>有没有把整个品类的生意放在自己肩上</b>。</p>
+<table class="tbl"><thead><tr><th></th><th>产品经理(你现在的岗位)</th><th>品类负责人(发展到的位置)</th></tr></thead><tbody>
+<tr><td>对什么负责</td><td>一个产品从想法到落地</td><td>一个品类的生意:增长、利润、心智</td></tr>
+<tr><td>看什么数据</td><td>配方、工艺、竞品、用户原声</td><td>再加毛利、价格带、渠道、生命周期</td></tr>
+<tr><td>提报什么</td><td>产品方案</td><td>产品分级、品牌内容、预算、品类战略</td></tr>
+</tbody></table>
+<p class="muted">大课一第二段会把品类经营的架构、品牌经理责任制的五层结构和四阶成长路径讲清楚。这里只先立一个判断:<a href="#big1">你现在做的每一步,都在往那个位置靠</a>。</p>`}
+]
+},
+
+{
+kind: 'meta', id: 'sop', title: '产品创新八步:这门课的骨架', group: '开始之前',
+lead: '13 个环节只是这八步的切分。每个环节开头都会标出它对应第几步、回答哪个问题、交出哪份产出物。',
+blocks: [],
+render: function () {
+  var steps = [
+    ['①', '定课题', '要做什么决定', 'd1', 'D1'],
+    ['②', '看供给', '市场上有什么', 'd1', 'D1'],
+    ['③', '看需求', '用户要什么', 'd1', 'D1'],
+    ['④', '找交叉', '哪里有空白', 'd2a', 'D2 上午'],
+    ['⑤', '验机会', '这个空白值不值得做', 'd2a', 'D2 上午'],
+    ['⑥', '算可行', '做不做得出来、划不划算', 'd2p', 'D2 下午'],
+    ['⑦', '定卖点', '怎么说用户听得懂', 'd2p', 'D2 下午'],
+    ['⑧', '出方案', '一份能过会的提案', 'd2p', 'D2 下午']
+  ];
+  var map = [
+    ['① 定课题', 'D1-01 定本组要支持的决定', 'd101'], ['② 看供给', 'D1-01 供给树 · D1-03 竞品图谱', 'd103'],
+    ['③ 看需求', 'D1-03 痛点假设 · D1-N / D2-01 证据收口', 'd1n'], ['④ 找交叉', 'D2-02 聚类 · D2-03 空白 · D2-04 三源交叉', 'd204'],
+    ['⑤ 验机会', 'D2-04 定证据闭环 · D2-05 排序', 'd205'], ['⑥ 算可行', 'D2-06 商业及供应链回推', 'd206'],
+    ['⑦ 定卖点', 'D2-07 价值主张与核心卖点', 'd207'], ['⑧ 出方案', 'D2-08 概念提案', 'd208']
+  ];
+  var s = '<div class="sop">' + steps.map(function (x) {
+    return '<div class="sop-step"><span class="sop-no">' + x[0] + '</span><b>' + x[1] + '</b><p class="sop-q">' + x[2] + '</p><span class="sop-d ' + x[3] + '">' + x[4] + '</span></div>';
+  }).join('') + '</div>';
+  s += '<p class="sop-legend"><span><i class="l1"></i>D1 下午:① ② ③</span><span><i class="l2"></i>D2 上午:④ ⑤</span><span><i class="l3"></i>D2 下午:⑥ ⑦ ⑧</span></p>';
+  s += '<h3>八步 × 环节</h3><div class="tbl-scroll"><table class="tbl"><thead><tr><th>步骤</th><th>落在哪个环节</th></tr></thead><tbody>' +
+    map.map(function (m) { return '<tr><td><b>' + m[0] + '</b></td><td><a href="#' + m[2] + '">' + m[1] + '</a></td></tr>'; }).join('') + '</tbody></table></div>';
+  s += '<p>两条硬约束:<b>没验证过的机会不能进卖点;没算过商业条件的卖点不能进提案。</b>这也是 D2-04 → D2-06 的版本编号(V1.0 / V2.0 / V3.0)存在的原因——每一版都要比上一版多过一道关。</p>';
+  s += '<div class="block note"><h3>D1 离场时,你手上会有</h3><ol><li><b>一个明确要做的决定</b>——本组三个半天到底要支持哪个产品决定;</li><li><b>三个待答问题</b>——会改变结论、而资料现在还回答不了的那三个;</li><li><b>一份能跑的研究任务</b>——增强 AI 自驱任务卡,带支持路径、反证路径和停止条件。</li></ol></div>';
+  return s;
+}
+},
+
+{
+kind: 'meta', id: 'index', title: '13 份产出物速查', group: '开始之前',
+lead: '每个环节一份产出物,形态、用途、流向固定。任何一份缺失或字段不全,下一环的输入就是缺的——AI 推送会在环节结束时点出来。',
+blocks: [],
+render: function () {
+  var rows = [
+    ['D1-01', '品类全景图谱', '三栏表', '供给树 / 需求树 / 供需缺口', 'd101'],
+    ['D1-02', '本题验证配置卡', '一页卡', '资料资格 / 统计口径 / 引文规则 / 分歧处理', 'd102'],
+    ['D1-03', '竞品图谱 + 待验证痛点假设', '矩阵表 + 假设清单', '卖点组合矩阵 / 正反原话 / 2–3 条可证伪假设', 'd103'],
+    ['D1-04', '增强 AI 自驱任务卡', '一页卡', '假设键 / 支持路径 / 反证路径 / 停止条件', 'd104'],
+    ['D1-N', '调研战报 + 缺口清单', '报告 + 缺口表', '按假设键的回应 / 三类缺口 / 原件覆盖', 'd1n'],
+    ['D2-01', '战报验收记录', '检查表', '假设回应率 / 原件覆盖 / 分母口径', 'd201'],
+    ['D2-02', '聚类表 + 痛点库 + KANO 表 + 人群 × 场景矩阵', '四张表', '人群 → 场景 → JTBD → 痛点,四层不混', 'd202'],
+    ['D2-03', '产品机会及指标初表', '机会 × 指标表', '结构 / 变化 / 未覆盖三类,各带指标', 'd203'],
+    ['D2-04', '候选机会清单 V1.0', '机会卡 ×6 字段', '结论 / 三源证据 / 反例 / 未知 / 下一步 / 工艺注释', 'd204'],
+    ['D2-05', '优先级机会清单 + 未知项单列', '排序表 + 未知项表', '证据强度 × 可做性 × 商业价值', 'd205'],
+    ['D2-06', '回推表 + 候选机会清单 V2.0', '成本表 + 更新版机会卡', 'B0 / O1 两条路、三条费用、工艺与合规条件', 'd206'],
+    ['D2-07', '价值主张卡 + 卖点清单', '一页卡 + 卖点表', '一句主张、三条收益、证据边界、多版本表达', 'd207'],
+    ['D2-08', '概念提案 + 候选清单 V3.0 + 成果导航', '提案文档', '能过会的一页 + 质询记录 + 训后导航', 'd208']
+  ];
+  var s = '<div class="jump-grid">' + rows.map(function (r) {
+    return '<a class="jump" href="#spec-' + r[4] + '"><b>' + r[0] + '</b><span>' + r[1] + '</span><em>形态:' + r[2] + '</em><i>字段:' + r[3] + '</i></a>';
+  }).join('') + '</div>';
+  s += '<p class="muted">点任意一份产出物,直接跳到它的规范板(真实样卡 + 用途 + 流转)。</p>';
+  return s;
+}
+}
+);
+
+// m2 · 大课详案:大课一(90 分钟,四段)/ 大课二(50 分钟)/ 大课三(50 分钟)
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'big', id: 'big1', no: '大课一', title: '产品创新的完整架构', group: '大课详案',
+meta: [['D1 13:30–15:00 · 90 分钟', 'tag'], ['学员:研发中心产品经理', ''], ['讲法:四段递进,配现场练习', ''], ['附:讲授稿 + 数据速查 + 讲师备忘', '']],
+lead: '从<b>战略层</b>到<b>组织层</b>,再到<b>个人层</b>:先讲清楚消费环境、创新性质、AI 和方便面行业这四件事发生了什么变化;再讲清楚产品创新长在「品类经营」这张网里、由「品牌经理责任制」落到人身上;最后讲清楚新秀与老品牌、市场侧与研发侧的不同创新逻辑,以及这套 SOP 怎么切进三个半天。',
+outline: [
+  ['第一段 · 20 分钟', '宏观趋势与行业变局', '为什么现在要换打法'],
+  ['第二段 · 30 分钟', '战略层 → 组织层 → 个人层', '创新谁来负责、怎么落到你'],
+  ['第三段 · 25 分钟', '新秀 vs 老品牌 · 市场侧 vs 研发侧', '康师傅在哪、你从哪一侧切入'],
+  ['第四段 · 15 分钟', '产品创新 SOP + 三个半天链路', '今天下午从哪一步开始', true]
+],
+before: [
+{t: '这一课的位置', html: `
+<p>这是三个半天的开场课,也是整个工作坊的「总图」。它不教你某个具体动作,而是把产品创新这件事的四层关系摆给你看:<b>外面发生了什么(宏观)→ 谁该负责这件事(战略与组织)→ 你从哪一侧切入(新秀与老品牌、市场与研发)→ 具体怎么做(SOP)</b>。</p>
+<p>后两节大课是这一节在方法层面的展开:<a href="#big2">大课二</a>讲怎么发现机会,<a href="#big3">大课三</a>讲怎么收敛、表达和交付。13 个环节则是把第四段的 SOP 拆成可以一步步执行的动作。</p>`},
+{t: '讲法:四段递进 + 现场练习', html: `
+<p>如果你需要照着讲,每一段下面都有一个折叠的<b>「讲授稿」</b>,用口语写好了,可以直接念;<b>「数据速查」</b>把这一段要引用的数字和一页板书列出来。四段之间各有一个小练习,学员不用等到 D1-01 才动手:</p>
+<table class="tbl"><thead><tr><th>时间</th><th>内容</th><th>现场练习</th></tr></thead><tbody>
+<tr><td>0–20 分</td><td>第一段 宏观趋势与行业变局</td><td>练习一:在 4 × 4 格子里写下你能想到的新品(3 分钟)</td></tr>
+<tr><td>20–50 分</td><td>第二段 战略层 → 组织层 → 个人层</td><td>练习二:给你的课题定位——哪一类创新、哪一格被卡住(3 分钟)</td></tr>
+<tr><td>50–75 分</td><td>第三段 新秀与老品牌、市场侧与研发侧</td><td>练习三:拆解「挂面截三段」,写出它倒逼研发的三个问题(5 分钟)</td></tr>
+<tr><td>75–90 分</td><td>第四段 SOP 与三个半天链路</td><td>练习四:写下本组三步走 + 三个待答问题(5 分钟,直接带进 D1-01)</td></tr>
+</tbody></table>
+<p class="muted">练习四的产出不单列成产出物,它写进 D1-01 的认知盘点四栏,作为品类全景图谱的起点。</p>`}
+],
+parts: [
+{
+ id: 'big1-p1', no: '第一段', title: '宏观趋势与行业变局', time: '20 分钟', goal: '换打法:从抢增量到在存量里找结构',
+ pts: [
+  {t: '0–4 分', ti: '开场:先把问题问出来', html: `
+<p>开场问全场一个问题,收 5 个答案,不评判,写在黑板上:</p>
+<div class="script"><p class="say">「我们自己的新品,最近一款是在哪个格子里做出来的?」</p><p class="say">「如果让你现在加一句话——方便面还能怎么做——你会说什么?」</p></div>
+<p>先把答案收上来。等讲完这 90 分钟,大家会发现:多数答案落在的格子,其实已经很挤;真正空着的格子,不在大家习惯看的地方。</p>`},
+  {t: '4–8 分', ti: '消费环境变了:从「抢增量」到「存量里找结构」', html: `
+<p>过去三十年,方便面的增长公式很简单:出一个大单品,靠铺货规模把它推成增量。行业现在的位置是:<b>大单品增量时代已经结束,创新不再是抢新客,而是在巨大的存量里把结构做开</b>。</p>
+<p>结构做开,就是把「谁、在什么场景、花多少钱、要什么」重新组合。课堂数据给了三个切面:</p>
+<ul>
+<li><b>按人群切。</b>六组用户笔记里,「口味新鲜」合计命中 106/260 篇,是六组需求中命中最多的一项;「方便/快手」97/260,六组全部进前三——但它是品类前提,不是差异化。</li>
+<li><b>按场景切。</b>「仪式感」在户外出行组排第一(29 条),在上班族组几乎不出现——同一款面,换个场景,价值完全不同。</li>
+<li><b>按价格切。</b>125 个有效价里,≤4 元占 42.4%,4–6 元 34.4%,6–9 元 10.4%,&gt;9 元 12.8%。超过四分之一的商品站在 6 元以上——价格带分层已经发生。</li>
+</ul>
+<div class="block note"><h3>第一段的第一个判断</h3><p>增量时代,创新是「做出一个更大的单品」;存量时代,创新是「在一个已经很大的盘子里,找到还没被占满的结构格子」。</p></div>`},
+  {t: '8–12 分', ti: '创新的性质变了:从营销驱动到工艺驱动', html: `
+<p>以前的产品创新,绝大多数是营销驱动的口味微调:换个口味、换个包装、请个代言人。这套动作用来做防御可以,但它做不到「代际突破」——因为真正决定要不要被替代的,是<b>工艺和形态</b>。</p>
+<p>方便面行业走过三次代际:<b>油炸 → 非油炸 → 半干鲜熟</b>。每一次,胜负手都从营销端移到了工厂端:</p>
+<table class="tbl"><thead><tr><th>代际</th><th>代表工艺</th><th>关键参数(知识库,行业通行值)</th><th>难点</th></tr></thead><tbody>
+<tr><td>油炸</td><td>棕榈油高温脱水</td><td>140–160℃,60–110 秒;含水 3–6%,含油 18–22%</td><td>成熟,成本低;「非油炸」诉求下是短板</td></tr>
+<tr><td>非油炸</td><td>热风三段控温 / 挤压熟化</td><td>80–90℃/60–70% 湿 → 90–100℃/30–40% 湿 → 70–80℃ 低湿;含水 8–12%</td><td>要专用线;复水口感与蓬松度是核心</td></tr>
+<tr><td>半干鲜熟</td><td>蒸煮后酸浸保鲜</td><td>pH 4.2–4.6,含水 20–26%,aw 0.85–0.90</td><td>口感接近鲜面;保鲜与渠道温度要求高</td></tr>
+</tbody></table>
+<p>谁能在下一代工艺上先做到「成本可控、口感过关」,谁就拿到下一轮的基本盘。你的研发能力在这里是最直接的资本——但这一课要你学会的是:<b>把研发能力翻译成市场语言</b>,而不是停在参数上。</p>`},
+  {t: '12–16 分', ti: 'AI 带来的变量:不是快一点,是重新划线', html: `
+<p>关于 AI,最常见的误解是「它能帮我把活干快一点」。真正的变化是:<b>能做和不能做的事,重新划了线。</b></p>
+<div class="two-col">
+<div class="col"><h4>以前:抽样推断</h4><ul><li>抽 50 个用户,推断 5000 万</li><li>从少量评论里扒痛点</li><li>结论强弱靠人的经验</li></ul></div>
+<div class="col"><h4>现在:全量对照</h4><ul><li>所有能拿到的商品、原话、工艺条件放在一起逐格对照</li><li>每条结论都能回到原文、来源、编号</li><li>先画供给树、需求树,再在交叉处找机会</li></ul></div>
+</div>
+<p>但有一个必须放在设计前提里的局限:<b>AI 会编。</b>它会给你一个漂亮的共识、一段顺滑的分析,却可能没有证据,或者证据对不上。所以这次真正的功夫是三句话:让 AI <b>说得出证据</b>、<b>说得出反例</b>、<b>说得出它不知道什么</b>。</p>
+<p>附录 A 放了六个数据反常识:每一个都是 AI 初版结论和人工复核结论的对比。比如「辣」在六组痛点里都排第一,AI 会得出「用户嫌辣,建议全线降辣」——逐条读原文后,39 条里只有 1 条真在嫌辣,29 条是把「辣得过瘾」当卖点夸。课上演示其中两三个,其余请课后自己翻。</p>`},
+  {t: '16–20 分', ti: '落到方便面行业:三个结构性事实', html: `
+<p>抬头看行业,长期有效的变化有三条,课堂上直接能看见数据的是后两条:</p>
+<ol>
+<li><b>价格带分层。</b>≤4 元仍是最大的一层(53/125),但 4 元以上合计 72/125,超过一半。尤其是 &gt;9 元的 16 个里,日清 5 个、康师傅 3 个、白象 3 个——高端不是没人做。</li>
+<li><b>形态分化。</b>400 个商品里,标题标「拌面」的 255 个(63.7%);同时非油炸 105 个(26.3%)、地域风味 86 个(21.5%)。拌面和汤面、油炸和非油炸,是不同产线、不同成本结构的生意。</li>
+<li><b>地域风味崛起。</b>地域风味标签逐条数 109 个(不含日式 59、韩式 55),其中陕西 31、武汉热干面 25、北京 15。但注意:在电商搜索样本里,陕西风味的有效价中位只有 3.38 元/100g(11 个),武汉热干面 3.16 元(3 个)——<b>地域风味在当下的样本里是扎堆的平价带,不是天然的高溢价</b>。</li>
+</ol>
+<h4>练习一:画出你脑子里的「4 × 4」(3 分钟)</h4>
+<p>发给每组一张 4 × 4 格子:横轴是价格带(每 100g ≤4 / 4–6 / 6–9 / &gt;9 元),纵轴是工艺(油炸 / 非油炸 / 半干鲜熟 / 冻干或其他)。<b>把你能想到的、市场上已经有的新品,写进对应的格子。</b></p>
+<p>课堂数据打出来的 18 个格子里,最扎眼的是这一格:</p>
+<table class="tbl compact"><thead><tr><th>格子</th><th>有有效价的 SKU</th><th>其中康师傅</th></tr></thead><tbody>
+<tr><td>≤4 元 × 非油炸</td><td>14 个</td><td class="zero">0 个</td></tr>
+</tbody></table>
+<p class="muted">口径:125 条有效价中「工艺 = 非油炸」的 29 条里,≤4 元带 14 条。康师傅 35 个有效价里「工艺 = 非油炸」的 0 个。合计恒为 18 格(4 × 4 加「其他工艺」列)。</p>
+<p>这一格是空着的,但空白不等于机会——同格已经有 14 个别人家的 SKU,其中大部分是低价散牌。它到底是「没人做得到」还是「做了不划算」,要交给 D1-01 之后的环节去验。这一格本章会反复出现。</p>`}
+ ],
+ takeaway: `<p><b>第一段的落点:</b>增量时代结束了,创新的性质从营销驱动变成工艺驱动,AI 重新划了能做与不能做的线;落到方便面,价格带在分层、形态在分化、地域风味在崛起,而我们脑中最熟悉的格子,往往不是最空的那一格。</p>
+<p>现场接一句:【练习四结束时我会问你们:你组的课题,落在哪一格?】</p>`},
+{
+ id: 'big1-p2', no: '第二段', title: '战略层 → 组织层 → 个人层', time: '30 分钟', goal: '把「谁负责创新」讲到底',
+ pts: [
+  {t: '0–3 分', ti: '为什么不能只看「产品创新」', html: `
+<p>单看产品创新,会走进三个僵局:</p>
+<table class="tbl"><thead><tr><th>僵局</th><th>表现</th><th>根因</th></tr></thead><tbody>
+<tr><td><b>部门割裂</b></td><td>做出来的卖不动;卖点要的,工艺做不了</td><td>没有人对整个品类的生意负责</td></tr>
+<tr><td><b>标准错位</b></td><td>用同一套 KPI 考核性质完全不同的创新</td><td>防御型微创新和代际迭代用了同一把尺</td></tr>
+<tr><td><b>短长失衡</b></td><td>全是改口味换包装,没人做底层代际突破</td><td>考核周期只奖励短期</td></tr>
+</tbody></table>
+<p>三个僵局的共同解药是同一件事:<b>有人站在品类的全局,对这个生意负责。</b>这就是为什么下面要分三层讲。</p>`},
+  {t: '3–13 分', ti: '【战略层】品类经营:创新长在这张网里', html: `
+<p><b>产品创新不是孤立动作,它长在「品类经营」这张网里。</b>品类经营的结构可以拆成一句话:</p>
+<div class="case"><h4>品类经营 = 一根主干 + 两个抓手 + 一双眼睛</h4>
+<table class="tbl"><thead><tr><th>部件</th><th>是什么</th><th>对创新的意义</th></tr></thead><tbody>
+<tr><td><b>主干</b></td><td>品类全生命周期:导入 → 成长 → 成熟 → 衰退 → 焕新</td><td>决定现在该做防御、该迭代,还是该拓新</td></tr>
+<tr><td><b>抓手一</b></td><td>品牌资产:一个品类的品牌记忆与信任</td><td>决定新产品能不能挂主品牌,还是必须另起</td></tr>
+<tr><td><b>抓手二</b></td><td>营销预算:一年投入的分项盘子</td><td>决定创新能拿到多少资源</td></tr>
+<tr><td><b>眼睛</b></td><td>市场研判:人群、渠道、价格、趋势的变化</td><td>决定创新方向看不看得准</td></tr>
+</tbody></table>
+<p class="case-foot">主干回答「现在该做什么」,两个抓手回答「做出来挂谁、花多少钱」,眼睛回答「对不对」。</p></div>
+<h4>创新分三类,不能用同一把尺</h4>
+<div class="kind3">
+<div class="kind"><h4>防御型微创新</h4><dl><dt>周期</dt><dd>3–6 个月</dd><dt>看什么</dt><dd>存量守住率</dd><dt>例子</dt><dd>改口味、换包装、出限定、经典款联动</dd><dt>记号</dt><dd>「别让老客跑」</dd></dl></div>
+<div class="kind"><h4>代际底层迭代</h4><dl><dt>周期</dt><dd>5–8 年</dd><dt>看什么</dt><dd>专利和产线能力</dd><dt>例子</dt><dd>非油炸热风三段控温、半干鲜熟、锁鲜工艺</dd><dt>记号</dt><dd>「别被下一代替代」</dd></dl></div>
+<div class="kind"><h4>长尾溢价拓利</h4><dl><dt>周期</dt><dd>1–2 年</dd><dt>看什么</dt><dd>毛利率</dd><dt>例子</dt><dd>地域风味单品、高端线、细分人群专款</dd><dt>记号</dt><dd>「多赚一点、多占一格」</dd></dl></div>
+</div>
+<p>这三类产品在报表上长得不一样:防御型看销量和复购,代际迭代三五年里几乎不给利润,长尾拓利单价高、毛利高但量小。用销量 KPI 考核代际迭代,它永远过不了会;用毛利率考核防御型,它会不敢做。</p>
+<h4>顺手要认清品类边界</h4>
+<p>方便面的原生心智是<b>便捷、应急、饱腹</b>。创新可以做「<b>相对健康</b>」——少盐少油、非油炸、加蛋白、真材实料;不硬冲「<b>专业健康</b>」——减肥代餐、术后营养、慢病管理,那是和辅食品牌、药企膳食正面相撞的赛道。</p>
+<p>用户说「想要一款健康方便面」时,要追问一层:他要的是「少油少盐」,还是「养生代餐」?前者品类能承载,后者要换一种生意。</p>
+<h4>练习二(3 分钟):给你的课题定位</h4>
+<p>每组把课题写在一张便签上,用三行字回答:<b>① 它属于三类创新里的哪一类?② 它主要动的是哪根主干/哪个抓手?③ 它可能撞在哪根品类边界上?</b>贴到白板上的三个区域。贴完看:三块是否均衡——如果所有课题都挤在「防御型」,说明大家熟悉的分工,本身就偏向守成。</p>
+<div class="block note"><h3>这一层的落点</h3><p>产品创新是点,品类经营是面。先想清楚这个点是哪类创新、长在哪根主干上。</p></div>`},
+  {t: '13–24 分', ti: '【组织层】品牌经理责任制:有人对全局负责', html: `
+<p>战略层说「要对品类生意负责」,组织层回答的是:<b>谁来负责,怎么负责。</b>这里的参照是品牌经理(品类经理)责任制。</p>
+<h4>五层结构</h4>
+<div class="tbl-scroll"><table class="tbl"><thead><tr><th>层</th><th>是什么</th><th>对应到产品创新</th><th>落到你身上</th></tr></thead><tbody>
+<tr><td><b>① 组织载体</b></td><td>品牌经理放在品类组里,按利润中心的方式运行</td><td>每个品类有一个人对生意负责</td><td>你所在的品类组,就是你负责的「经营单元」</td></tr>
+<tr><td><b>② 角色定位</b></td><td>品类经营第一责任人(三重角色)</td><td>创新由谁统筹、谁拍板</td><td>你是本品类创新的第一责任人</td></tr>
+<tr><td><b>③ 职责贯穿</b></td><td>四项职责:全生命周期 / 品牌资产 / 营销预算 / 市场研判</td><td>创新在生命周期哪个位置、挂谁、花多少、对不对</td><td>贯穿整个流程,不只是在研发段</td></tr>
+<tr><td><b>④ 机制层</b></td><td>流程链条 / 分级决策 / 部门协同(穿透圈层)/ 激励 / 人才</td><td>创新怎么被推动、怎么被评价</td><td>你的提报会在哪个圈层被卡</td></tr>
+<tr><td><b>⑤ 组织成效</b></td><td>市场部重塑、品牌驱动增长</td><td>创新最终变成什么</td><td>不只是出产品,是让品类持续增长</td></tr>
+</tbody></table></div>
+<h4>三重角色</h4>
+<div class="kind3">
+<div class="kind"><h4>经营责任人</h4><p style="font-size:13px;margin:0">对这个品类的增长、利润、心智负责。创新不是交差,是经营动作。</p></div>
+<div class="kind"><h4>协同枢纽</h4><p style="font-size:13px;margin:0">把研发、工艺、供应链、渠道拉到一张桌上,用同一套事实说话。</p></div>
+<div class="kind"><h4>标准唯一出口</h4><p style="font-size:13px;margin:0">对外只说一个口径:卖点怎么说、边界在哪、证据到哪为止,由你统一。</p></div>
+</div>
+<h4>四项职责,对应四项权限</h4>
+<div class="resp">
+<div class="resp-row"><span class="rh">职责</span><b>品类全生命周期</b><span class="rk">对应权限</span><b>产品分级决策权</b></div>
+<div class="resp-row"><span class="rh">职责</span><b>品牌资产</b><span class="rk">对应权限</span><b>品牌内容终审权</b></div>
+<div class="resp-row"><span class="rh">职责</span><b>营销预算</b><span class="rk">对应权限</span><b>分项预算支配权</b></div>
+<div class="resp-row"><span class="rh">职责</span><b>市场研判</b><span class="rk">对应权限</span><b>品类战略表决权</b></div>
+</div>
+<p>责任有多大,权限就要有多大。只有责任没有权限,创新会停在提案上;只有权限没有责任,创新会变成随意的动作。</p>
+<h4>穿透圈层:你的方案会在哪一圈被卡</h4>
+<div class="rings">
+<div class="ring c1"><b>核心圈</b><span>本人 + 品类组<br>你自己拍板</span></div>
+<div class="ring c2"><b>协同圈</b><span>研发 · 工艺 · 供应链<br>能力提供方:做不做得出来</span></div>
+<div class="ring c3"><b>决策圈</b><span>分管领导 · 委员会<br>拍板方:值不值得投</span></div>
+<div class="ring c4"><b>生态圈</b><span>供应商 · 渠道 · 消费者<br>接受度:卖不卖得动</span></div>
+</div>
+<p>这个模型给你一个非常实际的用法:<b>每一份产出物写的时候,就问自己一句「它会卡在哪一圈」</b>——卡在协同圈,是工艺和成本没讲清;卡在决策圈,是三类创新的标准用错了;卡在生态圈,是渠道和消费者不接受。</p>
+<h4>四阶成长:你在这条路上的第几阶</h4>
+<div class="ladder">
+<div><b>新品孵化官</b><span>把一个新品从 0 推到 1</span></div>
+<div class="lv2"><b>整合营销大师</b><span>新品 × 品牌 × 渠道,会讲故事</span></div>
+<div class="lv3"><b>增长操盘手</b><span>对品类的增长曲线负责</span></div>
+<div class="lv4"><b>生意领导者</b><span>对整个品类的生意负责</span></div>
+</div>
+<div class="block note"><h3>这一层的落点</h3><p>创新的瓶颈,往往不在点子,而在「谁负责、谁拍板、谁为结果买单」。品牌经理责任制解决的正是这个问题。</p></div>`},
+  {t: '24–30 分', ti: '【个人层】你们不是「研发人员」,是「未来的品类负责人」', html: `
+<p>把前两层压到一个人身上,就是这一层要说的话:<b>你就是未来要对这个品类负责的人。</b>这次坐在教室里的都是研发中心的人——这不是局限,是起点。研发侧是你的本行,别人很难替代。</p>
+<p>但一个品类负责人不能只会研发。要补两块:</p>
+<div class="caps">
+<div class="cap" style="--acc:var(--red)"><h4>研发侧</h4><span class="cap-lv">本行</span><ul><li>配方、工艺、形态、成本</li></ul><p class="cap-q">这次工作坊里,你是全组最懂这一块的人。</p></div>
+<div class="cap" style="--acc:var(--amber)"><h4>市场侧</h4><span class="cap-lv">要补</span><ul><li>人群、场景、卖点、传播</li></ul><p class="cap-q">从 D1-03 起,每天都要用市场侧的眼睛看一遍。</p></div>
+<div class="cap" style="--acc:var(--teal)"><h4>经营侧</h4><span class="cap-lv">要建立</span><ul><li>毛利、价格带、渠道、生命周期</li></ul><p class="cap-q">D2 下午的回推和排序,就是练这一块。</p></div>
+</div>
+<p>三个半天,练的就是这三块的整合:D1 用研发侧的眼睛看供给、市场侧的眼睛看竞品;D2 上午把两块拼成机会;D2 下午把经营侧加进来,变成算得过账的提案。</p>
+<div class="case"><h4>一个提醒:别只做「研发侧的好答案」</h4><p>研发侧最容易做出的,是技术上漂亮、参数漂亮、实验室里做得很好的产品。但品类负责人要回答的是另一个问题:<b>这个漂亮,用户看不看得见、愿不愿意为它多付钱。</b>D2-07 会反复练这个翻译——把「热风三段控温」翻译成用户听得懂的一句话。</p></div>
+<div class="block note"><h3>这一层的落点</h3><p>你的岗位是研发,你的未来是品类负责人。这次工作坊,就是从「研发人员」往「品类负责人」走的第一步。</p></div>`}
+ ],
+ takeaway: `<p><b>第二段的落点:</b>产品创新长在品类经营这张网里(战略层);对品类生意负责的人是品牌经理(组织层);而坐在教室里的你,就是未来那个对品类生意负责的人(个人层)。</p><p>现场可以问一句:【刚才练习二的便签里,有几组选的是代际迭代?如果一组都没有——这就是组织层说的「标准错位」。】</p>`},
+{
+ id: 'big1-p3', no: '第三段', title: '新秀 vs 老品牌 · 市场侧 vs 研发侧', time: '25 分钟', goal: '认清康师傅的位置,和你要切换的两侧视角',
+ pts: [
+  {t: '0–9 分', ti: '新秀和老品牌:创新逻辑完全不同', html: `
+<p>同一个「产品创新」,新品牌和成熟企业走的不是同一条路。把两边放在一张表里比:</p>
+<div class="tbl-scroll"><table class="tbl wide compare"><thead><tr><th>维度</th><th>新秀 / 新品牌</th><th>成熟企业(如康师傅)</th></tr></thead><tbody>
+<tr><td>起点</td><td>找没被满足的缝隙</td><td>在巨大的存量上做结构</td></tr>
+<tr><td>优势</td><td>快、敢、没有包袱</td><td>产线、渠道、供应链、品牌资产</td></tr>
+<tr><td>劣势</td><td>没产能、没渠道</td><td>组织惯性、不敢担责、考核周期错配</td></tr>
+<tr><td>创新类型</td><td>多为长尾溢价拓利</td><td>必须做防御 + 代际迭代</td></tr>
+<tr><td>典型失败</td><td>做出来了铺不出去</td><td>谁都不敢拍板,错过窗口</td></tr>
+</tbody></table></div>
+<p>这两条路线最值得对照的是:<b>失败的不是「想错了」,而是「最该发力的一步没发力」。</b>新秀的失败发生在最后一公里——产能和渠道;老品牌的失败发生在最前一公里——没人敢拍板。</p>
+<p>数据里有一个很能说明问题的切面:康师傅 35 个有有效价的商品,四分位价格是 P25 2.98 / 中位 3.93 / P75 4.24 元每 100g。康师傅的位置非常清楚:<b>主力牢牢站在 4 元以下,大企业,基本盘巨大。</b></p>
+<div class="case"><h4>康师傅的位置:挑战不是「找不到点子」,是「在巨大存量上做结构性创新」</h4>
+<p>大企业的优势,恰恰也是它创新的难点:已经做好的基本盘越大,做任何结构性变化要守住的就越多。于是创新容易被压缩成两种:一种是安全的小改动(防御型),一种是等别人先做、再跟进(跟跑)。代际迭代和长尾拓利,反而最容易被推迟。</p>
+<p>所以对康师傅来说,最稀缺的不是点子——点子在教室里一个下午就能出十个——而是<b>把点子放到三类创新的标准下、拿到协同圈和决策圈去推进的能力</b>。这次工作坊练的就是这个。</p></div>`},
+  {t: '9–15 分', ti: '市场侧 vs 研发侧:同一个人要切换两侧', html: `
+<p>不是「市场部门 vs 研发部门」,而是<b>同一个产品经理,在两个视角来回切换</b>。两侧的起点、风险、验证方式都不同:</p>
+<div class="tbl-scroll"><table class="tbl wide compare"><thead><tr><th></th><th>研发侧创新</th><th>市场侧创新</th></tr></thead><tbody>
+<tr><td>起点</td><td>工艺 / 原料 / 配方的突破</td><td>人群 / 场景 / 卖点的重构</td></tr>
+<tr><td>例子</td><td>非油炸热风三段控温</td><td>把挂面截成三段卖小孩</td></tr>
+<tr><td>风险</td><td>做出来没人买</td><td>说得好听但做不出来</td></tr>
+<tr><td>验证方式</td><td>感官测试、稳定性</td><td>概念测试、卖点测试</td></tr>
+<tr><td>谁受益</td><td>长期竞争壁垒</td><td>短期销量</td></tr>
+</tbody></table></div>
+<p><b>最好的创新是两侧交汇:工艺上做得出来,市场上说得通。</b>只会在研发侧发力,容易做出漂亮却卖不动的产品;只会在市场侧发力,容易做出好听却落不了地的概念。这次流程的设计,就是让这两侧在每一步都被对方检验一遍:D1 用市场侧看竞品,D2-06 用研发侧回推能不能做,D2-07 再把研发语言翻译成市场语言。</p>`},
+  {t: '15–22 分', ti: '案例:挂面截三段——一次典型的市场侧创新', html: `
+<div class="case"><h4>一把挂面 2 块钱。截成三分之一,装小包,卖给小孩,卖 60 元。</h4>
+<ul>
+<li><b>成本没变</b>——还是那些面。</li>
+<li><b>变的是三件事</b>:规格(长段 → 小段小包)+ 人群(家庭主妇 → 孩子)+ 场景(主食原料 → 儿童零食)。</li>
+<li><b>从「主食原料」变成「儿童零食」</b>,价格翻 30 倍。</li>
+<li><b>本质不是产品创新,是品类定义创新。</b></li>
+<li>这是典型的<b>市场侧创新</b>:工艺没变、原料没变,变的是卖给谁、在什么场景卖、怎么说。</li>
+</ul>
+<p class="case-foot">数据参考:任务资料里对高端手工面的观察是「15–20 元/斤普通高端手工面、60 元+/斤婴童面」——「60 元/斤」是行业观察值,课堂数据包不含这条价格,引用时按观察数据对待。</p></div>
+<p>但故事没完。它会反过来倒逼研发:</p>
+<ol>
+<li><b>小包装的防腐与保质。</b>面截短、装小包后,表活比变大,水分活度控制要重新做。</li>
+<li><b>断条率。</b>挂面截成三段,切口处容易断;要解决断条,就要改配方或改工艺。</li>
+<li><b>煮制时间。</b>给孩子吃,要更短的煮制时间、更软的口感;这要求调整面筋网络或干燥曲线。</li>
+</ol>
+<h4>练习三:倒逼研发的三个问题(5 分钟)</h4>
+<p>每组结合自己课题的工艺经验,回答:<b>如果你组的课题里也有一个「市场侧创新」,它会倒逼研发解决什么问题?把它写成三个具体的工艺/参数问题。</b>比如:不是「变得更非油炸」,而是「在 X 元成本带内,把非油炸面饼的含水率做到 Y%,同时复水时间 ≤ Z 分钟」。</p>
+<p>写完交换看一眼:一个听起来很简单的市场侧创意,拆到研发这边,往往需要一串参数。</p>`},
+  {t: '22–25 分', ti: '本段的三个判断', html: `
+<ol>
+<li><b>新秀和老品牌不是比谁更聪明</b>,是比谁把「最该发力的那一步」做到了。</li>
+<li><b>市场侧和研发侧不是两个部门</b>,是你要来回切换的两个视角;最好的创新在两侧交汇处。</li>
+<li><b>康师傅真正的挑战,是在巨大存量上做结构性创新。</b>这也是这次 SOP 要从供给、需求和工艺三边同时下手的理由。</li>
+</ol>`}
+ ],
+ takeaway: `<p><b>第三段的落点:</b>新秀输在最后一公里,老品牌输在最前一公里;市场侧和研发侧要在同一个人身上相遇;挂面截三段说明<em>品类定义</em>有时比<em>产品本身</em>更值钱,而它会倒逼研发给出具体参数。</p>`
+},
+{
+ id: 'big1-p4', no: '第四段', title: '产品创新 SOP + 三个半天的链路', time: '15 分钟', goal: '下午就从「定课题」出发',
+ pts: [
+  {t: '0–7 分', ti: '完整 SOP:八步', html: `
+<p>前面三段讲的是「为什么」和「谁负责」,这一段讲「怎么做」。从定课题到出方案,一共八步:</p>
+<div class="sop">
+<div class="sop-step"><span class="sop-no">①</span><b>定课题</b><p class="sop-q">要做什么决定</p></div>
+<div class="sop-step"><span class="sop-no">②</span><b>看供给</b><p class="sop-q">市场上有什么</p></div>
+<div class="sop-step"><span class="sop-no">③</span><b>看需求</b><p class="sop-q">用户要什么</p></div>
+<div class="sop-step"><span class="sop-no">④</span><b>找交叉</b><p class="sop-q">哪里有空白</p></div>
+<div class="sop-step"><span class="sop-no">⑤</span><b>验机会</b><p class="sop-q">这个空白值不值得做</p></div>
+<div class="sop-step"><span class="sop-no">⑥</span><b>算可行</b><p class="sop-q">做不做得出来、划不划算</p></div>
+<div class="sop-step"><span class="sop-no">⑦</span><b>定卖点</b><p class="sop-q">怎么说用户听得懂</p></div>
+<div class="sop-step"><span class="sop-no">⑧</span><b>出方案</b><p class="sop-q">一份能过会的提案</p></div>
+</div>
+<p>这八步和第一段、第二段讲的东西一一对应:②③ 需要研发侧和市场侧同时看;④⑤ 要在品类经营的框架里判断「哪一类创新」;⑥ 是经营侧;⑦⑧ 是把整个方案送到穿透圈层里去接受检验。</p>`},
+  {t: '7–12 分', ti: '三个半天怎么切这八步', html: `
+<table class="tbl"><thead><tr><th>半天</th><th>负责哪几步</th><th>对应环节</th><th>离场时</th></tr></thead><tbody>
+<tr><td><b>D1 下午</b></td><td>① 定课题 · ② 看供给 · ③ 看需求(开个头)</td><td>D1-01 → D1-02 → D1-03 → D1-04 → 夜间 D1-N</td><td>一个决定、三个待答问题、一份研究任务</td></tr>
+<tr><td><b>D2 上午</b></td><td>④ 找交叉 · ⑤ 验机会</td><td>D2-01 → 大课二 → D2-02 → D2-03 → D2-04</td><td>候选机会清单 V1.0</td></tr>
+<tr><td><b>D2 下午</b></td><td>⑥ 算可行 · ⑦ 定卖点 · ⑧ 出方案</td><td>大课三 → D2-05 → D2-06 → D2-07 → D2-08</td><td>概念提案 + 候选清单 V3.0</td></tr>
+</tbody></table>
+<p>三条规矩贯穿始终:<b>没验证过的机会不能进卖点;没算过商业条件的卖点不能进提案;没对照验证配置卡的结论,一律标「待确认」。</b></p>`},
+  {t: '12–15 分', ti: '练习四 + 收尾:今天下午离场时,你手上会有什么', html: `
+<h4>练习四:三步走 + 三个待答问题(5 分钟)</h4>
+<p>每组在纸上写两样:</p>
+<ol><li><b>三步走</b>:你们的课题今天下午先做哪一步、明确要支持的<em>决定</em>是什么、这件事大概属于三类创新中的哪一类。</li><li><b>三个待答问题</b>:会改变结论、而你目前回答不了的那三个问题。</li></ol>
+<p>这两样直接写进 D1-01 的认知盘点——「我希望搞清楚的」和「我已经知道的」两栏。</p>
+<div class="block note"><h3>收尾:今天下午离场时,你手上会有一个明确要做的决定、三个待答问题、和一份能跑的研究任务。</h3><p>然后就交给 AI 跑一整晚。</p></div>
+<p>AI 推送(大课结束时,数字分身会把下面这三行递到每组):</p>
+<div class="push"><div class="push-bar"><b>AI 推送</b><span>大课一结束</span></div><div class="push-rows">
+<div class="push-row"><b>【本轮产出】</b><p>你手上有:练习四纸上写下的「三步走」和「三个待答问题」——它们还不是产出物,是 D1-01 认知盘点的草稿。</p></div>
+<div class="push-row"><b>【还缺什么】</b><p>缺一个能贴到品类图上的<b>具体格子</b>。只说「我们要做一款更好吃的面」还不够——要落到「哪个人群 × 哪个场景 × 哪个价格带 × 哪种工艺」。</p></div>
+<div class="push-row"><b>【下一步】</b><p class="ask">接下来要做 D1-01 品类全景扫描。请先回答:你组的课题,想解决的是哪个具体格子的问题?(D1-01 提示词第一行就要填这个)</p></div>
+</div></div>`}
+ ],
+ takeaway: `<p><b>第四段的落点:</b>八步 SOP 是骨架,三个半天是切分,13 份产出物是每步留下的东西。现在就把课题收敛到「一个格子 + 一个决定」。</p>`
+}
+],
+after: [
+{t: '讲授稿(大课一全文,可直接照着讲)', cls: 'accent', html: `
+<details class="q"><summary>第一段 宏观趋势与行业变局(约 20 分钟)</summary><div class="script" style="padding:8px 14px 14px">
+<p>各位,先把手机放一放,回答我一个问题:<b>我们自己的新品,最近一款是在哪个格子里做出来的?</b>(收 5 个答案,写上黑板)</p>
+<p>再看看这些答案——它们大多落在我们最熟悉的格子里。这是个自然的结果,因为过去三十年,方便面的创新公式就是这样:出一个大单品,靠铺货规模把它推成增量。<b>但大单品增量时代已经结束了。</b></p>
+<p>结束了意味着什么?意味着创新不再是在增量里抢新客,而是在巨大的存量里把结构做开。谁、在什么场景、愿意花多少钱、要什么——这四个要素重新组合,就是新的增长空间。</p>
+<p>课堂数据里,人群、场景、价格三个切面都在变。六组笔记里「口味新鲜」命中最多,但「方便/快手」六组全部前三——那是品类前提,不是差异。价格上,四分之一以上的电商商品已经站在 6 元/100g 以上,价格带分层已经发生。</p>
+<p>第二个变化更深:<b>创新的性质变了。</b>以前是营销驱动的口味微调,现在是工艺驱动的代际突破。方便面行业走过油炸、非油炸、半干鲜熟三代,每一代的胜负手都在工厂端,不在营销端。</p>
+<p>第三个变量是 AI。大家听到 AI 都会说「快一点」。我想说的不一样:<b>AI 改变的不是速度,是能做和不能做的事。</b>以前是抽样推断,现在是全量对照。但 AI 会编——所以今天真正的功夫,是让它说得出证据、说得出反例、说得出它不知道什么。后面附录里有六个反常识的案例,大家一定会感兴趣。</p>
+<p>最后落到我们自己的行业:价格带在分层、形态在分化、地域风味在崛起。大家看一眼这 4 × 4 的格子——最有意思的一格是「≤4 元 × 非油炸」:别人有 14 个 SKU,我们康师傅 0 个。这一格是空的,但空不等于机会。记住这一格,后面我们要用一整天来回答它。</p>
+</p></div></details>
+<details class="q"><summary>第二段 战略层 → 组织层 → 个人层(约 30 分钟)</summary><div class="script" style="padding:8px 14px 14px">
+<p>(承接练习二便签)看白板上的便签:大部分课题,都贴在「防御型」这一块。这不是大家的问题,这是分工带来的结果——我们最熟悉的工作,本来就是防御型的。</p>
+<p><b>为什么产品创新不能单独看?</b>因为它会掉进三个僵局:部门割裂、标准错位、短长失衡。三个僵局的解药是同一个:<b>有人站在品类的全局,对这个生意负责。</b></p>
+<p><b>战略层:</b>产品创新长在品类经营这张网里。品类经营是一根主干——全生命周期——加两个抓手——品牌资产和营销预算——再加一双眼睛——市场研判。在主干上,创新分三类:防御型微创新看存量守住率,代际底层迭代看专利和产线能力,长尾溢价拓利看毛利率。三类用同一把尺去量,就永远得不出结论。</p>
+<p><b>组织层:</b>谁来负责?品牌经理。它不是一个头衔,是一套制度:五层结构——组织载体、角色定位、职责贯穿、机制层、组织成效;三重角色——经营责任人、协同枢纽、标准唯一出口;四项职责对四项权限——全生命周期对产品分级决策,品牌资产对品牌内容终审,营销预算对分项预算支配,市场研判对品类战略表决。还要穿过四个圈层:核心圈你自己拍板,协同圈看研发工艺供应链做不做得出来,决策圈看值不值得投,生态圈看卖不卖得动。这条路有四阶:新品孵化官、整合营销大师、增长操盘手、生意领导者。</p>
+<p><b>个人层:</b>讲到这里,我想对在座的每一位说:<b>你们不是只做研发的,你们是未来的品类负责人。</b>研发侧是你们的本行,市场侧是这次要补的,经营侧是这次要建立的。三个半天练的就是这三个视角的整合。</p>
+</p></div></details>
+<details class="q"><summary>第三段 新秀 vs 老品牌 · 市场侧 vs 研发侧(约 25 分钟)</summary><div class="script" style="padding:8px 14px 14px">
+<p>先说新秀。新秀的优势是快、敢、没包袱;劣势是没产能没渠道。他们最常见的失败,是做出来了铺不出去——输在最后一公里。</p>
+<p>再说我们。康师傅是大企业,基本盘巨大。我们的优势是产线、渠道、供应链、品牌资产;劣势是组织惯性、不敢担责、考核周期错配。最常见的失败,是谁都不敢拍板,错过窗口——输在最前一公里。</p>
+<p>所以康师傅的挑战不是「找不到点子」。点子一个下午能出十个。真正的挑战是:<b>在巨大存量上,做结构性创新。</b></p>
+<p>接下来是同一件事的两张脸。市场侧怎么创新?人群、场景、卖点的重构。研发侧怎么创新?工艺、原料、配方的突破。举个例子——<b>一把挂面两块钱,截成三分之一,装小包,卖给小孩,卖六十块。</b>成本没变,变的是规格、人群、场景;它从主食原料变成了儿童零食;本质不是产品创新,是品类定义创新。</p>
+<p>但这故事的另一半是研发。截短了会不会断条?装小包了怎么放得住?小孩要煮多软?——一个市场侧的创意,最后逼着研发回答一串参数。这就是我说的:<b>最好的创新是两侧交汇。</b></p>
+<p>(练习三:5 分钟)</p>
+</p></div></details>
+<details class="q"><summary>第四段 SOP 与三个半天链路(约 15 分钟)</summary><div class="script" style="padding:8px 14px 14px">
+<p>最后,八步:定课题、看供给、看需求、找交叉、验机会、算可行、定卖点、出方案。D1 下午做前三步,D2 上午做中间两步,D2 下午做最后三步。每一步都有一份产出物,每一步结束 AI 都会推你一把:告诉你手上有什么、还缺什么、下一步先回答哪个问题。</p>
+<p>今天下午离场时,你手上会有一个明确要做的决定、三个待答问题、一份能跑的研究任务。现在花五分钟,把这三样写下来。(练习四)</p>
+<p>写完了吗?好,抬头笑一下——接下来的三个半天,我们不聊点子好不好,我们聊这个点子<b>有没有证据、做不做得出来、划不划算。</b></p>
+</div></details>`},
+{t: '数据速查与板书(备课用)', html: `
+<p class="muted">讲台上可以照着这张表念数字,口径都在括号里;板书只写括号外的粗体。</p>
+<div class="tbl-scroll"><table class="tbl compact"><thead><tr><th>段</th><th>板书</th><th>可引用的数字(口径)</th></tr></thead><tbody>
+<tr><td>一</td><td><b>增量 → 存量结构</b></td><td>口味新鲜 106/260;方便/快手 97/260(词典命中篇次);价格带 ≤4 / 4–6 / 6–9 / &gt;9 = 53 / 43 / 13 / 16(125 个有效价)</td></tr>
+<tr><td>一</td><td><b>营销 → 工艺</b></td><td>油炸 140–160℃、含油 18–22%;热风三段控温、含水 8–12%;半干 pH 4.2–4.6、含水 20–26%(知识库行业通行值)</td></tr>
+<tr><td>一</td><td><b>18 格 · 空格</b></td><td>≤4 元 × 非油炸:14 个 SKU(其中非康师傅);康师傅 35 个有效价里非油炸 0 个</td></tr>
+<tr><td>二</td><td><b>主干 + 2 抓手 + 眼</b></td><td>三类创新:3–6 个月看存量守住率 / 5–8 年看专利产线 / 1–2 年看毛利率</td></tr>
+<tr><td>二</td><td><b>5 层 · 3 角色 · 4 职责 4 权限 · 4 圈 · 4 阶</b></td><td>—</td></tr>
+<tr><td>三</td><td><b>最后一公里 vs 最前一公里</b></td><td>康师傅 P25 2.98 / 中位 3.93 / P75 4.24(35 个有效价);挂面 2 元 → 60 元(任务资料示例,按教案案例讲)</td></tr>
+<tr><td>四</td><td><b>8 步 · 3 半天 · 13 产出</b></td><td>D1:① ② ③;D2 上午:④ ⑤;D2 下午:⑥ ⑦ ⑧</td></tr>
+</tbody></table></div>`},
+{t: '讲师备忘', cls: 'note', html: `
+<ul>
+<li><b>时间最紧的是第二段</b>(30 分钟要讲三层)。如果练习二超时,把练习二压成「举着手说一句」,不要压三层结构——三层是第一天的骨架。</li>
+<li><b>品牌经理责任制部分不要照搬客户原文口径</b>:本课引用的是通用的组织参照结构(五层、三重角色、四职责四权限、穿透圈层、四阶成长),用于打开视野,不作康师傅现状描述。若客户追问「我们是不是这样」,答:这是参照坐标,不是诊断。</li>
+<li><b>挂面案例按教案案例讲</b>,其中的价格(2 元 → 60 元)是任务给定的教学案例;如果学员拿真实数据追问,用「60 元/斤婴童面」一句带过,并说明是行业观察值。</li>
+<li><b>不要现场评价学员的点子</b>:这一段的目的不是比谁的点子好,是把大家拉进同一个判断框架。</li>
+<li>课间分发:4 × 4 空格子纸(练习一)、三种颜色便签(练习二)。</li>
+</ul>`}
+]
+},
+
+// ======================================================================
+// 大课二
+// ======================================================================
+{
+kind: 'big', id: 'big2', no: '大课二', title: '机会发现:三条线交叉的地方才是机会', group: '大课详案',
+meta: [['D2 09:25–10:15 · 50 分钟', 'tag'], ['承接:D1 晚间的调研战报', ''], ['讲法:五个反常识案例 + 一条纪律', '']],
+lead: '夜间 AI 跑出来的机会清单,不能直接拿来用。这一课讲清楚:<b>AI 有幻觉,这是设计前提不是缺陷</b>;<b>人做什么、AI 做什么</b>;用六个真实数据讲透<b>反常识的发现</b>;最后给出<b>三源交叉</b>——商品事实、用户原声、工艺条件三条线交叉的地方,才是机会。',
+outline: [
+  ['0–5 分', '昨天的战报', '先看缺口,再看结论'],
+  ['5–15 分', 'AI 有幻觉:人做什么,AI 做什么', 'AI 全量扫描,人判断真假'],
+  ['15–35 分', '六个反常识的数据发现', '同一个数字,换一个读法就反过来'],
+  ['35–45 分', '三源交叉', '三条线都指向同一个方向'],
+  ['45–50 分', '布置练习与推送', 'D2-02 从分层编码开始']
+],
+before: [
+{t: '这一课回答的问题', html: `
+<p>D1 晚间,AI 按任务卡跑了 16 个小时。今天早上,每组面前有一份战报和一张机会清单。大多数人第一反应是「先看清单里有什么」。这一课要你先停下来看两件事:<b>这份清单里哪些是 AI 编的、哪些是数据撑着的</b>;<b>支撑着的那些,是不是三条线都指向同一个方向</b>。</p>
+<p>课后的 D2-01 先验收战报,D2-02 至 D2-04 用这一课给的三件事——<b>分层编码、三类发现、三源交叉</b>——把战报变成候选机会清单 V1.0。</p>`}
+],
+parts: [
+{
+ id: 'big2-p1', no: '一', title: '昨天的战报:先看缺口,再看结论', time: '5 分钟', goal: '把「跑完了」和「跑对了」分开',
+ pts: [{t: '0–5 分', ti: '三句话验收', html: `
+<p>打开战报,回答三个问题(D2-01 会给正式检查表):</p>
+<ol>
+<li><b>三条假设各回应到了什么程度?</b>支持、部分支持、推翻、未回应——四选一,不许写「基本支持」。</li>
+<li><b>每条结论能不能回到原件?</b>商品链接、笔记标题或 ID。回不去的,当场降级为「假设」。</li>
+<li><b>分母写没写?</b>「23 篇提到」——是在 260 篇里 23 篇,还是在 40 篇里 23 篇?</li>
+</ol>
+<p>昨天布置的任务卡里每条假设都带了<b>停止条件</b>。现在检查一下:每个停止条件是不是按任务卡写的标准停下来的,而不是「跑累了就停」。</p>`}]
+},
+{
+ id: 'big2-p2', no: '二', title: 'AI 有幻觉:人做什么,AI 做什么', time: '10 分钟', goal: '把幻觉当成前提,而不是当成缺陷',
+ pts: [{t: '5–15 分', ti: '幻觉是设计前提', html: `
+<p>大模型最擅长的,是「说得像那么回事」。它会给你一个漂亮的共识、一段顺滑的分析,但可能根本没有证据,或者证据对不上。这不是 bug,是这类工具的工作方式——所以<b>既不能不用,也不能直信</b>,要给它设验证纪律。</p>
+<p>昨天 D1-02 定下的验证配置卡,就是这个纪律。今天早上对它做一次验收:</p>
+<div class="two-col">
+<div class="col ok"><h4>AI 做什么</h4><ul><li>全量扫描:400 个商品、260 篇笔记、120 篇竞品社媒逐条过</li><li>初步分类:把原话按人群、场景、痛点先归类</li><li>找模式:统计频次、算中位、拉出价格带分布</li><li>提出待验证假设</li></ul></div>
+<div class="col bad"><h4>人做什么</h4><ul><li>判断真假:抽读原文,看说的是不是这个意思</li><li>剔除误判:把打标错误、兜售帖、重复内容剔出去</li><li>定权重:哪条重要、哪条可以忽略</li><li>拍板:值不值得做</li></ul></div>
+</div>
+<p>有一个细节每次都会碰到:<b>「没查到」「没权限」「数据确实不存在」是三件事。</b>AI 有时会把三种情况都写成「资料库里没有」。验收时逐条核对:是没搜到,是平台不给,还是这个东西确实不存在?</p>
+<p>这个纪律不是今天才立的。D1-02 的配置卡里已经定好:全部比例写分母、词典打标词必须抽读原文、价格双口径。今天这一课的所有例子,都是照着这套纪律复核出来的。</p>`}]
+},
+{
+ id: 'big2-p3', no: '三', title: '六个反常识的数据发现', time: '20 分钟', goal: '同一个数字,换一个读法就反过来',
+ pts: [{t: '15–35 分', ti: 'AI 初判 vs 人工复核', html: `
+<p>下面六个例子,全部来自课堂数据包。每个例子里,AI 看数字给出一个结论,人工读原文后结论反过来了。课上一组一组过,每组约 3 分钟;完整版见 <a href="#appx-a">附录 A</a>。</p>
+<div class="tbl-scroll"><table class="tbl wide"><thead><tr><th>#</th><th>AI 初判</th><th>人工复核</th><th>这一步用在哪</th></tr></thead><tbody>
+<tr><td>1</td><td>「辣」在六组都排痛点第一 → <b>用户嫌辣,建议全线降辣</b></td><td>39 条逐条读:正向(「辣得过瘾」「香辣美味」)29 条、读不出 9 条、真嫌辣 1 条(G1「避免重辣重油」)</td><td>D2-02 分层编码</td></tr>
+<tr><td>2</td><td>「贵」出现 11 次,G6 最多 → <b>地域用户价格敏感</b></td><td>G6 的 9 条里,「贵州」被词典识别成了「贵」(如「为什么在贵州带回来的羊肉粉这么好吃」);另外 2 条一条是高铁外卖配送费、一条无明确价格抱怨</td><td>D2-02 抽读原文</td></tr>
+<tr><td>3</td><td>「量大」是高频痛点 → <b>推大份量</b></td><td>260 篇里只出现 2 次,都是夸:「便宜量大又好吃」「量大一顿能吃很饱」</td><td>D2-02 频次≠问题</td></tr>
+<tr><td>4</td><td>≤4 元占 42.4%,康师傅在该带 22 个 → <b>康师傅主战场在 ≤4 元</b></td><td>54 条含「整箱/组合/混合/批发」,剔除后剩 71 条,≤4 元占 47.9%;康师傅 22 个里 15 个是整箱/混合装,剔除后只剩 7 个</td><td>D2-03 矩阵与价格</td></tr>
+<tr><td>5</td><td>汤达人社媒中位点赞 6,六家最低 → <b>汤达人讨论冷清、品牌老化</b></td><td>20 篇里 10 篇点赞 ≤5,多为海外兜售帖(「洛杉矶汤达人$10/3大包」等);剔除后剩 16 篇,中位从 6 升到 29</td><td>D1-03 / D2-03 竞品比较</td></tr>
+<tr><td>6</td><td>「答应我,一定要试试这个面条!!!」出现多次 → <b>话题热度高</b></td><td>竞品社媒 120 行里同标题出现 4 次,其中两行正文完全相同;G5 的 Top1 也是同一篇。400 个商品里 11 个标题重复、多出 14 行(去重后 386 个)</td><td>D2-02 去重</td></tr>
+</tbody></table></div>
+<p>六个例子里,有四个的结论方向完全反了(1、2、3、5),两个的数字幅度变了(4、6)。但你会发现一条共同的规律:<b>错误的来源不是算错了,而是把「提到」当成了「态度」、把「出现」当成了「存在」、把「样本」当成了「市场」。</b></p>
+<h4>三句话带走</h4>
+<ol><li><b>频次说的是「有人提到」,不是「有人不爽」。</b></li><li><b>打标词会命中别的词</b>——贵州、重庆、贵价;抽 5 条读原文是底线。</li><li><b>先要分母,再要结论。</b>没有分母的比例,不叫发现。</li></ol>
+<p>还有一条写给「空白」的:<b>任何空白,先查同一格的竞品。</b>康师傅在 ≤4 元 × 非油炸是 0,但同一格有 14 个别人家的 SKU——这一格有供给,但用户需求原话是缺的。空白不是机会,是<b>待验证的问题</b>。</p>`}]
+},
+{
+ id: 'big2-p4', no: '四', title: '三源交叉:三条线交叉的地方才是机会', time: '10 分钟', goal: '把「机会」定义成一个可复核的结构',
+ pts: [{t: '35–45 分', ti: '供给、需求、工艺', html: `
+<p>一个机会,至少要在三条线上同时成立:</p>
+<div class="cap" style="--acc:var(--red);margin:6px 0 10px"><h4>一、商品事实</h4><p style="font-size:13.5px;margin:0">市场上有没有人在做?在哪个价格带、形态、工艺上做?做得怎么样?——来自电商商品与竞品社媒。</p></div>
+<div class="cap" style="--acc:var(--amber);margin:0 0 10px"><h4>二、用户原声</h4><p style="font-size:13.5px;margin:0">有没有人真的在说这件事?说的是夸还是嫌?在什么场景下说?——来自六组用户笔记、竞品评论。</p></div>
+<div class="cap" style="--acc:var(--teal);margin:0 0 10px"><h4>三、工艺条件</h4><p style="font-size:13.5px;margin:0">工艺上做不做得出来?成本和稳定性在不在范围里?——来自 49 条工艺知识库和你自己的研发经验。</p></div>
+<p><b>三条线指向同一个方向,才叫机会;两条线指向,叫候选;一条线指向,叫线索;哪条线都没有,是想象。</b></p>
+<p>今天下午要到 V1.0 候选清单,就是三条线都能各写出至少一条证据的机会。每张机会卡都会有一个「工艺注释」栏——那是你自己的经验在写,AI 只能标「待工艺确认」。</p>
+<p>还有一层:产品经理本人也要在这三条线上切换视角。看商品事实时切换到市场侧;写用户原声时切换到使用场景里;写工艺注释时回到研发侧的本行。三条线在同一个人身上对齐,就是这次工作坊练的核心。</p>`}]
+},
+{
+ id: 'big2-p5', no: '五', title: '布置练习与推送', time: '5 分钟',
+ pts: [{t: '45–50 分', ti: '从分层编码开始', html: `
+<p>接下来 D2-01 先验收战报,然后 D2-02 开始分层编码:<b>人群 → 场景 → JTBD(用户要完成的事)→ 痛点,四层不能混。</b>四层混在一起,就会出现「辣」那样的误判。</p>
+<p>AI 推送(大课二结束时):</p>
+<div class="push"><div class="push-bar"><b>AI 推送</b><span>大课二结束</span></div><div class="push-rows">
+<div class="push-row"><b>【本轮产出】</b><p>你手上有:一套人为规定的复核纪律(频次要读原文、空白要先查同格竞品、比例先要分母)和三源交叉的定义。</p></div>
+<div class="push-row"><b>【还缺什么】</b><p>还缺把战报验收掉。不验收的清单里,混着 AI 编的和词典误判的,后面所有排序都会被带偏。</p></div>
+<div class="push-row"><b>【下一步】</b><p class="ask">接下来要做 D2-01 调研验收。请先回答:战报里,哪一条结论你现在最不放心?它是没找到原件,还是原件读出来意思不对?</p></div>
+</div></div>`}]
+}
+],
+after: [
+{t: '讲师备忘', cls: 'note', html: `
+<ul>
+<li><b>六个例子讲 2–3 个就够</b>(建议 1、2、5),其余让学员对照附录 A 自己看。重点是「为什么同一个数字读法不同,结论会反过来」。</li>
+<li><b>汤达人那个例子注意口径</b>:剔除后中位是 <b>29</b>(剩 16 篇)。不同的剔除规则(只剔 2 条洛杉矶帖 → 21;只按标题去重 → 5)结果不同——这正是要点:口径不同,结论不同,所以要把口径写下来。</li>
+<li><b>不要用「总赞」排品牌声量</b>:农心总赞 75,484 里 47,173(62.5%)是一条 aespa 活动帖。</li>
+<li>三源交叉的三个框,建议用三种颜色的便签占位三次:红 = 白板左边「商品事实」,黄 = 右上「用户原声」,绿 = 右下「工艺条件」。后续每个机会都要求三色便签各一张。</li>
+</ul>`}
+]
+},
+
+// ======================================================================
+// 大课三
+// ======================================================================
+{
+kind: 'big', id: 'big3', no: '大课三', title: '从机会到提案:收敛、表达、交付', group: '大课详案',
+meta: [['D2 13:30–14:20 · 50 分钟', 'tag'], ['承接:候选机会清单 V1.0', ''], ['讲法:四段,最后落到市场侧延展', '']],
+lead: '上午结束时,手上是 2–3 个带证据的机会。这一课讲清楚:<b>多个机会怎么排序(收敛的逻辑)</b>;<b>机会怎么变成概念</b>;<b>AI 能帮你做什么</b>——设计示意图、卖点文案、竞品对比、把分析串成提案;<b>提案怎么表达</b>;以及定稿后<b>市场侧还可以延展什么</b>。',
+outline: [
+  ['0–10 分', '收敛的逻辑', '多个机会怎么排序'],
+  ['10–20 分', '从机会到概念', '哪里有空白 → 我要做成什么样'],
+  ['20–32 分', 'AI 能帮什么、不能替什么', '示意、文案、对比、串联'],
+  ['32–42 分', '提案的表达层次', '给谁看、讲什么、先讲结论'],
+  ['42–50 分', '市场侧延展', '定稿之后还能做什么'],
+],
+before: [
+{t: '这一课的位置', html: `
+<p>大课二把「机会怎么被发现」讲完,大课三把「机会怎么被选择、被说清」讲完。这一课讲完,后面四节就是把课上的内容在你们的机会卡上跑一遍:D2-05 排序 → D2-06 回推 → D2-07 卖点 → D2-08 提案。</p>`}
+],
+parts: [
+{
+ id: 'big3-p1', no: '一', title: '收敛的逻辑:多个机会怎么排序', time: '10 分钟', goal: '用三个维度,不用一个感觉',
+ pts: [{t: '0–10 分', ti: '证据强度 × 可做性 × 商业价值', html: `
+<p>上午可能得出 2–3 个候选机会,也可能更多。一个都不能凭「我觉得」排序,用三个维度:</p>
+<table class="tbl"><thead><tr><th>维度</th><th>问什么</th><th>怎么打分(1–3)</th><th>数据来源</th></tr></thead><tbody>
+<tr><td><b>证据强度</b></td><td>三条线(商品事实 / 用户原声 / 工艺条件)各有多少条证据?</td><td>3 = 三线齐全且各有 2 条以上;2 = 三线齐全但薄;1 = 只有一两线</td><td>机会卡 V1.0</td></tr>
+<tr><td><b>可做性</b></td><td>现在的产线、工艺、供应商能不能做?</td><td>3 = 现有产线可做;2 = 要改线或新增原料;1 = 新工艺 / 新产线</td><td>研发侧自己的判断</td></tr>
+<tr><td><b>商业价值</b></td><td>价格带、毛利、量级撑不撑得起?</td><td>3 = 高溢价且量级可期;2 = 一般;1 = 低价薄利或量级不明</td><td>D2-06 回推表</td></tr>
+</tbody></table>
+<p>最终排序看总分,但更重要的一条规则是:<b>三个维度里任何一个得 1 分的机会,不能排进前三。</b>证据薄、做不出、不赚钱——只要有一项卡死,其他两项再高也是虚的。</p>
+<p>还要单独列一类:<b>未知项</b>。有些机会现在没法打分,因为缺一个关键数据——比如「这个价格带的消费者接受度没测过」。未知项不是低分项,是今天必须写进 V1.0、但要在后续补证里回答的问题。</p>`}]
+},
+{
+ id: 'big3-p2', no: '二', title: '从机会到概念:哪里有空白 → 我要做成什么样', time: '10 分钟',
+ pts: [{t: '10–20 分', ti: '概念的四句话', html: `
+<p>机会是「哪里有空白」,概念是「我要做成什么样」。一个概念,能用四句话讲清楚:</p>
+<ol>
+<li><b>给谁:</b>什么人,在什么场景下。</li>
+<li><b>解决什么:</b>他现在的痛点是什么(带原话)。</li>
+<li><b>做什么:</b>产品是什么形态、什么工艺、什么价格带。</li>
+<li><b>凭什么:</b>为什么是我们做得出、别人做不好(工艺 + 供应链 + 品牌)。</li>
+</ol>
+<div class="case"><h4>对比:两个都叫「健康面」的概念,差在哪</h4>
+<div class="tbl-scroll"><table class="tbl wide"><thead><tr><th></th><th>概念 A</th><th>概念 B</th></tr></thead><tbody>
+<tr><td>四句话</td><td>给想健康但怕胖的轻断食青年 → 在宿舍夜宵场景 → 想吃面怕负罪感 → 做一款荞麦青稞非油炸面</td><td>给想吃非油炸但觉得贵的家庭囤货主妇 → 在日常囤货场景 → 非油炸都卖 6 元以上 → 做一款 ≤4 元带的非油炸汤面</td></tr>
+<tr><td>机会卡依据</td><td>G4「健康」29/39 篇;G4 中位点赞 467,为六组第二高</td><td>「≤4 元 × 非油炸」格:对手 14 个、康师傅 0 个</td></tr>
+<tr><td>反例 / 风险</td><td>健康需求是品类可承载的吗?——「少油少盐」可以,「代餐减肥」撞品类边界</td><td>非油炸在 ≤4 元确实做得出吗?——14 个对手里多是低价散牌,要查工艺和成本</td></tr>
+<tr><td>可以过会吗</td><td>取决于能否把「轻断食」收回到「相对健康」</td><td>取决于成本能不能打进 4 元带</td></tr>
+</tbody></table></div>
+<p class="case-foot">概念 A 讲得很诱人,但卡在品类边界;概念 B 听起来朴素,但正好落在第三节讲的「工艺做得出 + 市场上说得通」的交汇处。</p></div>
+<p>一个好的概念,在四句话之外还要能过三道关:<b>四句话能不能被一句话问倒</b>(比如「凭什么别人做不了?」「凭什么是我们?」「用户为什么比现在更愿意买?」)——<b>能过这三问,再往下做示意图。</b></p>`}]
+},
+{
+ id: 'big3-p3', no: '三', title: 'AI 能帮什么、不能替什么', time: '12 分钟', goal: '把 AI 放进流程,但别让它替你做判断',
+ pts: [{t: '20–32 分', ti: '四件可以让 AI 做的事', html: `
+<div class="two-col">
+<div class="col"><h4>1. 概念可视化:生成产品示意图</h4><p>把「四句话」交给 AI,让它生成包装、形态、使用场景的示意图。可以用在小组展演和提案的第一页,帮助团队对齐「我们说的是同一个东西」。</p><p class="muted">边界:示意图是想象,不是设计稿;不能拿示意图去说服决策,要说清「以下为生成示意,需设计确认」。</p></div>
+<div class="col"><h4>2. 卖点文案:多版本表达</h4><p>同一个卖点,按不同价格带、不同人群、不同场景各写一版。客户最期待的也是这一块:<b>怎么把产品故事讲得让消费者更想买,让品牌方一听就觉得「不一样」。</b></p><p class="muted">边界:任何一版都不能越过证据边界——说「更少油」可以,说「健康无负担」就要有依据。</p></div>
+<div class="col"><h4>3. 竞品对比:把机会放回市场里看</h4><p>让 AI 拉一个「我们的概念 vs 同格竞品」的对比表:形态、工艺、价格、卖点组合、证据。找出差异点,也找出看起来一样的地方。</p><p class="muted">边界:AI 的对比只能基于已有的商品和原话数据,它拼不出没采集到的品牌。</p></div>
+<div class="col"><h4>4. 串联分析:把散落的分析拼成一份材料</h4><p>13 份产出物是散的。让 AI 按「结论 → 依据 → 风险 → 行动」的结构串成提案,你做减法,不做加法。</p><p class="muted">边界:串联不能掩盖矛盾。两段分析互相打架,要写进提案,不要删掉。</p></div>
+</div>
+<p>一句话记住:<b>AI 做十版,人挑一版。</b>十版都是草稿,挑那版的理由必须是你的。</p>`}]
+},
+{
+ id: 'big3-p4', no: '四', title: '提案的表达层次', time: '10 分钟',
+ pts: [{t: '32–42 分', ti: '给谁看、讲什么、先讲结论', html: `
+<div class="three-col" style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:10px 0">
+<div class="kvcard card" style="border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--card)"><h4 style="margin:0 0 6px;font-size:14px;color:var(--red)">给谁看</h4><ul style="font-size:13.5px;margin:0;padding-left:1.1em"><li>协同圈:工艺、供应链——关心<b>做不做得出来</b></li><li>决策圈:领导、委员会——关心<b>值不值得投、属于哪类创新</b></li><li>生态圈:渠道——关心<b>好不好卖、有没有货架位置</b></li></ul></div>
+<div class="kvcard card" style="border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--card)"><h4 style="margin:0 0 6px;font-size:14px;color:var(--red)">讲什么</h4><ul style="font-size:13.5px;margin:0;padding-left:1.1em"><li>同一个提案,三份版本:一句话(决策圈)、一页(协同圈)、一份(归档)</li><li>三类创新属性必须写在开头,避免「用同一把尺」</li></ul></div>
+<div class="kvcard card" style="border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--card)"><h4 style="margin:0 0 6px;font-size:14px;color:var(--red)">先讲结论</h4><ul style="font-size:13.5px;margin:0;padding-left:1.1em"><li>第一页只写三件事:做什么、为什么现在、要什么资源</li><li>证据往后放,顺序是结论 → 依据 → 风险 → 行动</li></ul></div>
+</div>
+<p>这份提案的读者,大概率就是你在第二段大课看到的穿透圈层里的人。提到决策圈时,最忌讳的是「用销量考一个代际迭代」。提案里说清「这属于三类创新中的哪一类、看什么指标」,本身就是过会的门票。</p>
+<p>展演的规矩:一组 5 分钟,不能超过 5 页;其他组每组至少提一个「缺什么」的问题——按 D2-08 的质询记录表来。</p>`}]
+},
+{
+ id: 'big3-p5', no: '五', title: '市场侧延展:定稿之后还能做什么', time: '8 分钟',
+ pts: [{t: '42–50 分', ti: '三件事可以把一个概念往前推一步', html: `
+<ol>
+<li><b>产品示意:</b>概念定稿后,用 AI 生成形态、包装、使用场景示意图;在小组内先对齐,再在对外沟通里用「生成示意,待设计确认」的标注使用。</li>
+<li><b>卖点表达:</b>定一个「证据允许说到哪」的边界,再在这个边界内按价格带、人群、场景生成多版本。每一版都要能对应到一条原话或一个商品事实。客户最期待的正是这一块——研发人员不是不会讲故事,是需要从证据出发去讲。</li>
+<li><b>渠道接受度预判:</b>用价格带、形态、毛利去反推:这个产品适合什么渠道?同类商品在那个渠道卖什么价?要多少量才能撑得起进店?——数据里没有渠道端销量的,标「待确认」,用研发经验给出定性判断。</li>
+</ol>
+<p>这三件事不改变概念,只是把概念从「一说出来」推到「别人能接住」。做完之后,一份提案就具备了被讨论的基础。</p>
+<p>AI 推送(大课三结束时):</p>
+<div class="push"><div class="push-bar"><b>AI 推送</b><span>大课三结束</span></div><div class="push-rows">
+<div class="push-row"><b>【本轮产出】</b><p>你手上有:一套排序规则(证据强度 × 可做性 × 商业价值,任一维 1 分不进前三)、概念四句话、提案的三层读者和「先讲结论」的写法。</p></div>
+<div class="push-row"><b>【还缺什么】</b><p>缺把上午的机会卡逐个打分排序。不排序,下午四节就只是把 2–3 个机会都做一遍,最后做不深一个。</p></div>
+<div class="push-row"><b>【下一步】</b><p class="ask">接下来要做 D2-05 机会验证与排序。请先回答:你组 V1.0 候选里,哪一个机会的「可做性」你最有把握?凭什么?</p></div>
+</div></div>`}]
+}
+],
+after: [
+{t: '讲师备忘', cls: 'note', html: `
+<ul>
+<li><b>客户最期待卖点部分。</b>23 号课前对齐会上,客户原话大意是:研发人员讲故事的能力相对薄弱,5 块钱的产品讲的时候老觉得受限,要针对不同价位把产品故事讲得让消费者更想买。所以第三段的「2. 卖点文案」和第五段的「2. 卖点表达」要多留时间——如果整体超时,先砍概念对比的例子。</li>
+<li><b>示意图不要用真实品牌元素</b>,提示词里要求「不出现任何品牌 Logo」,避免在法律和品牌层面出问题。</li>
+<li>下午四节 + 展演的时间很紧(D2-05 至 D2-08 约 3 小时),展演前 10 分钟要收齐各组提案。</li>
+</ul>`}
+]
+}
+);
+
+// m3 · D1 下午:D1-01 ~ D1-04 + D1-N(产出物样卡在 x2-deliv.js,提示词在 x1-prompts.js)
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'half', id: 'half-d1', label: 'D1 下午', time: '13:30–17:30',
+theme: '从「我觉得」到「有证据」',
+lead: '先听完大课一的完整架构,再把这个品类长什么样、什么数字才算证据、竞品在卖什么、我们怀疑什么,一条线走完;最后把怀疑写成今晚能执行、能停下的任务。',
+goal: [
+  '<a href="#d101">品类全景图谱</a> + <a href="#d102">本题验证配置卡</a>',
+  '<a href="#d103">竞品图谱 + 待验证痛点假设</a> + <a href="#d104">增强 AI 自驱任务卡</a>',
+  '一个决定、三个待答问题;任务卡交给 AI 过夜(<a href="#d1n">调研战报 + 缺口清单</a>明早验收)'
+],
+note: '每个环节对应八步 SOP 的哪一步:D1-01 → ① ② ③ 开场;D1-02 定证据纪律;D1-03 → ② 看供给;D1-04 → ③ 看需求的待答清单。'
+},
+
+{
+kind: 'section', id: 'd101', no: 'D1-01', title: '品类全景扫描', group: 'D1 下午', type: '八步 ① 定课题 · ② 看供给 · ③ 看需求',
+time: 'D1 15:00–15:40', from: '本组课题卡(课前确认的课题方向:使用情境 + 产品范围)',
+prompts: ['d101'],
+industry: {
+  title: '读图之前:方便面是由哪些格子组成的',
+  html: `<p>供给树的分支不是随便分的。方便面的供给有四个真实维度,每个维度背后是不同的工艺和成本:</p>
+<table class="tbl"><thead><tr><th>维度</th><th>分支(课堂数据里的口径)</th><th>为什么这样分</th></tr></thead><tbody>
+<tr><td><b>形态</b></td><td>袋装 184 · 桶装 95 · 盒装 22 · 杯装 21 · 碗装 20 · 未标注形态 58(共 400)</td><td>泡的、拌的、炒的准备方式不同;桶装/碗装包材占比 25–35%,袋装 12–13%</td></tr>
+<tr><td><b>工艺</b></td><td>非油炸 105 · 鲜熟/半干 24 · 未标注 271</td><td>油炸脱水、非油炸(热风三段控温)、半干(酸浸 pH 4.2–4.6)是三条产线,成本结构不同</td></tr>
+<tr><td><b>价格带</b></td><td>≤4 / 4–6 / 6–9 / &gt;9 元每 100g</td><td>同一形态在不同价格带是不同的生意:≤4 元拼规模,&gt;9 元拼溢价</td></tr>
+<tr><td><b>地域风味</b></td><td>陕西 31 · 武汉热干面 25 · 北京 15 · 江浙沪 10 · 广东 9 · 新疆 7 · 川渝 6</td><td>差异化主要来源之一,但溢价能力要用有效价验证</td></tr>
+</tbody></table>
+<p>需求树来自六大人群(G1 上班族 / G2 学生 / G3 户外 / G4 健康 / G5 一人食囤货 / G6 地域)。供需缺口就是「供给树的某个格子,有没有对应人群在同一格子里的原话」。</p>
+<p class="muted">提醒:400 个商品是按 16 个关键词搜出来的样本,不是全市场;「未标注」不等于「油炸」,只说明标题里没写。</p>`
+},
+pillars: [
+{name: '我已经知道的', tip: '凭经验、凭已有资料就能判断的。不要写「大概」,写具体:哪个产品、哪个价位、哪个渠道。', sample: '康师傅主力在 4 元以下的经典系列;桶面比袋面贵;近两年非油炸的牌子多起来了。'},
+{name: '我还不知道的', tip: '意识到自己不懂的。这一栏最值钱——AI 会优先补这里。', sample: '非油炸在 ≤4 元价格带里到底是谁在做、做得怎么样?地域风味是不是真能卖高价?'},
+{name: '我希望搞清楚的', tip: '想通过 AI 补上的具体问题,最好对应到一个会改变结论的判断。', sample: '我们课题所在的「价格带 × 工艺」格子里,主要玩家是谁、有没有空白。'},
+{name: '我的真实限制', tip: '预算、现有产线、渠道、合规、时间。写清楚,AI 才不会推荐做不到的方向。', sample: '本课题不考虑自建非油炸产线;不能动用主品牌做高溢价。'}
+],
+problem: `<p>打开资料库之前,很少有人知道方便面有这么多分法:泡的和拌的、油炸的和非油炸的、4 元的和 14 元的、陕西的和日式的。不问清楚这个品类<b>由哪些格子组成、每个格子谁在占</b>,后面所有「找机会」都只能在自己熟悉的那几格里打转。</p>
+<p>这一节要回答:<b>本组课题所在的那几格,长什么样?有没有明显缺位?</b>它不负责判断「哪里是机会」——那是 D2 的事。</p>
+<p>产出物是<b>品类全景图谱</b>:一张三栏表,左边供给树、右边需求树、中间连供给缺口。这张表是整个三个半天的底座,后面每一张卡都会回到它上面找位置。</p>`,
+how: `
+<p><b>发起任务。</b>把提示词连同四栏认知盘点一起发给数字分身。提示词只交代本节要什么(供给树、需求树、供需缺口、来源与覆盖),怎么建树、怎么取证由 Skill 决定。</p>
+<p><b>AI 会做什么:</b>先看本组前序上下文,在资料库(商品 400 条、用户笔记 260 篇、工艺知识库 49 条)里找你能用的部分;按形态、工艺、价格带、地域味道、人群画出供给树和需求树;在两边之间连上「人群 × 场景 × 需求」的实际命中。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>它会先给一版树,再指出「哪里证据薄」。<b>证据薄的分支,正是你「我还不知道的」这一栏要核对的地方。</b></li>
+<li>当它问你「这个课题要不要把 X 算进来」时,回答要能改变结论:说清「为什么算 / 为什么不算」,而不是「都行」。</li>
+<li>你答不上来、但不影响结构的,直接让它标「待确认」往下走,不要停下来。</li>
+</ul>`,
+deliver: `<p>交付物:<b>品类全景图谱</b>。图上必须同时有:三棵树的分支、每一支的计数与来源、以及最后一栏「空白点 × 缺口」。<b>空白点只写格子,不写结论</b>——结论留给 D2-04。</p>`,
+discuss: `
+<ul>
+<li><b>对齐格子。</b>每组把本组课题落在供给树的哪几格贴出来;看有没有两组的格子重叠。重叠不一定是问题,但要知道。</li>
+<li><b>挑出「薄格子」。</b>每组说出一个「证据薄、值得后面看」的格子,并说清薄在哪里:是商品少,还是用户原话少。</li>
+<li><b>写下三个待答问题。</b>从「我还不知道的」和「薄格子」里各挑几条,收敛成 3 条,带到 D1-04。</li>
+</ul>`,
+check: ['我们能不能在供给树上指出本组课题所在的格子?', '每个空白的判断有没有对应的计数(不是「感觉很少」)?', '有没有把「未标注 271」直接当成「没有」?'],
+right: ['把「未标注 271」当「标题没写」,不当「油炸」。', '每个格子都写出一个计数和来源文件。', '认知盘点里的「我还不知道的」至少有一条被这次扫描回答了。'],
+wrong: ['拿搜索关键词的结构当市场份额(400 个是按 16 个关键词搜出的样本)。', '把淘宝/天猫当可靠比价源(59 条里只有 2 条有效价)。', '扫完就下「哪里是机会」的结论——那是 D2 的事。'],
+push: {
+  out: '你手上有:品类全景图谱 v1——供给树按「形态 / 工艺 / 价格带 / 地域」四维拆开,需求树按六大人群拆开,并标出了「有供给、没需求原话」和「有需求、没供给」两大类空白点。',
+  gap: '但图谱只到格子,还没落到「本组课题的格子是谁在占、占得多满」。比如「≤4 元 × 非油炸」这一格,你只知道康师傅 0 个。缺这一格的主要玩家、价格和卖点,D1-03 才能比。',
+  next: '【下一步】接下来要做 D1-02 验证纪律。请先回答:这张图里,哪一条结论即使换个统计口径也会成立?哪一条会变?(它会决定验证配置卡要锁哪几条口径。)',
+  who: '本组数字分身 · D1-01 结束时自动输出'
+},
+handoff: '交给 D1-02:品类全景图谱 v1 + 本组 3 个「薄格子」+ 用到的数据口径。D1-02 的第一件事,就是拿验证配置卡回查这张图。'
+},
+
+{
+kind: 'section', id: 'd102', no: 'D1-02', title: '验证纪律', group: 'D1 下午', type: '证据纪律:锁住「什么叫成立」',
+time: 'D1 15:40–16:05', from: 'D1-01 的品类全景图谱 + 本组 3 个薄格子',
+prompts: ['d102'],
+industry: {
+  title: '背景:口径一换,结论就变——两个真实例子',
+  html: `<p><b>价格口径。</b>125 条有效价里,54 条标题含「整箱 / 组合 / 混合 / 批发」。按 125 条算,≤4 元占 42.4%;剔除整箱后剩 71 条,≤4 元占 47.9%,中位从 4.17 降到 4.10。康师傅更明显:≤4 元 22 个,其中 15 个是整箱或混合装,剔除后只剩 7 个。</p>
+<p><b>统计口径。</b>同一个「中位数」,G1 按通常算法是 48.5,汇总文件里的「上中位数」是 52。数字都对,但没写清用的是哪一种,谁也没法复核。</p>
+<p>这两个例子说明:<b>不是数字错了,是口径没定。</b>验证纪律就是把口径提前定死,写进配置卡,后面每个环节照这张卡办。</p>`
+},
+pillars: [
+{name: '我已经知道的', tip: '本组现在用的口径:价格怎么算、样本怎么剔、哪几条结论最容易被人反驳。', sample: '百克价是标题推算,不是到手价;康师傅 ≤4 元里很多是整箱。'},
+{name: '我还不知道的', tip: '不知道哪些数据「不算数」,哪些统计要写分母。', sample: '小红书点赞能不能当热度?社媒中位点赞受不受账号体量影响?'},
+{name: '我希望搞清楚的', tip: '希望在配置卡里锁定的规则。', sample: '保留还是剔除整箱价;词典打标要不要逐条复核。'},
+{name: '我的真实限制', tip: '本组能拿到什么数据、拿不到什么。', sample: '没有销量、没有复购、没有满意度;不能调用企业内部数据。'}
+],
+problem: `<p>每个组都会产出一堆数:多少条、占比多少、中位多少。但没有验证纪律,这些数会在展演时被一句「这个口径对吗」问倒。</p>
+<p>这一节只定一件事:<b>本组的结论,按什么标准才算成立。</b>资料资格、统计与引文口径、模型分工、分歧处理——四样写进一张卡,后面 12 个环节都用它。顺带回查 D1-01 的图谱,看有没有违规。</p>`,
+how: `
+<p><b>发起任务。</b>提示词要求 AI 先给一张验证配置卡的初稿,再逐条挑 D1-01 图谱里最容易被反驳的主张,用配置卡的标准回查。</p>
+<p><b>AI 会做什么:</b>读本组图谱,找出「只靠一次点赞快照」「只靠词典打标」「混了两种口径」的主张,逐条给出:怎么改口径、改完结论会不会变。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>「模型分工」这一项,AI 会问「哪些判断必须人来定」。把 D1-01 里你们最不放心的一条写进去。</li>
+<li>涉及企业标准(成本、工艺参数、价格政策)的,一律让它标「待确认」,不要让它猜。</li>
+<li>当它说「这条结论在两种口径下方向一致」,核对两个数字是不是都写出来了。</li>
+</ul>`,
+deliver: `<p>交付物:<b>本题验证配置卡</b>。四块内容缺一不可,另外加一列「回查记录」:拿这张卡回查本组图谱后,哪几条主张被降级了。</p>`,
+discuss: `
+<ul>
+<li><b>比卡片。</b>两组交换配置卡,专挑对方「统计口径」问一句:「如果我换一种口径,你的结论变不变?」</li>
+<li><b>合并。</b>全班讨论后形成一份通用的最低纪律(建议至少包含:写分母、价格双口径、词典词抽读)。</li>
+<li><b>回查。</b>各组拿通用纪律回查 D1-01 图谱,改掉违规处。</li>
+</ul>`,
+check: ['我们的配置卡能不能拦住「康师傅 ≤4 元 22 个」这种容易被反驳的说法?', '词典打标词(辣、贵、量大)有没有规定必须抽读原文?', '有没有硬性的「三种情况分开报」——没查到 / 没权限 / 不存在?'],
+right: ['所有比例都写分母;中位数写明是哪一种。', '价格、竞品声量都报两种口径。', '把「课堂成果标未经正式确认」写进卡片。'],
+wrong: ['把「剔除整箱后」的新数字悄悄替掉旧数字,不说明。', '只锁统计口径,不锁「哪些判断必须人来定」。', '写一张很漂亮但没人会遵守的卡——配置卡要短到能贴在桌上。'],
+push: {
+  out: '你手上有:本题验证配置卡——五块内容(资料资格 / 统计口径 / 引文口径 / 模型分工 / 分歧处理)+ 一张回查记录(本组图谱里哪几条被降级为假设)。',
+  gap: '但配置卡只管「证据成不成立」,还不管「证据该怎么比」。比如竞品的卖点怎么比、声量怎么比、正反原话怎么读——这些还没规则。另外图谱里那 3 个薄格子,谁在占、占得怎么样,还是空的。',
+  next: '【下一步】接下来要做 D1-03 竞品格局。请先回答:本组最关心的是哪一款竞品的卖点组合?你怀疑它哪里没做透?(小组先把这两个问题答出来,再发提示词。)',
+  who: '本组数字分身 · D1-02 结束时自动输出'
+},
+handoff: '交给 D1-03:验证配置卡 + 回查后修订的图谱。D1-03 的竞品比较必须按这张卡的口径做。'
+},
+
+{
+kind: 'section', id: 'd103', no: 'D1-03', title: '竞品格局', group: 'D1 下午', type: '八步 ② 看供给 · ③ 看需求(起假设)',
+time: 'D1 16:05–16:45', from: 'D1-01 图谱 + D1-02 验证配置卡',
+prompts: ['d103'],
+pillars: [
+{name: '我已经知道的', tip: '本组熟悉的产品和品牌,它们卖得怎么样、卖什么价位。', sample: '康师傅 BIG 干拌面主要在 4 元出头;日清、拉面说在 6 元以上。'},
+{name: '我还不知道的', tip: '不熟的竞品在哪个价格带、哪几层卖点、用户正反怎么评价。', sample: '低价非油炸是谁在卖?用户是在夸还是嫌?'},
+{name: '我希望搞清楚的', tip: '能推翻本组固有认知的竞品信号。', sample: '6 元以上价格带里,用户原话更多是夸还是嫌?'},
+{name: '我的真实限制', tip: '本组能查的范围。', sample: '竞品社媒每家只有一个关键词,不能当声量。'}
+],
+problem: `<p>竞品格局最容易犯的错,是「比声量」——总赞、篇数、热度。但这批数据里声量不可比:每家各一个关键词、约 20 篇,还混着兜售帖和活动帖。而且你们真正要回答的不是「谁声量大」,而是「本组所在的那一格,谁已经占了、占的是什么卖点组合、用户正反都说了什么」。</p>
+<p>这一节要产出两样:<b>竞品图谱</b>(同格商品与卖点组合矩阵)和 <b>2–3 条待验证痛点假设</b>(可证伪的)。它们是 D1-04 任务卡的原型。</p>`,
+industry: {
+  title: '读矩阵之前:为什么拌面这个形态值得单独看',
+  html: `<p>拌面和汤面的差别不只是「泡好倒水」:</p>
+<ul>
+<li><b>准备方式不同。</b>拌面要么开火煮、要么泡好沥干,多一步;这一步对宿舍、办公室、高铁是门槛,对「想吃更接近现做」的场景反而是价值。</li>
+<li><b>料包结构不同。</b>汤面的味道主要靠汤底(粉包 + 酱包),拌面靠酱料附着在面上,酱包占比更高,香辛料和油的配比逻辑不一样。</li>
+<li><b>价格带结构不同。</b>康师傅 BIG 干拌面 12 盒整箱的百克价在 3.59–4.09 元之间;竞品里拉面说、白象的拌面价差很大。拌面天然跨两个价格带的生意。</li>
+</ul>
+<p>所以竞品格局不能把汤面和拌面混在一起比——混在一起,比出来的只是关键词命中。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词交代:商品层面比什么(同格商品的卖点组合),社媒层面比什么(卖点组合 + 正反原话),以及要求「区分商品宣称 / 用户回应 / 你的推断」。</p>
+<p><b>AI 会做什么:</b>按配置卡口径挑出同格商品,整理卖点组合矩阵;从竞品社媒里找「正反都有」的原话;针对本组最关心的 2–3 个问题,提出可证伪的痛点假设。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>看到特别高的单条互动,先问是不是活动帖、表情包或重复抓取——再让它判断。</li>
+<li>「拌面」是标题词,不等于产品形态。让它说明哪些是真实态、哪些只是关键词。</li>
+<li>痛点假设必须是<b>能被推翻的句子</b>。「用户想要更非油炸」不算,「≤4 元价格带的非油炸用户,愿意为了非油炸多付 1 元」才算。</li>
+</ul>`,
+deliver: `<p>交付物:<b>竞品图谱 + 待验证痛点假设</b>。矩阵表里每一个卖点格子只标三种:<span class="chip">宣称</span> 商品标题/详情写的;<span class="chip">回应</span> 用户原话说的;<span class="chip tag">推断</span> 你们自己的判断——三者不混。</p>`,
+discuss: `
+<ul>
+<li><b>认领假设。</b>每组从假设清单里认领 2–3 条,说清「凭什么这么怀疑」。认领的假设要带编号(H1、H2…)。</li>
+<li><b>互挑。</b>邻组专挑你组假设里的「不可证伪句」,要求改写。</li>
+<li><b>对齐。</b>确认每条假设都写清了「什么情况推翻它」——这是下一节任务卡的反证路径。</li>
+</ul>`,
+check: ['我们的竞品比较有没有用总赞排品牌声量?', '痛点假设是不是一句能被推翻的话?', '矩阵里区分了「商品宣称 / 用户回应 / 我们的推断」吗?'],
+right: ['先抽掉兜售帖和重复帖,再比。', '找「正反都有」的原话——那才是活着的需求。', '假设写成「在 X 人群、Y 场景、Z 价格带,用户愿意为 W 付出 N」。'],
+wrong: ['用「日清中位 11.25 元」说明「高端是趋势」(那批样本多是进口礼盒)。', '把「拌面」关键词数量当形态份额。', '假设写成「用户希望产品更好」——不可证伪。'],
+push: {
+  out: '你手上有:竞品图谱(同格商品 × 卖点组合矩阵,标了宣称 / 回应 / 推断)和 2–3 条带编号的可证伪痛点假设。',
+  gap: '假设有了,但还没有验证计划。没有验证路径,今晚 AI 就不知道先查什么、查到哪算完;没有反证路径,它会把所有证据都往「支持」那边读。',
+  next: '【下一步】接下来要做 D1-04 假设定稿与任务下达。请先回答:这三条假设里,哪一条如果被推翻,本组课题就要换方向?(把这一条排在最前面。)',
+  who: '本组数字分身 · D1-03 结束时自动输出'
+},
+handoff: '交给 D1-04:竞品图谱 + H1–H3 待验证痛点假设(带各假设的「凭什么怀疑 / 什么情况推翻」)。'
+},
+
+{
+kind: 'section', id: 'd104', no: 'D1-04', title: '假设定稿与任务下达', group: 'D1 下午', type: '③ 看需求 —— 把假设写成今晚能跑的任务',
+time: 'D1 16:45–17:20', from: 'D1-01 图谱 · D1-02 配置卡 · D1-03 竞品图谱与假设',
+prompts: ['d104'],
+pillars: [
+{name: '我已经知道的', tip: '三条假设,以及各自的证据现状。', sample: 'H1:≤4 元带非油炸用户愿意多付 1 元——现在只有 3 条原话,证据薄。'},
+{name: '我还不知道的', tip: 'AI 过夜能跑到什么,有什么不能跑。', sample: '外部补证抓不抓得到商品评论?能不能抓抖音?'},
+{name: '我希望搞清楚的', tip: '最想让今晚回答的那一个问题。', sample: '用户说的「想吃非油炸但贵」,到底是在说价格,还是在说不值?'},
+{name: '我的真实限制', tip: '今晚只能在授权范围内跑。', sample: '授权外部补证,但只限公开社媒和电商;不碰内部数据。'}
+],
+problem: `<p>前两节攒下的假设,如果原样交给 AI 过夜,它会做什么?大概率是:把所有看起来相关的证据都找回来,然后写一份「支持 H1 的证据有……」——因为它不知道这个任务什么时候算做完,也不知道什么情况该停下来。</p>
+<p>这一节把假设写成<b>一张增强 AI 自驱任务卡</b>:每条假设给一个编号、一个支持路径、一个反证路径、一个停止条件。这张卡决定了今晚 AI 跑得快不快、准不准、停得下停不下。</p>`,
+how: `
+<p><b>发起任务。</b>提示词要求 AI 把三条假设整理成任务卡:字段固定,每条假设一行;最多 3 条主线,其余放「备查」。</p>
+<p><b>AI 会做什么:</b>补齐每条假设的「支持 / 反证 / 停止条件」字段;指出哪些字段拿不准、需要你们回答;只问「会改变结论」的问题。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>停止条件必须是<b>看得见的东西</b>:「找到 5 条反例」「读完 G4 全部 39 篇」——不能写「查得差不多了」。</li>
+<li>任务边界要写清:只执行这张卡里的假设,不扩展新方向;不需要补证就直接成报。</li>
+<li>数据来源与权限:先复用资料库;外部补证是否授权、去哪里补,由本组当场决定。</li>
+</ul>`,
+deliver: `<p>交付物:<b>增强 AI 自驱任务卡</b>。一页卡,每条假设一行;页面底部三个签字位:<b>本组确认</b>、<b>验证配置卡编号</b>、<b>授权状态</b>(仅资料库 / 可外部补证)。</p>`,
+discuss: `
+<ul>
+<li><b>收齐。</b>每组的任务卡交给助教归档——今晚 AI 就按卡执行,明早按卡验收。</li>
+<li><b>互查。</b>两组交换任务卡,专挑「停止条件」:它能不能被程序判定?「读完了」「差不多了」打回去。</li>
+<li><b>定决定。</b>每组用一句话写下<b>本组今天做出的决定</b>——「我们要不要做 X」或「我们选 A 还是 B」。这个决定写进任务卡抬头。</li>
+</ul>`,
+check: ['每条假设都有编号、支持路径、反证路径、停止条件吗?', '停止条件能不能被程序判断(数字或清单),而不是「查得差不多」?', '授权状态写清了吗:只跑资料库,还是可以外部补证?'],
+right: ['主线假设不超过 3 条,其余放「备查」。', '反证路径写得和支持路径一样具体。', '任务卡抬头写清本组的决定——今晚的一切是为它服务的。'],
+wrong: ['只写支持路径,不写反证路径——AI 会形成偏见。', '停止条件写「调查充分」——没法执行。', '夜里让它「顺便再想想新方向」——范围一扩,什么深度都没有。'],
+push: {
+  out: '你手上有:增强 AI 自驱任务卡(H1–H3 + 支持 / 反证 / 停止条件 + 授权状态)和本组今天做出的决定。D1 下午四个环节的产出物齐了。',
+  gap: '但任务卡还没跑。今晚 AI 要按它跑 16 个小时,明早先验收,而不是先看它找到了什么。',
+  next: '【下一步】今晚执行 D1-N 第二轮调研。请在交卡前回答:如果今晚只能得到一条答案,你最想要哪一条?(就这一条,写进任务卡抬头。)',
+  who: '本组数字分身 · D1-04 结束时自动输出'
+},
+handoff: '交给 D1-N(晚间执行)与明早 D2-01(验收):任务卡原件 + 验证配置卡编号 + 本组的决定。'
+},
+
+{
+kind: 'section', id: 'd1n', no: 'D1-N', title: '第二轮调研(晚间执行)', group: 'D1 下午', type: 'AI 自驱 · 人下线',
+time: 'D1 17:20 – D2 08:00(AI 跑,约 16 小时)', from: 'D1-04 的增强 AI 自驱任务卡 + D1-02 验证配置卡',
+prompts: ['d1n'],
+pillars: [
+{name: '我已经知道的', tip: '今晚要验证的是哪几条假设、用到哪些资料。', sample: 'H1–H3,资料库 + 授权的外部补证。'},
+{name: '我还不知道的', tip: '明早应该重点看什么。', sample: '三条假设里哪一条证据最薄?'},
+{name: '我希望搞清楚的', tip: '今晚第一件事做什么。', sample: '先把资料库原件查一遍,再判断要不要补证。'},
+{name: '我的真实限制', tip: '今晚 AI 只能在这个范围内工作。', sample: '只执行任务卡,不扩方向;找不到的按三类分开报。'}
+],
+problem: `<p>今晚不需要人坐在电脑前。AI 按任务卡执行:先复用资料库原件,检查每条假设被支持到什么程度;只对「会改变判断的真实缺口」决定是否外部补证;最后按假设键做 VOC 预聚类,产出战报和缺口清单。</p>
+<p>这一节的产出物明早 D2-01 第一件事就验收。所以任务卡里的停止条件和授权状态,今晚就会被严格执行——写成什么样,明早就收到什么样。</p>`,
+how: `
+<p><b>发起任务。</b>把任务卡编号和验证配置卡编号发给 AI,让它按卡执行。人不在场,AI 按 Skill 规则自行判断是否补证。</p>
+<p><b>AI 会做什么:</b>按假设键逐条查找、整理、比对证据;按停止条件停;产出战报、缺口清单(三类分开)、VOC 预聚类。</p>
+<p><b>你该怎么回应(明早):</b></p>
+<ul>
+<li>先看缺口,再看结论。缺口是「今晚最重要的发现」也说不定。</li>
+<li>看到「没查到」先问是哪一类:没搜到、平台不给、还是东西不存在。</li>
+<li>任何一条结论,先用编号回到原件核对。</li>
+</ul>`,
+deliver: `<p>交付物:<b>调研战报 + 缺口清单</b>。战报按假设键一页写:假设 → 结论(支持 / 部分支持 / 推翻 / 未回应)→ 证据(带原件)→ 缺口(三类)→ 对下一步的影响。</p>`,
+discuss: `
+<p>明早 D2-01 用。这一节没有现场讨论。</p>`,
+check: ['战报里每条结论是不是都能回到原件?', '缺口是否分了「没查到 / 没权限 / 不存在」三类?', '每条假设的停止条件是否被尊重?'],
+right: ['战报抬头写明执行范围(资料库 / 外部补证)与执行时间。', '证据按假设键归档,明早能一条条回读。', '「不支持」比「支持」更值得看——它会让今晚的任务更有价值。'],
+wrong: ['战报里混着「AI 推测」和「原件证据」,不区分。', '为了「看起来有成果」,把薄证据写成「支持」。', '超出任务卡范围,自己找了 20 个新方向。'],
+push: {
+  out: '你手上有:调研战报(按假设键逐条)+ 缺口清单(三类)+ VOC 预聚类。这是三源交叉的第一批结构化的用户原声。',
+  gap: '但战报是 AI 的初判,不符合验证配置卡的思路。比如「辣」「贵」这类词典打标结果,需要人工抽读;部分结论可能没有对应的原件。',
+  next: '【下一步】明早先做 D2-01 调研验收。请先回答:晚上跑出来的结论里,你一眼看上去觉得「不对劲」的是哪一条?为什么?',
+  who: '本组数字分身 · D1-N 结束(凌晨)自动输出;明早一打开就能看到'
+},
+handoff: '明早交给 D2-01:调研战报 + 缺口清单 + VOC 预聚类,按假设键归档。'
+}
+);
+
+// m4 · D2 上午:D2-01 / D2-02 / D2-03 / D2-04(产出物样卡在 x2-deliv.js,提示词在 x1-prompts.js)
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'half', id: 'half-d2a', label: 'D2 上午', time: '09:00–12:20',
+theme: '从「有证据」到「有机会」',
+lead: '先验收昨晚的战报,再听大课二把「机会」定义清楚;然后把用户原声分层,把供给矩阵和需求对上,最后在三条线的交叉处写下候选机会。',
+goal: [
+  '<a href="#d201">战报验收记录</a>(含缺口与可用资料集合)',
+  '<a href="#d202">聚类表 + 痛点库 + KANO 表 + 人群 × 场景矩阵</a>,<a href="#d203">产品机会及指标初表</a>',
+  '<a href="#d204">候选机会清单 V1.0</a>:2–3 张机会卡,三源证据齐全'
+],
+note: '对应八步 SOP:D2-01 收口 ③;D2-02 至 D2-03 是 ④ 找交叉;D2-04 是 ④ 与 ⑤ 的交接——机会成立之后,下午才能排序。'
+},
+
+{
+kind: 'section', id: 'd201', no: 'D2-01', title: '调研验收', group: 'D2 上午', type: '③ 看需求 —— 先验收,再使用',
+time: 'D2 09:00–09:25', from: 'D1-N 的调研战报 + 缺口清单,按假设键归档',
+prompts: ['d201'],
+pillars: [
+{name: '我已经知道的', tip: '昨晚任务卡里三条假设,本组最想看哪一条。', sample: 'H1 最想看:≤4 元带的非油炸用户愿不愿意多付 1 元。'},
+{name: '我还不知道的', tip: '战报里哪些是 AI 推断、哪些有原件。', sample: '「23 篇提到」的 23 条原文在哪?'},
+{name: '我希望搞清楚的', tip: '最想先核对哪一条结论。', sample: 'G4「健康」29 篇里,有多少是在说方便面?'},
+{name: '我的真实限制', tip: '验收只能看战报和原件,不能重新跑。', sample: '时间只有 25 分钟。'}
+],
+problem: `<p>早上第一件事不是看战报里找到了什么,而是看它<b>能不能被信</b>。昨晚 AI 按任务卡跑了一整夜,它会把「支持」和「没找到」混着写,把「没搜到」和「数据不存在」写成一句话,把词典打标当成用户态度。</p>
+<p>这一节用一张检查表把战报过一遍:<b>假设回应率、原件覆盖率、分母口径</b>,三项合格,战报才能进入后面的环节。</p>`,
+how: `
+<p><b>发起任务。</b>提示词要求 AI 从战报里抽出一张验收记录:每条假设回应到什么程度、支撑结论的原件能不能找到、所有比例的分母写没写;缺口是否分了三类。</p>
+<p><b>AI 会做什么:</b>逐条核对假设回应;抽读词典打标词条目;把「未回应」的假设标出来,并说明为什么不回应。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>随机抽 5 条结论,自己点开原件读一遍——AI 说「支持」,读原文是不是在支持。</li>
+<li>对于「部分支持」,问清楚剩下没被支持的那部分具体是什么缺口。</li>
+<li>有「AI 推断」的结论,逐条标记「降级为假设」。</li>
+</ul>`,
+deliver: `<p>交付物:<b>战报验收记录</b>。三列检查 + 一张可用资料集合:验收合格、能直接用的原件放「可用」;不合格的降级为「假设」或「待确认」。</p>`,
+discuss: `
+<ul>
+<li><b>报缺口。</b>每组用一句话说「昨晚最重要的一个缺口」——不是最重要的发现,是缺口。</li>
+<li><b>全班汇总缺口类型。</b>把各组缺口归成三类,看哪一类最多;哪一类是靠更多时间能补上的,哪一类是资料本身就没有。</li>
+<li><b>确认可用资料集合。</b>这个集合是 D2-02 分层编码的输入。</li>
+</ul>`,
+check: ['三条假设的回应率算出来了吗?', '支撑结论的原件,能点开读到吗?', '每个比例都写了分母吗?'],
+right: ['抽 5 条读原件,从「支持」里找出 1 条误读。', '把「未回应」的假设留下来,并写清缺口是什么。', '可用资料集合里,只放回到原件能读通的条目。'],
+wrong: ['战报「写得很好看」就通过。', '所有「没找到」合并成一句「资料库里没有」。', '跳过验收,直接开始聚类——错的前提会带偏后面的所有环节。'],
+push: {
+  out: '你手上有:战报验收记录——假设回应率、原件覆盖率、分母口径三项合格,外加一份可用资料集合(按假设键归档、能回读原件)。',
+  gap: '这批资料还是散的——同一句「想吃非油炸但嫌贵」,在不同人群里可能是完全不同的意思。而且你能感觉到「辣」「健康」这些词打标有误读,但还没在资料里统一纠正。',
+  next: '【下一步】先听大课二,把「机会」定义清楚;然后做 D2-02 VOC 证词聚类。请先回答:你组的可用资料里,最多的是哪一类原话(主妇囤货、学生夜宵、上班加班、户外、健康、地域)?',
+  who: '本组数字分身 · D2-01 结束时自动输出'
+},
+handoff: '交给大课二 + D2-02:战报验收记录 + 可用资料集合(按假设键归档)。'
+},
+
+{
+kind: 'section', id: 'd202', no: 'D2-02', title: 'VOC 证词聚类', group: 'D2 上午', type: '④ 找交叉 —— 把原话拆成四层',
+time: 'D2 10:15–11:05', from: 'D2-01 战报验收记录 + 可用资料集合',
+prompts: ['d202'],
+pillars: [
+{name: '我已经知道的', tip: '本组可用资料里,最突出的一两种原话。', sample: '上班族组里反复出现「晚上九点才吃」。'},
+{name: '我还不知道的', tip: '同一个词,不同人群是不是一个意思。', sample: '「健康」在 G4 里是在说减脂,还是在说少添加?'},
+{name: '我希望搞清楚的', tip: '哪些痛点是「反复出现但没有被解决」的。', sample: '「想吃非油炸但觉得贵」到底有几个人。'},
+{name: '我的真实限制', tip: '原话只能用语料原文,不能用 AI 改写的。', sample: '每条原话都带笔记 ID。'}
+],
+problem: `<p>「辣」「贵」「量大」这些词,词典打标出来的频次在课堂上都会看到——但大课二已经讲过,同一个数字换一个读法,结论就反了。所以聚类不能从词频开始,要从<b>四个层次</b>开始:<b>人群 → 场景 → JTBD → 痛点</b>。四层混在一起,就会出现「辣是最大痛点」这种明显的误读。</p>
+<p>这一节要产出四张表:聚类表(每个原话落在哪一层)、痛点库(带态度判定的痛点)、KANO 表(每条痛点属于什么需求类型)、人群 × 场景矩阵。</p>`,
+industry: {
+  title: '读原话之前:四层为什么不能混',
+  html: `<p>拿一句最常见的原话:「晚上九点才吃饭,我只点半碗」。</p>
+<table class="tbl compact"><thead><tr><th>层</th><th>这一句里对应什么</th><th>如果混了会怎样</th></tr></thead><tbody>
+<tr><td><b>人群</b></td><td>加班到很晚的上班族</td><td>只看人数,看不出是谁</td></tr>
+<tr><td><b>场景</b></td><td>晚上九点的加班餐</td><td>看不到「时间晚了」这个条件</td></tr>
+<tr><td><b>JTBD</b></td><td>想在已经很晚、胃口一般的时候吃一点、不折腾</td><td>被误读成「想要小份量」</td></tr>
+<tr><td><b>痛点</b></td><td>夜里胃口小,但也担心重辣重油</td><td>「点半碗」「避免重辣重油」被当成两个独立偏好</td></tr>
+</tbody></table>
+<p>这是 G1 里唯一一条真在说「辣」有点问题的原话。如果四层混了,它会被并入「辣」的 39 次里,看不出它其实是一个人、一个场景的一句话。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词要求 AI 把可用资料的原话按四层拆开;对每个痛点词,抽读原文,标注态度(正 / 负 / 读不出);输出四张表。</p>
+<p><b>AI 会做什么:</b>先把打标词的原话抽出来读;再按人群、场景做矩阵;再给每条痛点贴一个 KANO 类型(基本型 / 期望型 / 兴奋型),标注「频次先验」——意思是这是基于频次的假设,不是问卷调查结果。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>如果你在原文里看到和 AI 判定相反的句子,直接写在表格旁边,要求它重新判。</li>
+<li>KANO 类型拿不准的,先标「待确认」,后面用 D2-05 的验证来补。</li>
+<li>不要为了让表好看,把「读不出态度」的原话删掉——它们本身是数据的一部分。</li>
+</ul>`,
+deliver: `<p>交付物:<b>四张表</b>——聚类表、痛点库、KANO 表(频次先验)、人群 × 场景矩阵。每一格都必须带笔记 ID,能回读原文。</p>`,
+discuss: `
+<ul>
+<li><b>挑三句。</b>每组从痛点库里挑三句最有代表性的原话,贴在白板上——读出来,让别组判断它属于哪个人群、哪个场景。</li>
+<li><b>对照大课二。</b>你们组里有没有出现「AI 初判」和「人工复核」相反的条目?挑一条讲。</li>
+<li><b>找空白格。</b>在人群 × 场景矩阵里,找到有原话但没有产品对应的格子——这是 D2-03 的输入。</li>
+</ul>`,
+check: ['每一句原话都落在唯一一层(人群/场景/JTBD/痛点)吗?', '打标词都有态度判定(正/负/读不出)吗?', '矩阵每一格都有笔记 ID 吗?'],
+right: ['把「读不出态度」的原话单独列为一类。', '对「辣」「贵」「量大」先抽读原文,再决定归哪一类。', 'KANO 表标明「频次先验」,不冒充问卷结果。'],
+wrong: ['把所有含「汤」的原话都归为「想要汤面」。', '按打标频次直接排名次,不抽读。', 'KANO 类型拍脑袋,没有任何依据。'],
+push: {
+  out: '你手上有:四张表——聚类表、痛点库、KANO 表(频次先验)、人群 × 场景矩阵,每一格都能回读笔记 ID。',
+  gap: '这些原点声音还只在「需求」这一侧。它们还没有和「供给」对上——哪一格需求有原话,但市场上没有对应的产品?哪个产品有供给,但需求原话是空的?这个对照还没有做。',
+  next: '【下一步】接下来要做 D2-03 风味趋势与矩阵空白。请先回答:你组的人群 × 场景矩阵里,哪一个格子「原话最多,但最不知道该买什么」?',
+  who: '本组数字分身 · D2-02 结束时自动输出'
+},
+handoff: '交给 D2-03:四张表 + 3 个「有原话、没产品」的格子。'
+},
+
+{
+kind: 'section', id: 'd203', no: 'D2-03', title: '风味趋势与矩阵空白', group: 'D2 上午', type: '④ 找交叉 —— 需求对上供给',
+time: 'D2 11:05–11:45', from: 'D2-02 四张表 + D1 的品类全景图谱',
+prompts: ['d203'],
+pillars: [
+{name: '我已经知道的', tip: '本组课题所在的格子、以及需求最强的格子。', sample: 'G4「健康」29 篇最强,G6「口味新鲜」23 篇最强。'},
+{name: '我还不知道的', tip: '「空白」到底是别人没做,还是没人要。', sample: '≤4 元 × 非油炸,另外 14 个 SKU 卖得怎么样?'},
+{name: '我希望搞清楚的', tip: '哪几格是「有需求 + 没供给」或者「有供给 + 没需求」。', sample: '6–9 元价格带里,用户原话是不是多了?'},
+{name: '我的真实限制', tip: '数据是单次快照,不能判趋势方向。', sample: '没有时间序列,看不到涨跌。'}
+],
+problem: `<p>需求侧四张表做完了,现在是 ④ 找交叉:把「需求强度」放到「供给矩阵」上。看到空白时,初学者最容易写「这里是机会」——但大课二已经讲过:<b>空白不是机会,是待验证的问题</b>。</p>
+<p>这一节要产出<b>产品机会及指标初表</b>:每个机会都要带上它需要验证的指标,而且按「结构 / 变化 / 未覆盖」三类分开——这三类的证据强度完全不同,放进同一张表会互相抬价。</p>`,
+industry: {
+  title: '读矩阵之前:三类空白,说法完全不同',
+  html: `<p>把每次搜索当成一次快照:<b>结构</b>是现在长什么样,<b>变化</b>是过去一段时间往哪走,<b>未覆盖</b>是该有的东西还没有。单次快照能看见结构,看不见变化。</p>
+<p><b>结构</b>:价格带 53 / 43 / 13 / 16(≤4 / 4–6 / 6–9 / &gt;9),非油炸 105 个 SKU 里 49 个是未识别品牌;拌面是标题词——63.7% 的商品标题含「拌面」,但其中大量是营销词。</p>
+<p><b>未覆盖</b>:≤4 元 × 非油炸,康师傅 0 个。但同一格有 14 个别人家的有效价 SKU。</p>
+<p><b>变化</b>:这批数据只有一次快照,<b>不能判</b>「非油炸在涨」「地域风味在火」。要判变化,必须拿同一关键词隔一段时间再采一次。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词要求 AI 把需求矩阵和供给矩阵叠在一起,按三类(结构 / 变化 / 未覆盖)列出空白,并给每格一个「机会指标」(要验证什么、用什么数据能验证)。</p>
+<p><b>AI 会做什么:</b>找出「需求有原话 + 供给为空」的格子;找出「供给满、需求原话薄」的格子(这是危险区,可能没人要);把价格带、工艺、形态、地域四个维度交叉。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>任何「在涨」的说法,问它有没有时间序列;没有,改写成「现在是 X」。</li>
+<li>「未覆盖」的格子,先查同格竞品——如果有,空白就不成立,它是「被谁占着」。</li>
+<li>指标要能在接下来的三个小时内被验证,或明确写「本次不验证」。</li>
+</ul>`,
+deliver: `<p>交付物:<b>产品机会及指标初表</b>。一行一个机会,五列:空白格(人群 × 场景 × 价格带 × 工艺)、类别(结构 / 变化 / 未覆盖)、供给证据、需求证据、需要验证的指标。</p>`,
+discuss: `
+<ul>
+<li><b>数一数。</b>每组报「结构 / 未覆盖」各几个、「变化」几个。如果许多组在「变化」上写了判断,一起看时间序列——没有的,全降为「结构」。</li>
+<li><b>查同格。</b>挑本组一个「未覆盖」格,说出同格已有的其他品牌 SKU 有几个、是什么——有,就写「已有 N 个,其中谁」。</li>
+<li><b>挑指标。</b>每组从表里选出最关键的 2 个指标,准备 D2-04 用。</li>
+</ul>`,
+check: ['表里有没有「在涨」的结论?时间序列在哪?', '每个「未覆盖」格,是否查过同格竞品?', '每个机会都带了「需要验证的指标」吗?'],
+right: ['「≤4 元 × 非油炸」写成「未覆盖(康师傅 0 个,同格对手 14 个 SKU)」——带条件。', '有原话、没供给 ≠ 机会;有供给、没原话 ≠ 需求。两者都标「待验证」。', '「变化」类单独列一栏,标「本次不验证」。'],
+wrong: ['把「搜索页找不到」当成市场空白。', '用「日清在 6 元以上」推出「6 元以上是趋势」。', '把三个类别混在一张排序表里,互相比较。'],
+push: {
+  out: '你手上有:产品机会及指标初表——每个空白格都带类别(结构 / 变化 / 未覆盖)、供给证据、需求证据、需要验证的指标。',
+  gap: '这些空白还只是「纸条」,没有一条用户原话直接贴在它上面。D2-04 要求三源交叉,现在只有供给和需求两边,工艺这一边(这一格做不做得出来)还没写。',
+  next: '【下一步】接下来要做 D2-04 三源交叉推理。请先回答:你组最想先认证的 2 个空白格里,你作为研发人认为哪一个「工艺上最有可能做出来」?为什么?',
+  who: '本组数字分身 · D2-03 结束时自动输出'
+},
+handoff: '交给 D2-04:机会及指标初表 + 2 个关键指标。'
+},
+
+{
+kind: 'section', id: 'd204', no: 'D2-04', title: '三源交叉推理', group: 'D2 上午', type: '④ 找交叉 · ⑤ 验机会(交接)',
+time: 'D2 11:45–12:20', from: 'D2-02 四张表 + D2-03 机会及指标初表',
+prompts: ['d204'],
+pillars: [
+{name: '我已经知道的', tip: '本组最想认证的 2 个空白格,以及用户原话在哪。', sample: '≤4 元 × 非油炸;「想吃非油炸但贵」。'},
+{name: '我还不知道的', tip: '用户原话和商品事实有没有真正对上。', sample: '说「贵」的人,是在嫌哪个价格带贵?'},
+{name: '我希望搞清楚的', tip: '工艺这一边这一格做不做得出来。', sample: '≤4 元带,非油炸工艺成本能不能撑住。'},
+{name: '我的真实限制', tip: '数据不含销量、复购、满意度。', sample: '不能写「这种产品一定好卖」。'}
+],
+problem: `<p>上午的最后一步:把供给、用户原声、工艺条件三条线交在一起。<b>三条线都指向同一个方向,才写进机会卡;只有两条线指向的,标「候选」;只有一条的,只能写「线索」。</b></p>
+<p>这一节产出<b>候选机会清单 V1.0</b>:每张机会卡 6 个字段——一句话结论、三源证据、反例、还缺什么、下一步验证、工艺注释。</p>`,
+industry: {
+  title: '读机会卡之前:工艺注释怎么写',
+  html: `<p>机会卡的第六栏「工艺注释」是这张卡里唯一由你(研发侧)亲手写的部分。AI 只能标「待确认」,因为 AI 不知道你们产线的真实条件。</p>
+<p>好的工艺注释写成这样:<b>「热风三段控温(80–90℃ / 90–100℃ / 70–80℃)在行业通行取值下,可把面饼做到含水 8–12%。但 ≤4 元价格带要求成本压低,非油炸工艺路线的成本能不能撑住,取决于 5 分钟复水时间是否可接受。」</b></p>
+<p>带具体参数、带条件、带风险——不是「非油炸可行」。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词要求 AI 对 D2-03 的 2 个空白格做三源交叉;每张机会卡都必须有至少一条供给证据、一条用户原话、一条工艺条件(或标「待工艺确认」);给出一句话结论和一句话反例。</p>
+<p><b>AI 会做什么:</b>找到支持的机会证据;找反例;列缺口;给出下一步验证方向。工艺注释留给组里填写。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>「三条线都指向」的工作由你做:AI 只负责给证据,判断由你拍板。</li>
+<li>工艺注释写具体参数,不写「可行」「能做」。</li>
+<li>缺口要写「这会影响哪一个结论」。</li>
+</ul>`,
+deliver: `<p>交付物:<b>候选机会清单 V1.0</b>。2–3 张机会卡,每张 6 个字段。结论必须是「一个可被推翻的判断」。</p>`,
+discuss: `
+<ul>
+<li><b>半天展演。</b>一组上台讲它的一张机会卡,其他组提「一句反驳」——反驳可以针对任何一条证据。</li>
+<li><b>挑最脆弱的证据。</b>每组指出自己卡里最薄弱的一条证据,并说它将如何补强。</li>
+<li><b>报「未覆盖」。</b>提醒各组的工艺注释:哪一栏是你们写的,哪一栏是 AI 待确认的。</li>
+</ul>`,
+check: ['每张机会卡三源各有证据,或明确标「待确认」?', '一句话结论能否被推翻,反例是否写明?', '工艺注释是你们写的,还是 AI 代写的?'],
+right: ['三源都薄的机会,标为「线索」而不是「候选」。', '反例写得和支持证据一样具体。', '工艺注释写参数和风险,不写「可行」。'],
+wrong: ['为了让卡好看,把「待工艺确认」删掉。', '把三源证据里的某一个来源反复引用,看起来证据很多。', '结论写「这是一个机会」——不可证伪。'],
+push: {
+  out: '你手上有:候选机会清单 V1.0——2–3 张机会卡,每张 6 个字段,三源证据、反例、缺口和工艺注释都写出来了。D2 上午的产出物齐了。',
+  gap: '这些卡还没有排过序。哪个值得先做、哪个应该放一放、哪个根本做不了,还没有判断;而且「做不做得出来、划不划算」这一块还没算。',
+  next: '【下一步】下午先听大课三(收敛与表达),再做 D2-05 排序。请先回答:你组这几张卡里,哪一张你最没把握?没把握在哪一条证据上?',
+  who: '本组数字分身 · D2-04 结束时自动输出'
+},
+handoff: '交给大课三 + D2-05:候选机会清单 V1.0(每张卡的 6 个字段)。'
+}
+);
+
+// m5 · D2 下午:D2-05 / D2-06 / D2-07 / D2-08(产出物样卡在 x2-deliv.js,提示词在 x1-prompts.js)
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'half', id: 'half-d2p', label: 'D2 下午', time: '13:30–17:30',
+theme: '从「有机会」到「能落地」',
+lead: '听大课三把收敛、表达、交付讲清楚;然后把候选机会排序、回推能不能做、把卖点讲成用户听得懂的话,最后交出一份能过会的提案。',
+goal: [
+  '<a href="#d205">优先级机会清单 + 未知项单列</a>,<a href="#d206">回推表 + 候选机会清单 V2.0</a>',
+  '<a href="#d207">价值主张卡 + 卖点清单</a>',
+  '<a href="#d208">概念提案 + 候选清单 V3.0 + 成果导航</a>'
+],
+note: '对应八步 SOP:D2-05 是 ⑤ 验机会;D2-06 是 ⑥ 算可行;D2-07 是 ⑦ 定卖点;D2-08 是 ⑧ 出方案。'
+},
+
+{
+kind: 'section', id: 'd205', no: 'D2-05', title: '机会验证与排序', group: 'D2 下午', type: '⑤ 验机会 —— 多个机会怎么选',
+time: 'D2 14:20–15:05', from: '候选机会清单 V1.0(2–3 张机会卡)',
+prompts: ['d205'],
+pillars: [
+{name: '我已经知道的', tip: '每张卡的三源证据和反例。', sample: 'A 卡证据最厚,但工艺注释写「要新产线」。'},
+{name: '我还不知道的', tip: '哪张卡缺一个关键数据,现在打不了分。', sample: '消费者愿意多付 1 元这件事,没测过。'},
+{name: '我希望搞清楚的', tip: '排序后谁第一、为什么。', sample: '证据强、能做的,是不是同一个。'},
+{name: '我的真实限制', tip: '只有 45 分钟。', sample: '先用课堂证据排序,缺的数据写进未知项。'}
+],
+problem: `<p>多张机会卡摆在面前,最容易的排序法就是「我觉得」。大课三给了一套规则:<b>证据强度 × 可做性 × 商业价值</b>,三个维度各打 1–3 分;<b>任何一维得 1 分的机会,不能排进前三。</b></p>
+<p>这一节还要做一件更重要的事:<b>把未知项单独列出来</b>。有些机会打不了分,不是因为它差,是因为缺一个数据——这些要进「未知项表」,而不是被塞进低分。</p>`,
+how: `
+<p><b>发起任务。</b>提示词要求 AI 对 V1.0 每张机会卡打三个维度分,并给每个分数写出依据和风险;不能打分的,单独列为未知项,写清缺什么数据。</p>
+<p><b>AI 会做什么:</b>从每张卡的证据里统计证据强度;按工艺注释判可做性;按价格带和竞品情况初判商业价值(这项最需要你复核)。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>商业价值这一维,AI 的初判很可能过于乐观,用你的研发经验和价格带常识逐条复核。</li>
+<li>能做的机会往往在「≤4 元」这些拥挤的格子——不要因为「容易做」就排第一。</li>
+<li>如果三张卡都得了 2 分,找出得分原因里的「同一条」——通常是一起缺同一个数据。</li>
+</ul>`,
+deliver: `<p>交付物:<b>优先级机会清单 + 未知项单列</b>。排序表里每一行三个维度分值 + 依据一句话;未知项表里写「缺什么数据、能用什么方式补、本次能不能补」。</p>`,
+discuss: `
+<ul>
+<li><b>亮分。</b>各组把每张卡的三个分数贴在白板上,看有没有「任何一维 1 分却排进前三」的情况。</li>
+<li><b>互问。</b>邻组挑你的最高分,问:「这一分是课堂证据给的,还是你的经验给的?」——经验给的要在表里写明。</li>
+<li><b>锁定主攻机会。</b>每组确定 1–2 个主攻机会,带到 D2-06。</li>
+</ul>`,
+check: ['三个维度的分数都有依据,且写明是「证据」还是「经验」吗?', '有没有任何一维 1 分的机会被排进前三?', '未知项有没有和「低分」分开?'],
+right: ['每个分数后边写一句话依据。', '商业价值维度的分数逐条由本组复核。', '未知项表里写清「本次能不能补」。'],
+wrong: ['三个维度都打 3 分,等于没排。', '把证据强但做不出来的机会排第一。', '未知项直接写成 1 分。'],
+push: {
+  out: '你手上有:优先级机会清单(1–2 个主攻机会,三维打分带依据)+ 未知项表。',
+  gap: '排序只回答了「更值得先做」,还没有回答「做起来要花多少、划不划算」。现在主攻机会只有一个「可做性」分,没有成本、价格带和两条路(B0 / O1)的比较。',
+  next: '【下一步】接下来要做 D2-06 商业及供应链回推。请先回答:你组主攻机会的工艺路径,是「在现有配比上改」,还是「新增一条并行的产品线」?',
+  who: '本组数字分身 · D2-05 结束时自动输出'
+},
+handoff: '交给 D2-06:优先级机会清单 + 主攻机会(1–2 个)+ 未知项表。'
+},
+
+{
+kind: 'section', id: 'd206', no: 'D2-06', title: '商业及供应链回推', group: 'D2 下午', type: '⑥ 算可行 —— 做不做得出来、划不划算',
+time: 'D2 15:05–15:50', from: 'D2-05 优先级机会清单 + 主攻机会',
+prompts: ['d206'],
+pillars: [
+{name: '我已经知道的', tip: '主攻机会的形态、工艺路径,以及成本的大致量级。', sample: '非油炸、汤面、袋装,目标 ≤4 元/100g。'},
+{name: '我还不知道的', tip: 'B0 / O1 两条路的费用结构。', sample: '换线要投多少?新增一条并行产品线的营运资金怎么算?'},
+{name: '我希望搞清楚的', tip: '这个主攻机会在财务上值不值得立项。', sample: '两条路哪条更值?'},
+{name: '我的真实限制', tip: '课堂数据不含你们的真实成本。', sample: '用行业值估算,正式数据标「待确认」。'}
+],
+problem: `<p>商业可行性不是「算个成本就结束」,而是<b>算哪条路更值</b>。对比两条路:<b>B0</b> 现状(在现有配比上改),<b>O1</b> 改后(按目标方案做)。三条费用要分开算:一次费用、资本投入、营运资金。</p>
+<p>研发侧在这一节是本行:成本结构、代工价、产线条件、工艺可行性,你们比 AI 清楚得多。AI 负责把数字摆到台面上,你负责判断它们是不是靠谱。</p>`,
+industry: {
+  title: '读回推表之前:供应链口径一览',
+  html: `<table class="tbl"><thead><tr><th>口径</th><th>知识库数值</th><th>怎么用</th></tr></thead><tbody>
+<tr><td>代工价</td><td>2.1–3.2 元/袋(不含税运),对应零售 4–6 元;2026-10-29 单次 1688 询价</td><td>成本区间估算</td></tr>
+<tr><td>成本结构(袋装)</td><td>面饼 34–38% / 调料 24–30% / 包材 12–13% / 人工 10% / 能耗 5–7%</td><td>拆解报价</td></tr>
+<tr><td>成本结构(桶装)</td><td>纸碗 + 盖膜 0.30–0.50 元/个,包材占比升至 25–35%</td><td>判断形态</td></tr>
+<tr><td>装箱 / 外箱 / 配送 / 损耗</td><td>知识库无条目</td><td>必须向业务方取得,标「待确认」</td></tr>
+<tr><td>区域分工</td><td>河南 = 面饼 + 调料;四川 = 复合调味;广东 = 非油炸 + 包材;山东 = 调味粉 + 设备;湖北 = 热干面 / 碱水面</td><td>寻源</td></tr>
+<tr><td>验厂比例</td><td>抽样 60 条货源中仅 42% 为验厂工厂</td><td>供应商风险</td></tr>
+<tr><td>产线投资</td><td>90g 袋面线 10–13 万元;非油炸挤压熟化机 6.8 万元/台</td><td>资本投入</td></tr>
+</tbody></table>
+<p class="muted">代工价不是长期报价;成本结构是行业通行值。合规:GB 17400-2015 对水分 ≤10%、酸价 ≤1.8mg/g、过氧化值 ≤0.25g/100g 有要求;GB 2760-2024 对添加剂有限量——具体以标准正文为准。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词要求 AI 对主攻机会拆两条路(B0 / O1)、三条费用,并列出工艺与合规条件;所有课堂估算都标「课堂估算」;缺的数据标「待确认」。</p>
+<p><b>AI 会做什么:</b>用知识库的代工价和成本结构做区间估算;比较两条路的增量;列出合规条件。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>「B0 / O1 比较只在收入、渠道费用、损耗比例都相同时才成立」——这个条件不成立的,写清楚。</li>
+<li>涉及你们真实产线数字的,标「待内部确认」。</li>
+<li>把 AI 的估算和你的经验对比:差得多的,以你的经验为先,但写清依据。</li>
+</ul>`,
+deliver: `<p>交付物:<b>回推表 + 候选机会清单 V2.0</b>。回推表是对主攻机会的成本拆解;V2.0 是加入商业条件后更新过的主攻机会卡——在 V1.0 六字段基础上,加「成本区间 / 价格带 / 两条路对比 / 合规条件」。</p>`,
+discuss: `
+<ul>
+<li><b>亮成本。</b>每组主攻机会的「单位成本估算」和「目标价格带」贴出来。</li>
+<li><b>互问。</b>邻组问:「你这条成本估算里,哪一项是 AI 拍的,哪一项是你们确认的?」</li>
+<li><b>更新版本。</b>把 V1.0 的机会卡按回推表修订,标为 V2.0。</li>
+</ul>`,
+check: ['B0 / O1 两条路的三条费用都拆开了吗?', '哪些是课堂估算、哪些是经验值、哪些是待确认,分开了吗?', '合规条件(水分、酸价、添加剂)列了吗?'],
+right: ['成本按区间报,不报单一数字。', '工艺注释写清「换线 / 改线 / 新增产线」哪一条。', '所有 AI 估算都标「课堂估算」。'],
+wrong: ['把 B0 / O1 比较建立在不同营收假设上。', '把代工价当成长期成本报价。', '合规只写在文末一句,没有落到工艺参数上。'],
+push: {
+  out: '你手上有:回推表(两条路、三条费用、工艺与合规条件)+ 候选机会清单 V2.0。主攻机会现在有了成本、价格带和合规约束。',
+  gap: '有了产品,还没有一句话让用户想买。用户可能根本不知道自己为什么需要它——「这是热风非油炸」不等于「这碗面值 4 块钱」。卖点还没有。',
+  next: '【下一步】接下来要做 D2-07 价值主张与核心卖点。请先回答:你组用户原话里,哪一句最像「用户希望别人替他说出来的话」?(这一句往往是卖点的起点。)',
+  who: '本组数字分身 · D2-06 结束时自动输出'
+},
+handoff: '交给 D2-07:候选机会清单 V2.0 + 回推表 + 用户原话里最有代表性的一句话。'
+},
+
+{
+kind: 'section', id: 'd207', no: 'D2-07', title: '价值主张与核心卖点', group: 'D2 下午', type: '⑦ 定卖点 —— 把研发侧翻译成市场侧',
+time: 'D2 15:50–16:30', from: '候选机会清单 V2.0 + D2-02 痛点库原话',
+prompts: ['d207'],
+pillars: [
+{name: '我已经知道的', tip: '本组主攻产品的关键工艺参数、成本和价格带。', sample: '≤4 元、非油炸热风三段、成本压得住。'},
+{name: '我还不知道的', tip: '用户最能被打动的是哪一点。', sample: '他更在意「不油」还是「便宜」?'},
+{name: '我希望搞清楚的', tip: '一条能被复述的卖点。', sample: '能不能一句话说清?'},
+{name: '我的真实限制', tip: '不能宣传功能、不能夸大。', sample: '不能写「健康」「减脂」「养生」。'}
+],
+problem: `<p>客户最期待这一节。课前沟通时原话大意是:<b>研发人员讲故事的能力相对薄弱,5 块钱的产品讲的时候老觉得受限,要针对不同价位把产品故事讲得让消费者更想买、让品牌方一听就觉得不一样。</b></p>
+<p>讲故事的前提不是写得漂亮,而是<b>证据允许说到哪</b>。这一节先定边界,再在边界内写多版本。研发侧的关键词——「非油炸」「热风三段控温」「含水 8–12%」——要翻译成市场侧能听见、用户能记住的话。</p>`,
+industry: {
+  title: '读卖点之前:证据的边界',
+  html: `<table class="tbl"><thead><tr><th>可以说的</th><th>不能说的</th><th>为什么</th></tr></thead><tbody>
+<tr><td>「非油炸面饼」「热风干燥工艺」</td><td>「健康」「无负担」「养胃」</td><td>工艺描述是事实;健康宣称需要依据和法规语境</td></tr>
+<tr><td>「更少油:含油率从 X% 降到 Y%」</td><td>「减脂」「瘦身」</td><td>比较只能基于本产品历史数据,功效词不能碰</td></tr>
+<tr><td>「面条更筋道」「复水 5 分钟」</td><td>「更好吃」(没有对照测评)</td><td>口感参数、时间参数是客观的;口味判断要有对照</td></tr>
+<tr><td>「4 元一袋的经典味道」</td><td>「比 XX 品牌好吃」</td><td>比较广告需要合规支撑</td></tr>
+</tbody></table>
+<p class="muted">具体宣称以 GB 17400-2015 及现行广告法规为准;课堂只给出边界原则。</p>`
+},
+how: `
+<p><b>发起任务。</b>提示词要求 AI 先写价值主张卡(一句话主张 + 三条收益 + 三条证据 + 证据边界),再按价格带、人群、场景各写 2–3 个版本的卖点。</p>
+<p><b>AI 会做什么:</b>从 V2.0 机会卡和 D2-02 原话里提取价值主张;把研发语言翻译成用户语言;生成不同价位的版本。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>每个版本都要问:「这句话的每一半,有没有证据?」没有的删掉。</li>
+<li>「健康」「养生」这类词一律换掉,除非客户确认可以合规使用。</li>
+<li>用你的研发经验判断:AI 生成的卖点里,哪一条在技术上是「说得过去但做不到」——删掉。</li>
+</ul>`,
+deliver: `<p>交付物:<b>价值主张卡 + 卖点清单</b>。价值主张卡:一句主主张、三条收益(用户能感知的)、三条证据(组件 + 原话)、三行证据边界(能说什么 / 不能说什么 / 合规标示)。卖点清单:不同版本 × 适合的渠道/人群。</p>`,
+discuss: `
+<ul>
+<li><b>互相听。</b>每组读一句主主张,让别组复述——复述出来的和原句差多少,说明「用户听得懂」这件事。</li>
+<li><b>找越界。</b>别组从你的卖点里挑出所有「没证据或越界」的说法,标红。</li>
+<li><b>选版本。</b>确定主推版本 1 个 + 备选版本 1–2 个。</li>
+</ul>`,
+check: ['每一条卖点都能对到一条原话或一个商品事实吗?', '有没有出现「健康」「减脂」「养胃」等未经验证的宣称?', '不同价位/人群有没有不同版本?'],
+right: ['卖点从用户原话起步,再做加工。', '每写一句,用「证据允许说到哪」测一次。', '留一份「不能说的话」清单。'],
+wrong: ['用行业术语写卖点(「三段控温」)——用户听不懂。', '把「健康」当前缀随便加。', '只写一个版本,然后拿去套所有渠道。'],
+push: {
+  out: '你手上有:价值主张卡(一句主张 + 三条收益 + 三条证据 + 证据边界)和卖点清单(主推版 + 备选版 + 不能说的话)。',
+  gap: '主张和卖点有了,但还没有进入一份完整的提案——决策圈的读者看不到结论,协同圈看不到成本,生态圈看不到渠道适配。',
+  next: '【下一步】接下来要做 D2-08 概念提案与分享。请先回答:你组一句话能把整个提案讲完吗?写下来,再和已有的价值主张比一比。',
+  who: '本组数字分身 · D2-07 结束时自动输出'
+},
+handoff: '交给 D2-08:价值主张卡 + 卖点清单(主推版 + 备选版)。'
+},
+
+{
+kind: 'section', id: 'd208', no: 'D2-08', title: '概念提案与分享', group: 'D2 下午', type: '⑧ 出方案 —— 一份能过会的提案',
+time: 'D2 16:30–17:30', from: '候选机会清单 V2.0 + 价值主张卡 + 卖点清单',
+prompts: ['d208'],
+pillars: [
+{name: '我已经知道的', tip: '本组主攻机会的全部证据和成本。', sample: 'V2.0 + 回推表 + 卖点。'},
+{name: '我还不知道的', tip: '过会时最可能被问倒的问题。', sample: '这个价格带用户真的接受吗?'},
+{name: '我希望搞清楚的', tip: '提案要说服谁、先讲什么。', sample: '第一页写一句结论。'},
+{name: '我的真实限制', tip: '5 分钟、5 页以内。', sample: '结论 → 依据 → 风险 → 行动。'}
+],
+problem: `<p>最后一步:把散落的分析串成一份能过会的材料,并且能当着所有人的面讲清楚<b>为什么选这个</b>。</p>
+<p>这一节产出三样:<b>概念提案</b>(一句话 + 一页纸 + 全案)、<b>候选清单 V3.0</b>(经过质询后更新的版本)、<b>成果导航</b>(每一份产出物分别存在哪里、结营后怎么用)。</p>`,
+how: `
+<p><b>发起任务。</b>提示词要求 AI 按「结论 → 依据 → 风险 → 行动」的结构,把 V2.0、回推表、价值主张卡串成提案;同时生成一句话版和一页版。</p>
+<p><b>AI 会做什么:</b>生成提案草稿;列出质询清单(决策圈、协同圈、生态圈各三个问题);把矛盾处标出来,不删。</p>
+<p><b>你该怎么回应:</b></p>
+<ul>
+<li>你做减法:AI 的草稿一定太长,留下结论和支撑结论的那几条。</li>
+<li>把矛盾写进提案——两段分析互相打架的地方,往往是最值得在展演里讲的地方。</li>
+<li>答案必须在第一页:<b>做什么、为什么现在、要什么资源。</b></li>
+</ul>`,
+deliver: `<p>交付物:<b>概念提案 + 候选清单 V3.0 + 成果导航</b>。成果导航是一页目录:13 份产出物各自的保存位置、一份对应一句话的用途、结营后第一周先从哪一份开始用。</p>`,
+discuss: `
+<ul>
+<li><b>展演。</b>每组 5 分钟:一句话、一页、结论、风险、行动。</li>
+<li><b>质询。</b>其他组按「质询记录表」提出至少一个问题;提案组当场回应「答得出 / 待确认 / 答不出」。</li>
+<li><b>更新 V3.0。</b>质询后,把得到的修正写进 V3.0 机会卡。</li>
+</ul>`,
+check: ['第一页能不能用一句话说清「做什么、为什么现在、要什么资源」?', '提案里的每个数字能不能回到产出物?', '质询记录里的「答不出」有没有写进 V3.0?'],
+right: ['一句话、一页、全案三层都准备。', '把「答不出」的问题保留在提案里,作为下一步。', '成果导航能直接指导结营后第一周。'],
+wrong: ['堆满证据,结论在最后一页。', '把矛盾藏起来,让展演看起来更顺。', '质询后匆匆改掉数据,不记录修改理由。'],
+push: {
+  out: '你手上有:概念提案(一句话 + 一页 + 全案)、候选清单 V3.0、成果导航,以及质询记录。三个半天的产出物全部齐了。',
+  gap: '结营之后,最大的风险是这份「成果导航」躺在文件柜里。下周一开始、第一项任务,它必须回到真实的工作里。',
+  next: '【下一步】结营后第一周陪练:拿 V3.0 回来,选一个「答不出」的问题先补。请先回答:哪一份产出物你最想在第一周就回到部门里用?(写在成果导航第一行。)',
+  who: '本组数字分身 · D2-08 结束时自动输出'
+},
+handoff: '交给结营与训后陪练:概念提案 + V3.0 + 成果导航 + 质询记录。'
+}
+);
+
+// m6 · 附录:A 六个反常识 / B 行业结构速查 / C 常见问题 / D 话术对照
+window.SEGS = window.SEGS || [];
+
+window.SEGS.push(
+{
+kind: 'appx', id: 'appx-a', title: '附录 A · 六个反常识的数据发现', group: '附录',
+lead: '每一个都是课堂数据跑出来的「AI 初版结论」与「人工复核后」的对比。课上演示两三个,其余请自己翻一遍——它们决定了你在每个环节里该对 AI 的哪些数字多想一层。',
+traps: [
+{
+ n: 1, title: '「辣」:39 条里只有 1 条是嫌辣', tag: '词典打标 ≠ 用户态度;必须读原文',
+ ai: `<p>六组笔记里「辣」共出现 39 次,在 G1/G2/G3/G4/G5/G6 全部排痛点第一;最集中的 G6 有 10 条。「辣味过重是用户最大的痛点,建议全线降低辣度。」</p>`,
+ human: `<p>39 条逐条读原文:<b>正向(「辣得过瘾」「香辣美味」等当卖点夸)29 条、读不出态度 9 条、明确嫌辣只有 1 条</b>(G1「晚上九点才吃饭,我只点半碗」|「避免重辣重油」)。</p>
+<p>能写的结论只有:<b>用户高度关注辣味,正反都有</b>——不能写「用户嫌辣」。</p>`,
+ quote: 'G3「买一盒自热狮子头火锅一个肘子,大吃一顿」正文:「香辣美味,肥而不腻」;G6「一人食就做这个酸汤米线」正文:「酸酸辣辣,开胃又过瘾!」',
+ where: '看到「辣」「香」「麻」这类口味词,抽 5 条读原文,判正 / 负 / 读不出。',
+ note: '关联环节:<a href="#d103">D1-03</a>、<a href="#d202">D2-02</a>;<a href="#big2">大课二</a>'
+},
+{
+ n: 2, title: '「贵」:11 条里真正抱怨价格的很少', tag: '机器会犯最低级的错,人必须复核',
+ ai: `<p>「贵」在六组出现 11 次,G6 地域组 9 次最多——「地域风味用户对价格敏感,建议主打性价比。」</p>`,
+ human: `<p>G6 的 9 条全是「<b>贵州</b>」被词典识别成「贵」:如「贵州到底想怎样 连速食都那么好吃」「为什么在贵州带回来的羊肉粉这么好吃」「#南山婆贵州酸汤」。G3 的 1 条是高铁外卖配送费。逐条读下来,没有一条是真正在抱怨方便面的价格。</p>`,
+ quote: 'G6 正文:「贵州到底想怎样 连速食都那么好吃」',
+ where: '对单字、短词打标,先查它可能是别的词的一部分(贵州 / 贵价,重辣 / 重庆辣……)。',
+ note: '关联环节:<a href="#d202">D2-02</a>;与第 1 条一起讲'
+},
+{
+ n: 3, title: '「量大」:出现 2 次,都是夸', tag: '频次高不等于问题',
+ ai: `<p>样本里「量大」是高频词,说明用户很在意份量,建议推出大份量产品。</p>`,
+ human: `<p>全部 260 篇里「量大」只出现 <b>2 次</b>,都是正面:「山姆必买神仙早餐‼️便宜量大又好吃!」、「面是碱水面…量大一顿能吃很饱」。它不是高频词,更不是痛点。</p>`,
+ quote: 'G5 标题:「便宜量大又好吃」;G2 正文:「量大一顿能吃很饱」',
+ where: '看到「量大 / 量小 / 份量」,区分「夸」和「嫌」;频次说的是「有人提到」,不是「有人不满」。',
+ note: '关联环节:<a href="#d103">D1-03</a>、<a href="#d202">D2-02</a>'
+},
+{
+ n: 4, title: '价格:125 个有效价里 54 条是整箱 / 组合 / 批发', tag: '口径不同,结论会变',
+ ai: `<p>≤4 元/100g 占 42.4%(53/125),是最大价格带;康师傅在这一带有 22 个 SKU,主战场就在 ≤4 元。</p>`,
+ human: `<p>54 条标题含「整箱 / 组合 / 混合 / 批发」(整箱 54、批发 6、箱装 5、混合 3,有重叠)。剔除后只剩 71 条:≤4 元 34 条(47.9%)、4–6 元 19 条(26.8%)、6–9 元 6 条(8.5%)、&gt;9 元 12 条(16.9%)。</p>
+<p>康师傅 ≤4 元的 22 个里,15 个是整箱/混合装,剔除后只剩 7 个。</p>
+<table><thead><tr><th>价格带</th><th>125 条</th><th>71 条</th></tr></thead><tbody>
+<tr><td>≤4 元</td><td>53(42.4%)</td><td>34(47.9%)</td></tr>
+<tr><td>4–6 元</td><td>43(34.4%)</td><td>19(26.8%)</td></tr>
+<tr><td>6–9 元</td><td>13(10.4%)</td><td>6(8.5%)</td></tr>
+<tr><td>&gt;9 元</td><td>16(12.8%)</td><td>12(16.9%)</td></tr>
+<tr><td>中位(元/100g)</td><td>4.17(P25 3.54 / P75 5.86)</td><td>4.10</td></tr>
+</tbody></table>
+<p><b>结论方向不因口径改变,但份额和样本量必须按口径说。</b>整箱款的百克价是「总价 ÷ 总克数」摊出来的,不是单包零售价。</p>`,
+ quote: '康师傅:「经典红烧牛肉面五连包 104g*5」「大食袋红烧牛肉面五连包 138g*5」——同一款,一个算整箱散装、一个算单份。',
+ where: '任何价格结论,同时写两个分母:125 与 71;品牌结论写「有效价 35 个中 22 个,其中 15 个为整箱」。',
+ note: '关联环节:<a href="#d101">D1-01</a>、<a href="#d102">D1-02</a>、<a href="#d203">D2-03</a>'
+},
+{
+ n: 5, title: '汤达人:声量被兜售帖稀释,中位从 6 升到 29', tag: '样本污染会误导判断',
+ ai: `<p>汤达人社媒中位点赞 6,六家竞品最低——「汤达人用户讨论冷清,品牌老化」。</p>`,
+ human: `<p>20 篇里 10 篇点赞 ≤5,多为海外兜售帖:「洛杉矶汤达人 $10/3 大包」「洛杉矶汤达人一箱 $20/30 袋」「巴黎厨房的面柜可以补起来啦」「华人零食仓库」。</p>
+<p>剔除正文含「洛杉矶 / 巴黎 / 现货 / 批发 / 零食仓 / 清仓」的帖子后剩 16 篇,<b>中位从 6 升到 29</b>(其余五家剔除后中位不变:阿宽 78、日清 66、农心 321.5、拉面说 115……)。</p>
+<p class="muted">口径说明:剔除规则不同,结果也不同——只剔 2 条洛杉矶帖剩 17 篇、中位 21;只按标题去重不剔代购剩 19 条、中位 5。所以剔除规则本身要写下来。</p>`,
+ quote: '汤达人「汤达人吃出虫」(5 赞)——真正有用的质量信号,也埋在这一堆兜售帖里。',
+ where: '竞品比较前先看「点赞 ≤5」的条数占比;剔除不要只按标题,要读正文。',
+ note: '关联环节:<a href="#d103">D1-03</a>;<a href="#big2">大课二</a>'
+},
+{
+ n: 6, title: '一条内容被重复算了 4 次', tag: '去重是基本功',
+ ai: `<p>「答应我,一定要试试这个面条!!!」在多篇内容里出现,说明这个话题热度很高。</p>`,
+ human: `<p>这条在小红书上以不同标题被多次抓取:竞品社媒 120 行里同标题出现 4 次(阿宽、农心 ×2、拉面说),其中农心与拉面说两行正文完全相同;G5 的 Top1(11,522 赞)也是同一篇。</p>
+<p class="muted">另外:农心总赞 75,484 里 47,173(62.5%)是一条 aespa 活动帖;电商 400 行里有 11 个标题重复、多出 14 行(去重后 386 个唯一标题)。</p>`,
+ quote: '「答应我,一定要试试这个面条!!!」——桃桃的做饭日记(日更)',
+ where: '统计前按标题 / 作者 / 链接去重;看到特别高的单条互动,先查是不是活动、表情包或重复抓取。',
+ note: '关联环节:<a href="#d103">D1-03</a>、<a href="#d202">D2-02</a>'
+}
+],
+practice: {
+ title: '现场练习:用第 1 个反常识检验本组',
+ html: `<p>拿本组 D1-03 竞品图谱里最有把握的一条结论,做三件事:①找出支撑它的原文;②随机抽 5 条读态度;③重写这条结论,看改了多少。改完的结论交给邻组,问一句:「这句话是不是也能被原文推翻?」</p>`
+}
+},
+
+{
+kind: 'appx', id: 'appx-b', title: '附录 B · 行业结构速查', group: '附录',
+lead: '不是知识科普,是每个环节都要挂上的判断依据。数据全部来自课堂数据包或 49 条工艺知识库,口径附在每节末尾。',
+blocks: [
+{t: 'B1 形态分化:汤面 / 拌面 / 炒面 / 非油炸', html: `
+<table class="tbl"><thead><tr><th>形态 / 工艺</th><th>工艺路线</th><th>成本与结构要点</th><th>课堂数据里的样子</th></tr></thead><tbody>
+<tr><td><b>油炸汤面</b></td><td>油炸脱水:棕榈油 140–160℃,60–110 秒,含水 3–6%,含油 18–22%</td><td>行业最成熟的路径;袋装面饼占成本 34–38%</td><td>未标注工艺的 271 条,大多属于这一类</td></tr>
+<tr><td><b>拌面 / 干拌</b></td><td>泡好沥干或煮后拌;酱包占比更高</td><td>多一步准备;酱料成本上升</td><td>康师傅 BIG 干拌面 12 盒整箱百克价 3.59–4.09 元</td></tr>
+<tr><td><b>炒面(UFO 等)</b></td><td>杯面 + 沥水 + 炒面料的组合</td><td>杯装包材;准备步骤多</td><td>按「拌面」关键词搜,UFO 可能被归到拌面里——形态标签不完全可靠</td></tr>
+<tr><td><b>非油炸</b></td><td>热风三段控温(80–90℃/60–70% 湿 → 90–100℃/30–40% 湿 → 70–80℃ 低湿,含水 8–12%)或挤压熟化</td><td>要换线;代工价 2.1–3.2 元/袋</td><td>105 条,其中 29 条有有效价</td></tr>
+<tr><td><b>半干 / 鲜熟</b></td><td>蒸煮后酸浸至 pH 4.2–4.6,含水 20–26%,aw 0.85–0.90</td><td>需冷链或高酸保鲜</td><td>鲜熟/半干 24 条,有效价 3 条</td></tr>
+</tbody></table>
+<p class="muted">口径:工艺知识库 49 条为行业通行值,不是法定限量;商品工艺以标题标注为准,「未标注」≠「非油炸」。关联:<a href="#d101">D1-01</a>、<a href="#big1-p1">大课一第一段</a>。</p>`},
+{t: 'B2 价格带结构:谁在哪个带', html: `
+<table class="tbl"><thead><tr><th>价格带(元/100g)</th><th>125 条有效价</th><th>71 条(剔除整箱)</th><th>康师傅(35 个有效价)</th></tr></thead><tbody>
+<tr><td>≤4 元</td><td>53(42.4%)</td><td>34(47.9%)</td><td>22 个(其中 15 个为整箱/混合装)</td></tr>
+<tr><td>4–6 元</td><td>43(34.4%)</td><td>19(26.8%)</td><td>9 个</td></tr>
+<tr><td>6–9 元</td><td>13(10.4%)</td><td>6(8.5%)</td><td>1 个</td></tr>
+<tr><td>&gt;9 元</td><td>16(12.8%)</td><td>12(16.9%)</td><td>3 个(御品盛宴小龙虾拌面 ×2、Express 速达面馆红烧半筋半肉面 ×1)</td></tr>
+</tbody></table>
+<p>全样本中位 4.17、P25 3.54、P75 5.86;康师傅 P25 2.98 / 中位 3.93 / P75 4.24——四分之三的有效价落在 4 元附近。</p>
+<table class="tbl compact"><thead><tr><th>品牌</th><th>记录数</th><th>有效价</th><th>中位</th><th>能不能用来比价格</th></tr></thead><tbody>
+<tr><td>康师傅</td><td>53</td><td>35</td><td>3.93</td><td>可以用,注明整箱混杂</td></tr>
+<tr><td>统一</td><td>30</td><td>12</td><td>3.97</td><td>参考</td></tr>
+<tr><td>农心</td><td>35</td><td>15</td><td>4.86</td><td>参考</td></tr>
+<tr><td>今麦郎</td><td>36</td><td>2</td><td>3.01</td><td>样本太少,不能拿来比</td></tr>
+<tr><td>五谷道场</td><td>23</td><td>4</td><td>6.82</td><td>样本少;也有 3.18 元低价款</td></tr>
+<tr><td>拉面说</td><td>30</td><td>3</td><td>9.48</td><td>不能作价格带结论</td></tr>
+<tr><td>白象</td><td>28</td><td>6</td><td>9.40</td><td>6 个里 4 个是礼盒或混装整箱,不能用</td></tr>
+<tr><td>日清</td><td>28</td><td>7</td><td>11.25</td><td>含进口礼盒,不能用</td></tr>
+</tbody></table>
+<p class="muted">口径:百克价由标题克重与件数推算;京东 123 / 淘宝 2 条有效价,价格结论只代表京东样本。关联:<a href="#d101">D1-01</a>、<a href="#d102">D1-02</a>、<a href="#d203">D2-03</a>。</p>`},
+{t: 'B3 地域风味:样本里的溢价能力', html: `
+<p>地域风味标签(不含日式 59、韩式 55)按 CSV 逐条数为 109 条:陕西 31、武汉热干面 25、北京 15、江浙沪 10、广东 9、新疆 7、川渝 6、重庆小面 3、贵州 2、东南亚 1(<code>细分标签汇总.csv</code> 记 86 个,口径无法从 CSV 完全复现,引用 86 时需注明)。</p>
+<table class="tbl compact"><thead><tr><th>地域</th><th>有有效价的 SKU</th><th>中位(元/100g)</th></tr></thead><tbody>
+<tr><td>陕西</td><td>11</td><td>3.38</td></tr>
+<tr><td>武汉热干面</td><td>3</td><td>3.16</td></tr>
+</tbody></table>
+<p><b>判断:</b>在电商搜索样本里,地域风味不是高溢价,而是竞争扎堆的低价带;需求侧「正宗/地域」在 260 篇里只有 11 次,远低于「口味新鲜」106 次。另外「地域 速食面」关键词第 1 页 31 条里康师傅 20 条——那是自营店占据搜索页,不是品牌份额。</p>
+<p class="muted">关联:<a href="#d101">D1-01</a>、<a href="#d203">D2-03</a>。</p>`},
+{t: 'B4 工艺门槛一览', html: `
+<table class="tbl"><thead><tr><th>工艺</th><th>关键参数</th><th>判断用</th></tr></thead><tbody>
+<tr><td>油炸脱水</td><td>棕榈油 140–160℃,60–110 秒;含水 3–6%;含油 18–22%</td><td>成熟、成本低;「非油炸」诉求下是短板</td></tr>
+<tr><td>热风非油炸</td><td>三段控温:80–90℃ / 60–70% 湿 → 90–100℃ / 30–40% 湿 → 70–80℃ 低湿;含水 8–12%</td><td>非油炸主流路径之一;要专用线</td></tr>
+<tr><td>挤压熟化</td><td>高温高压 + 剪切,出模泄压膨化</td><td>非油炸另一条路径;单机 6.8 万元/台(知识库)</td></tr>
+<tr><td>半干 / 鲜熟</td><td>酸浸 pH 4.2–4.6,含水 20–26%</td><td>口感接近鲜面;保鲜难度高</td></tr>
+<tr><td>真空和面</td><td>−0.06 ~ −0.08 MPa,面团 ≤30℃,含油率可降 1–2 个百分点</td><td>降含油的第一步,不改线</td></tr>
+<tr><td>蒸煮 α 化</td><td>饱和蒸汽 95–100℃,2.5–3.5 分钟,糊化度 ≥85%</td><td>所有面型的基础环节</td></tr>
+<tr><td>复合压延</td><td>6–8 道,终轧面带 1.0–1.2mm</td><td>口感与强度</td></tr>
+</tbody></table>
+<p class="muted">关联:<a href="#d101">D1-01</a>、<a href="#big1-p1">大课一第一段</a>、<a href="#d204">D2-04</a>、<a href="#d206">D2-06</a>。参数为行业通行值,不是法定限量。</p>`},
+{t: 'B5 供应链口径:每个数字对应哪一个口径', html: `
+<table class="tbl"><thead><tr><th>口径</th><th>知识库数值</th><th>用在哪个环节</th></tr></thead><tbody>
+<tr><td>代工价</td><td>2.1–3.2 元/袋(不含税运),对应零售 4–6 元;2026-10-29 单次 1688 询价</td><td>D2-06 成本区间</td></tr>
+<tr><td>成本结构(袋装)</td><td>面饼 34–38% / 调料 24–30% / 包材 12–13% / 人工 10% / 能耗 5–7%</td><td>D2-06 拆解报价</td></tr>
+<tr><td>成本结构(桶装)</td><td>纸碗 + 盖膜 0.30–0.50 元/个,包材占比升至 25–35%</td><td>D2-06 判断形态</td></tr>
+<tr><td>装箱 / 外箱 / 配送 / 损耗</td><td>知识库无条目</td><td>D2-06 必须向业务方取得,标「待确认」</td></tr>
+<tr><td>区域分工</td><td>河南 = 面饼 + 调料;四川 = 复合调味;广东 = 非油炸 + 包材;山东 = 调味粉 + 设备;湖北 = 热干面 / 碱水面</td><td>D2-06 寻源</td></tr>
+<tr><td>验厂比例</td><td>抽样 60 条货源中仅 42% 为验厂工厂</td><td>D2-06 供应商风险</td></tr>
+<tr><td>产线投资</td><td>90g 袋面线 10–13 万元;非油炸挤压熟化机 6.8 万元/台</td><td>D2-06 资本投入</td></tr>
+</tbody></table>
+<p class="muted">关联:<a href="#big3">大课三</a>、<a href="#d206">D2-06</a>。代工价不是长期报价;成本结构是行业通行值。</p>`},
+{t: 'B6 「≤4 元 × 非油炸」18 格全景', html: `
+<p>4 个价格带 × 4 种工艺(油炸 / 非油炸 / 半干鲜熟 / 冻干或其他),合计 16 格;再走查一遍,另外还有两类:「工艺未标注」与「有工艺标签但无有效价」——所以实际做判断时,看 18 个区间更稳妥。</p>
+<div class="mat">
+<div class="mh corner"></div><div class="mh">≤4 元</div><div class="mh">4–6 元</div><div class="mh">6–9 元</div><div class="mh">&gt;9 元</div>
+<div class="k">油炸</div><div>未标注 271 中的多数<small>整箱居多</small></div><div>经典系列 + 竞品<small>(见附录 B2)</small></div><div>康师傅 1 个<small>(35 个有效价中)</small></div><div>日清 5 · 康师傅 3 · 白象 3<small>礼盒 / 高端款</small></div>
+<div class="k">非油炸</div><div class="z0"><b>康师傅 0</b><small>同格对手 14 个 SKU</small></div><div>9 个(多为小香厨 / 有你一面)</div><div>3 个</div><div>3 个(五谷道场 / 拉面说高端款)</div>
+<div class="k">半干鲜熟</div><div>有效价 3 条(不足以判定)</div><div>—</div><div>—</div><div>—</div>
+<div class="k">冻干/其他</div><div>数据未覆盖<small>列入「待确认」</small></div><div>—</div><div>—</div><div>—</div>
+</div>
+<p class="muted">口径:本表的明细由 <code>全部商品.csv</code>(工艺 / 百克价)与 <code>健康代餐赛道.csv</code>(价格带 × 工艺)联合核对:非油炸 29 条有效价分入 14 / 9 / 3 / 3;≤4 元带的 14 条非油炸中,小香厨一家占 11 条。品牌行据 <code>品牌价格汇总.csv</code>。工艺识别基于标题标注,「未标注」不能归于某一格;「—」表示样本里没有可判定的条目。关联:<a href="#big1-p1">大课一第一段</a>、<a href="#d101">D1-01</a>、<a href="#d203">D2-03</a>。</p>`}
+]
+},
+
+{
+kind: 'appx', id: 'appx-c', title: '附录 C · 常见问题', group: '附录',
+lead: '按四个阶段整理,每条对应一个实际会遇到的情况。',
+faq: [
+{g: '课程阶段', qs: [
+ ['AI 一上来不问我问题,直接开始分析了,正常吗?', '正常。Skill 规定「先复用上下文,能查的自行查」,只在会改变结论时才提问。你想让它多问,就在提示词后补一句「请以提问方式推进,每次只问一个会改变结论的问题」。'],
+ ['它说「资料库里没有」,是不是就是市场没有?', '不是。没查到、没权限、数据确实不存在,是三件事。看它的缺口清单有没有按三类分开写。'],
+ ['D1 我们几乎没产出东西,怎么办?', '先看「本组进度自检」:如果三问都能答上,产出就是够的。D1 的交付是一个决定 + 三个待答问题 + 任务卡,不是一份报告。'],
+ ['它给的结论没有原文,怎么办?', '不要接受。任何结论都要带原文、来源、编号;没有的让它补证据或标「待确认」。']
+]},
+{g: '调研与证据', qs: [
+ ['今晚 AI 会不会自己去找外部数据?', '会,但只在缺口会改变判断时,并且受任务卡里的「授权状态」约束。不希望的话,在任务卡里写明「今晚只复用资料库原件」。'],
+ ['词典打标的结果能直接用吗?', '不能。至少抽 5 条读原文;「辣」「贵」「量大」是典型误判(见附录 A)。'],
+ ['竞品样本每家只有 20 篇,够吗?', '不够代表全网声量,但够用来比卖点组合。把它当「哪个关键词下的首屏」,不当「品牌排行」。'],
+ ['什么时候要区分「资料库原件」和「外部补证」?', '始终区分。两者可信度不同、时效不同,报告里必须分开标注。']
+]},
+{g: '机会与提案', qs: [
+ ['康师傅在 ≤4 元 × 非油炸是 0 个,这是不是现成的机会?', '不是。同格有别人家的 14 个有效价 SKU,这一格有供给、但缺少用户在 4 元带要非油炸的原话。标「待验证」,进 V1.0 之后由 D2-04 三源交叉判断。'],
+ ['能不能写「多数人更喜欢吃」?', '不能。没有测过的表述不能承诺。改写成可测试的问题。'],
+ ['两条路(B0 / O1)哪条更好?', '先看本组工艺和供应链的真实约束;三条费用分开算;并行路径要把旧品转移和真正新增销量分开。'],
+ ['课堂的「预计成本」「预计销量」能用吗?', '只能在课堂内部讨论,标注「未经正式确认」。正式立项要换成业务方提供的真实数据。']
+]},
+{g: '保存与交付', qs: [
+ ['「已经保存好了」能信吗?', '要看它说的是哪一步:保存成功 / 按编号回读通过 / 看板已包含 / 浏览器已核对。四条分开报,不能互相代替。'],
+ ['候选清单 V1.0 / V2.0 / V3.0 是什么关系?', '同一个清单的三个版本:V1.0 是三源交叉后的全池,V2.0 加入商业与工艺条件后修订,V3.0 是质询后更新版。每一版都保留修改记录。'],
+ ['结营后 7 周陪练用什么?', '用 D2-08 带走的「成果导航」:拿 V3.0 回到真实工作中,每周回答一个「答不出」的问题,不学新东西。']
+]}
+],
+tips: {title: '五句话带走', items: ['任何数字,先问分母。', '任何结论,先问反例。', '任何「空白」,先查同一格的竞品。', '任何「在涨」,先查有没有时间序列。', '任何「多数人」,先查有没有测过。']}
+},
+
+{
+kind: 'appx', id: 'appx-d', title: '附录 D · 话术对照:措辞规范', group: '附录',
+lead: '这一版是研发中心内训,学员全是产品经理。措辞统一按两张表来:一张说哪些口语化、越过岗位分工的说法不再使用、换成什么;一张说同一个产品经理在哪些环节切换哪一侧视角。',
+blocks: [
+{t: 'D1 不用的说法,和改用的说法', html: `
+<table class="tbl say-table"><thead><tr><th>不再使用(问题在哪)</th><th>统一改成</th></tr></thead><tbody>
+<tr><td class="no">把「补充卖点」交给别人去做<br><span class="muted">把动作分给了别人</span></td><td class="yes">「你自己要从市场角度再想一层」</td></tr>
+<tr><td class="no">把研发侧和市场侧说成两个岗位<br><span class="muted">默认是两个岗位</span></td><td class="yes">「同一个产品经理要在研发和市场两侧切换视角」</td></tr>
+<tr><td class="no">按多个岗位拆成几份职责清单<br><span class="muted">分散了责任主体</span></td><td class="yes">只有产品经理一个角色,强调「你要具备的能力」</td></tr>
+<tr><td class="no">「你怎么证明自己」<br><span class="muted">口语化、带对抗感</span></td><td class="yes">「这条结论的证据是什么、反例是什么」</td></tr>
+<tr><td class="no">用夸张的动词形容调转结论<br><span class="muted">不庄重</span></td><td class="yes">「反常识 / 反认知 / 颠覆直觉」</td></tr>
+<tr><td class="no">「研发人员就是不行」<br><span class="muted">贬低学员出身</span></td><td class="yes">「研发侧是你们的本行,市场侧是这一轮要补的」</td></tr>
+<tr><td class="no">「这个点子太好了」<br><span class="muted">用感觉替代判断</span></td><td class="yes">「这个判断的证据强度 2 分,可做性 3 分」</td></tr>
+</tbody></table>`},
+{t: 'D2 产品经理的能力切换表', html: `
+<p>同一个产品经理,在每个环节都要确认自己站在哪一侧。这不是分工,是<b>视角切换</b>——「研发侧」是你能直接判断的,「市场侧」和「经营侧」是这一轮要刻意用的两副眼镜。</p>
+<table class="tbl"><thead><tr><th>环节</th><th>研发侧(本行)</th><th>市场侧(要补)</th><th>经营侧(要建立)</th></tr></thead><tbody>
+<tr><td>D1-01 品类全景</td><td>工艺、形态、成本结构</td><td>人群、场景</td><td>价格带分层</td></tr>
+<tr><td>D1-03 竞品格局</td><td>同一工艺路线里做得怎么样</td><td>卖点组合、正反原话</td><td>同一条价格带里谁占位</td></tr>
+<tr><td>D2-02 VOC 聚类</td><td>用户的痛点在工艺上是什么问题</td><td>原话的情绪、表面诉求</td><td>——</td></tr>
+<tr><td>D2-03 矩阵空白</td><td>这一格做不做得出来</td><td>这一格有没有人说</td><td>这一格值不值得做</td></tr>
+<tr><td>D2-04 三源交叉</td><td>工艺条件支持吗</td><td>用户原话指向吗</td><td>空白格有没有生意</td></tr>
+<tr><td>D2-06 商业回推</td><td>做不做得出来</td><td>消费者接受吗</td><td>划不划算</td></tr>
+<tr><td>D2-07 卖点</td><td>证据允许说到哪</td><td>用户听得懂吗</td><td>价格带撑不撑得起这个说法</td></tr>
+</tbody></table>
+<p class="muted">这张表放在手边:在每一个环节开头,读一遍「这一节你要用哪两副眼镜」。</p>`}
+]
+},
+
+{
+kind: 'raw', html: `<div class="tips"><h3>结营前,最后记住这一句</h3><p style="font-size:15.5px;margin:0">产品创新从战略层到组织层再到个人层,最后落在一张张写得清「证据、反例、缺口」的卡上。你手里那份手册,不是让你背的;它是让你从「研发人员」往「品类负责人」走的第一步。</p></div>`
+}
+);
+
+// x2 · 13 份产出物规范:名称 / 形态 / 样卡 / 用途 / 流转
+// 样卡用课堂数据包的真实数字写成(示范格式与判断方式,不是标准答案)。
+// 对象字段:name 名称 · form 形态 · owner 谁做 · look 样卡 HTML · legend 图例 · purpose 三块用途 · handoff 下一环用法 · flow 流转链
+window.DELIV = {
+
+d101: {
+name: '品类全景图谱', form: '三栏表:供给树 / 需求树 / 供需缺口', owner: '本组产品经理 · 每组 1 份',
+legend: [['#C8102E', '空白点:有供给、没需求原话 / 有需求、没供给']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>品类全景图谱</b><span>第 3 组 · 居家囤货 × 常备</span><span class="doc-tag">未经正式确认</span></div>
+<div class="doc-h">① 供给树(400 SKU 样本) ② 需求树(G1–G6 用户原话) ③ 供需缺口</div>
+<div class="doc-body"><table>
+<thead><tr><th style="width:28%">① 供给树:有什么</th><th style="width:28%">② 需求树:要什么</th><th>③ 供需缺口</th></tr></thead>
+<tbody>
+<tr><td><b>形态</b><br>袋装 184 · 桶装 95 · 盒装 22 · 杯装 21 · 碗装 20 · 未标注形态 58</td><td><b>G5 一人食与家庭囤货</b><br>37 篇 · 口味新鲜 16 · 方便/快手 12 · 囤货 8</td><td>囤货场景:袋装供给充足(184),需求原话集中(37 篇)→ <b>接上了</b></td></tr>
+<tr><td><b>工艺</b><br>非油炸 105 · 鲜熟/半干 24 · 未标注 271</td><td><b>G4 健康控卡</b><br>39 篇 · 健康 29 · 方便/快手 14</td><td>「4 元以下非油炸」:同格对手 14 个 SKU,康师傅 0 个 → <b>待确认</b></td></tr>
+<tr><td><b>价格带</b>(有效价 125)<br>≤4 元 53 · 4–6 元 43 · 6–9 元 13 · &gt;9 元 16</td><td><b>G2 学生宿舍</b><br>39 篇 · 方便/快手 23 · 口味新鲜 21</td><td>宿舍夜宵 × 6 元以上:有供给、有场景,原话薄 → <b>待确认</b></td></tr>
+<tr><td><b>地域风味</b><br>陕西 31 · 武汉热干面 25 · 北京 15 · 江浙沪 10</td><td><b>G6 地域与高端尝鲜</b><br>40 篇 · 口味新鲜 23 · 正宗/地域 8</td><td>地域风味的溢价能力:≥6 元带原话 &lt;5 条 → <b>缺</b></td></tr>
+</tbody></table>
+<p class="doc-micro">来源:<code>全部商品.csv</code>(400 条)、<code>G1–G6-用户笔记-原文.csv</code>(260 篇)、<code>品牌价格汇总.csv</code>。计数可按原文逐条复核;空白点的判断待 D1-03 起逐格核查。</p></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '确定本组三个半天在哪个「格子」上工作:哪个人群 × 哪个场景 × 哪个价格带 × 哪种工艺。它是后面 12 个环节的地图。'],
+['拦住什么错', '拦住「在自己熟悉的格子里找机会」。没有这张图,竞品比较、空白判断、机会卡都会缺一个坐标,最后所有结论都长在同一个惯常方向上。'],
+['沉淀什么资产', '一次扫描之后,这张图可以复用到任何同品类的新项目:换课题,只换「①②③」里打钩的格子。']
+],
+handoff: [
+'<b>D1-02 验证配置卡:</b>把图谱里最容易被反驳的 3 条主张(例如「康师傅有效价 35 个」「非油炸 105 个」「地域风味的是平价带」)作为回查对象,逐条定口径。',
+'<b>D1-03 竞品格局:</b>按图谱圈定「同格商品」的范围——只比较落在本组格子和邻格里的品牌,不做群体声量比较。',
+'<b>D2-03 矩阵空白:</b>把「③ 供需缺口」的空白点直接带入,按结构 / 变化 / 未覆盖三类重新判一次。'
+],
+flow: ['D1-01', '品类全景图谱', 'D1-02 回查口径', 'D1-03 圈定同格', 'D2-03 空白三类']
+},
+
+d102: {
+name: '本题验证配置卡', form: '一页卡:资料资格 + 统计口径 + 引文规则 + 分歧处理(+ 回查记录)', owner: '本组产品经理 · 每组 1 份,全班共享一份最低纪律',
+legend: [['#C8102E', '回查记录:拿配置卡回查出问题的图谱条目']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>本题验证配置卡</b><span>本组:居家囤货 × 常备 · 生效至结营</span><span class="doc-tag">全场通用最低纪律附后</span></div>
+<div class="doc-h">五块内容 · 缺一不可</div>
+<div class="doc-body">
+<div class="rulerow"><b>资料资格</b><span>只认百克价非空的有效价(125 / 400);社媒只认能读到原文的笔记;竞品社媒按 20 篇 / 品牌的样本对待,不当声量。</span></div>
+<div class="rulerow"><b>统计口径</b><span>比例必须写分母;中位数用均值中位数;价格双报(125 条 / 剔除整箱 71 条);跨平台分开报(本批有效价京东 123、淘宝 2)。</span></div>
+<div class="rulerow"><b>引文口径</b><span>原文带笔记标题或 ID;词典打标词(辣、贵、量大)必须抽读原文,至少 5 条;「AI 推断」与「原件证据」分开写。</span></div>
+<div class="rulerow"><b>模型分工</b><span>证据方向由 AI 给;「值不值得做」「这一格是不是我们的」由本组拍板。</span></div>
+<div class="rulerow"><b>分歧处理</b><span>两种口径不一致 → 都列出来;都列不出证据 → 标「待确认」;三者分开:没查到 / 没权限 / 确实不存在。</span></div>
+<div class="rulerow mark"><b>回查记录</b><span>图谱主张「≤4 元是最大价格带,康师傅在这一带 22 个」→ 换 71 条口径后康师傅只剩 7 个 → <span class="warn">降级</span>为「整箱口径下成立,单份口径待确认」。</span></div>
+</div></div></div>`,
+purpose: [
+['支持什么决定', '决定「什么算证据」。D1 之后每一张卡上的结论,都会按这张卡来判断:能成立、要降级、还是标待确认。'],
+['拦住什么错', '拦住「换一个口径结论就反转」和「词典打标当用户态度」这两类错——附录 A 的第一和第四个反常识。'],
+['沉淀什么资产', '这张卡是整组的研究纪律,结营后遇到新项目可以直接复用;全班合并后的「最低纪律」可以成为产品中心的通用规范。']
+],
+handoff: [
+'<b>D1-03:</b>竞品比较先按本卡剔除兜售帖、活动帖与重复内容,再比较卖点组合;宁可少比,不可错比。',
+'<b>D1-04:</b>每一条假设的「反证路径」,就是按本卡的口径去找能推翻它的证据。',
+'<b>D2 全段:</b>V1.0、V2.0、V3.0 的每一次升级都要过一遍这张卡;卡片有冲突时由本组业务判断收口。'
+],
+flow: ['D1-02', '验证配置卡', 'D1-03 竞品比较', 'D1-04 反证路径', 'D2-01 验收', '全过程']
+},
+
+d103: {
+name: '竞品图谱 + 待验证痛点假设', form: '矩阵表(卖点组合)+ 假设清单(H1–H3)', owner: '本组产品经理 · 每组 1 矩阵 + 2–3 条假设',
+legend: [['#C8102E', 'H 假设行:可证伪的怀疑']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>竞品图谱 + 待验证痛点假设</b><span>本组:居家囤货 × 常备 · 同格竞品</span><span class="doc-tag">宣称 / 回应 / 推断 分开</span></div>
+<div class="doc-h">一、卖点组合矩阵(示例:4 元以下的非油炸 / 袋装 / 拌面格)</div>
+<div class="doc-body"><table>
+<thead><tr><th>品牌 · 商品</th><th>百克价</th><th>卖点组合</th><th>正反原话</th><th>我们判断</th></tr></thead>
+<tbody>
+<tr><td>康师傅 · 经典红烧牛肉面五连包</td><td class="r">整箱 / 五连包</td><td>【宣称】经典 · 红烧 · 大食袋</td><td>G1「晚上九点才吃饭,我只点半碗」</td><td>【推断】口味信任强,健康诉求无回应</td></tr>
+<tr><td>今麦郎 · 拉面范(安徽板面)</td><td class="r">3.01</td><td>【宣称】非油炸 · 宽面 · 桶装</td><td>G2「能囤在宿舍当饭吃的速食食品」</td><td>【推断】低价非油炸已有供给,但卖点集中在“非油炸”功能词</td></tr>
+<tr><td>小香厨(散牌)· 兰州牛肉面</td><td class="r">1.56–3.99</td><td>【宣称】地域 · 低价 · 多种口味</td><td>—</td><td>【推断】区域低价竞争,不构成心智</td></tr>
+</tbody></table>
+<p class="doc-micro">竞品社媒:康师傅 20 条(关键词「地域 速食面」)、今麦郎 20 条,1–2 个关键词,不作声量比较。</p>
+<div class="doc-h" style="margin-top:6px">二、待验证痛点假设</div>
+<table style="margin-top:6px">
+<thead><tr><th>编号</th><th>可证伪的假设</th><th>凭什么怀疑</th><th>什么情况推翻</th></tr></thead>
+<tbody>
+<tr class="mark"><td><b>H1</b></td><td>在 4 元以下价格带的非油炸用户,愿意为“非油炸”多付 1 元</td><td>G4 健康 29 / 39 篇;≤4 元 × 非油炸同格对手 14 个</td><td>≥10 条原话明确说“非油炸也得好吃才值 / 太贵了不会买”</td></tr>
+<tr><td><b>H2</b></td><td>囤货用户最在意的不是口味,而是“拆包后放得住”</td><td>G5 囤货 8 篇(37 篇中)</td><td>拆包/存放相关原话在 G5 中 &lt; 3 条</td></tr>
+<tr><td><b>H3</b></td><td>同一款面,学生宿舍更在意“方便”,加班族更在意“吃得少一点”</td><td>G1「只点半碗」;G2 方便/快手 23 / 39 篇</td><td>两组的场景化原话占比无显著差异</td></tr>
+</tbody></table></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「本组最怀疑什么」。竞品图谱给出的是「谁在卖什么」,假设清单给出的是「我们猜哪里没被满足」——下一步要拿证据去验证。'],
+['拦住什么错', '拦住「拿总赞排品牌声量」和「假设无法被证伪」。用样本量换结论,用可证伪换安慰。'],
+['沉淀什么资产', '卖点组合矩阵可以按品类复用;三类明确(宣称 / 回应 / 推断)的写法,是可迁移的判断习惯。']
+],
+handoff: [
+'<b>D1-04 增强 AI 自驱任务卡:</b>每条假设直接变成任务卡一行,补上支持路径、反证路径、停止条件。',
+'<b>D1-N 调研:</b>按假设编号执行,不再漫游搜索。',
+'<b>D2-04 三源交叉:</b>H1–H3 在早上的证据结论,是机会卡「反例 / 还缺什么」两栏的起点。'
+],
+flow: ['D1-03', '竞品图谱 + 假设', 'D1-04 任务卡', 'D1-N 验证', 'D2-04 反例']
+},
+
+d104: {
+name: '增强 AI 自驱任务卡', form: '一页卡:假设键 + 支持路径 + 反证路径 + 停止条件', owner: '本组产品经理 + 助教归档',
+legend: [['#C8102E', '停 止 条 件:最容易被写糊、也最决定成败的一栏']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>增强 AI 自驱任务卡</b><span>本组决定:4 元带要不要做非油炸</span><span class="doc-tag">今晚执行范围:仅资料库 + 授权外部补证</span></div>
+<div class="doc-h">一页卡 · 每条主线假设一行</div>
+<div class="doc-body"><table>
+<thead><tr><th>假设键</th><th>支持路径</th><th>反证路径</th><th>停止条件(程序可判定)</th></tr></thead>
+<tbody>
+<tr><td><b>H1</b><br>≤4 元非油炸用户愿多付 1 元</td><td>G4 全部 39 篇中,非油炸 + 价格相关原话</td><td>G4 / G2 / G5 中“非油炸但…”的转折句</td><td class="warn">找到 ≥10 条反证 或 读完 G4 全部 39 篇</td></tr>
+<tr><td><b>H2</b><br>囤货在意拆包存放</td><td>G5 全部 37 篇命中“囤 / 放 / 存”</td><td>G5 中“囤”只为“便宜”的原话</td><td class="warn">读完全部命中篇目,无新增</td></tr>
+<tr><td><b>H3</b><br>两组用户关注点不同</td><td>G1 与 G2 场景化原话对照表</td><td>同一条原话同时出现在两组</td><td class="warn">两侧各 ≥10 条对照后停止</td></tr>
+</tbody></table>
+<p class="doc-micro">签字:本组已确认 ☑ 配置卡编号:CFG-03 授权:外部补证 □(未授权,今晚只跑资料库) 备查:H4、H5 暂不执行</p></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定今晚 AI 跑什么、跑多久、什么时候停。它是机器能读懂的「研究指令」,不是给学员自己看的笔记。'],
+['拦住什么错', '拦住三种失败:只写支持不写反证(AI 形成偏见);停止条件不可执行(AI 不停);授权不清(AI 乱抓或不敢抓)。'],
+['沉淀什么资产', '这张卡的模板,是研究外包给 AI 时最核心的接口。一个任务卡格式,可以套到任何新项目上。']
+],
+handoff: [
+'<b>D1-N 执行:</b>AI 只执行卡内假设,按停止条件结束,缺口按三类分报。',
+'<b>D2-01 验收:</b>验收正是按这张卡逐项核对——回应率对不对、原件有没有、停止条件有没有被尊重。',
+'<b>D2-05 排序:</b>「哪条假设被推翻」直接决定哪些机会被踢出或降级。'
+],
+flow: ['D1-04', '自驱任务卡', 'D1-N 夜间执行', 'D2-01 验收']
+},
+
+d1n: {
+name: '调研战报 + 缺口清单', form: '报告(按假设键一页)+ 缺口表(三类)', owner: 'AI 自动生成 · 明早本组验收',
+legend: [['#C8102E', '「不支持 / 未回应」在战报里比「支持」更值钱']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>调研战报 + 缺口清单</b><span>D1-N · 按任务卡 CFG-03 执行</span><span class="doc-tag">AI 初稿 · 未经人工验收</span></div>
+<div class="doc-h">战报 · 按假设键</div>
+<div class="doc-body"><table>
+<thead><tr><th>假设键</th><th>结论</th><th>证据(带原件)</th><th>缺口</th><th>对下一步的影响</th></tr></thead>
+<tbody>
+<tr><td>H1</td><td><b>部分支持</b></td><td>G4 健康 29 / 39 篇;非油炸原话 9 条,其中 7 条读不出态度</td><td>价格相关原话 &lt;3 条</td><td>V1.0 中<strong>不能</strong>写「愿多付 1 元」</td></tr>
+<tr class="mark"><td>H2</td><td><b>不支持</b></td><td>G5 命中「囤」8 篇,全部指向「便宜 / 一次买够」,无一条讲存放</td><td>—</td><td>「拆包存放」降为线索</td></tr>
+<tr><td>H3</td><td><b>支持(弱)</b></td><td>G1「只点半碗」1 条;G2 方便/快手 23 / 39 篇</td><td>G2 缺同类原话</td><td>可作为 D2-02 的初始聚类</td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">缺口清单 · 三类分开</div>
+<table style="margin-top:6px">
+<thead><tr><th>没查到</th><th>没权限</th><th>数据确实不存在</th></tr></thead>
+<tbody><tr><td>≤4 元非油炸商品评论(标题有、评论没采到)</td><td>山姆 / 盒马等 To B 渠道</td><td>销量、复购、满意度(采集字段中无)</td></tr></tbody></table>
+<p class="doc-micro">停止条件遵守情况:H1 停在「读完 G4 全部 39 篇」;H2 停在「原文无新增」;H3 停在「两侧各 ≥10 条」。</p></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「哪些假设留下、哪些降级、哪些扔掉」。它把昨晚的证据按假设键整理好,今天早上直接进入验收,而不是重新读一堆散乱的搜索记录。'],
+['拦住什么错', '拦住「AI 说支持就支持」。战报把不支持、未回应、没查到三类写在同一页,很难被「看起来很有收获」掩盖。'],
+['沉淀什么资产', '按假设键归档的战报,是研究过程的可追溯记录。结营后补证,直接在这份记录上续写,不用重新开始。']
+],
+handoff: [
+'<b>D2-01 验收:</b>抽样回读原件,核验「部分支持 / 支持」是否成立,补齐分母。',
+'<b>D2-02 聚类:</b>VOC 预聚类作为四张表的起点,但要重新抽读、重新分层。',
+'<b>D2-04 机会卡:</b>「不支持」的 H2 是「反例」栏的最好素材——它说明为什么一个直觉不成立。'
+],
+flow: ['D1-N 输出', '战报 + 缺口', 'D2-01 验收', 'D2-02 预聚类起点']
+},
+
+d201: {
+name: '战报验收记录', form: '检查表:假设回应率 + 原件覆盖 + 分母口径', owner: '本组产品经理 · 每组 1 份',
+legend: [['#C8102E', '标注「待补证」的条目不进可用资料集合']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>战报验收记录</b><span>D2-01 · 本组 3 条假设</span><span class="doc-tag">可用 / 待补证 / 降级</span></div>
+<div class="doc-h">三项检查 · 以假设为单位</div>
+<div class="doc-body"><table>
+<thead><tr><th>假设</th><th>假设回应率</th><th>原件覆盖</th><th>分母口径</th><th>判定</th></tr></thead>
+<tbody>
+<tr><td>H1</td><td>部分支持</td><td class="warn">3 / 9 条原话可回读</td><td>缺</td><td><span class="warn">降为假设</span></td></tr>
+<tr><td>H2</td><td>不支持</td><td class="good">8 / 8 可回读</td><td>写「37 篇中 8 篇」</td><td><span class="good">可用</span></td></tr>
+<tr><td>H3</td><td>支持(弱)</td><td>6 / 10 可回读</td><td class="warn">未写分母</td><td><span class="warn">补分母后可用</span></td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">可用资料集合(能回读的原件)</div>
+<div class="doc-body" style="padding:6px 12px"><div class="doc-grid2">
+<div class="doc-box"><h5>G2 · 学生宿舍(39 篇)</h5><ul><li>#G2-07 方便/快手原话 ×3</li><li>#G2-12 「少一点」原话</li></ul></div>
+<div class="doc-box"><h5>G5 · 一人食囤货(37 篇)</h5><ul><li>「囤」8 篇:全部指向便宜 / 买够</li><li>#G5-03 「五连包刚刚好」</li></ul></div>
+</div></div></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「能用的资料是什么」。只有通过验收的原件,才能进入 D2-02 的聚类;不合格的,降级为假设、待补证,或者直接删掉。'],
+['拦住什么错', '拦住「好看的结论」。三项检查像门口的门卫:没有原件的、没有分母的、AI 推断冒充证据的,全部拦在门外。'],
+['沉淀什么资产', '验收记录本身就是「引用规范」的执行样本,可以拿去做新人培训。']
+],
+handoff: [
+'<b>D2-02 聚类:</b>接收「可用资料集合」,逐条编号。',
+'<b>D2-04 机会卡:</b>「降级为假设」的条目,进「还缺什么」栏。',
+'<b>D2-08 提案:</b>验收记录里的「待补证」清单,就是提案最后「下一步行动」的来源之一。'
+],
+flow: ['D2-01', '战报验收记录', 'D2-02 可用资料', 'D2-08 待补证']
+},
+
+d202: {
+name: '聚类表 + 痛点库 + KANO 表 + 人群 × 场景矩阵', form: '四张表:分层编码 / 痛点 / 需求类型 / 矩阵', owner: '本组产品经理 · 每组 1 套四表',
+legend: [['#C8102E', 'K A N O 类型标注「频次先验」:不是问卷结果']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>VOC 四张表</b><span>本组:六大人群笔记本 260 篇</span><span class="doc-tag">每一格带笔记 ID</span></div>
+<div class="doc-h">① 聚类表(人群 → 场景 → JTBD → 痛点)</div>
+<div class="doc-body"><table>
+<thead><tr><th>原话</th><th>人群</th><th>场景</th><th>JTBD</th><th>痛点</th></tr></thead>
+<tbody>
+<tr><td>「晚上九点才吃饭,我只点半碗」(G1)</td><td>G1 加班族</td><td>晚上九点半 · 加班餐</td><td>想在没胃口时也能吃一点、不折腾</td><td>夜里胃口小、怕重辣重油</td></tr>
+<tr><td>「晚上九点,办公室终于安静了,我才发现晚饭又拖过去了」(G1)</td><td>G1 加班族</td><td>晚上九点 · 办公室</td><td>想把晚饭补上</td><td>晚饭一再往后拖</td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">② 痛点库</div>
+<table style="margin-top:6px">
+<thead><tr><th>痛点词</th><th>频次</th><th>态度分布</th><th>代表原话</th></tr></thead>
+<tbody>
+<tr class="mark"><td>辣</td><td>39</td><td>正 29 · 读不出 9 · 负 1</td><td>G1「避免重辣重油」是唯一否定</td></tr>
+<tr><td>贵</td><td>11</td><td>「贵州」误判 9 条</td><td>G6「贵州到底想怎样」</td></tr>
+</tbody></table>
+<div class="doc-grid2" style="margin-top:8px">
+<div><div class="doc-h">③ KANO 表</div><table style="margin-top:4px"><thead><tr><th>需求</th><th>类型</th><th>说明</th></tr></thead><tbody><tr><td>方便 / 快手</td><td>基本型</td><td>品类前提</td></tr><tr><td>非油炸 / 少油</td><td>期望型(待确认)</td><td>频次先验</td></tr></tbody></table></div>
+<div><div class="doc-h">④ 人群 × 场景矩阵</div><table style="margin-top:4px"><thead><tr><th></th><th>宿舍夜宵</th><th>加班餐</th></tr></thead><tbody><tr><td><b>G2</b></td><td>23 篇</td><td>5 篇</td></tr><tr><td><b>G1</b></td><td>0 篇</td><td>14 篇</td></tr></tbody></table></div>
+</div></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「用户到底在说什么」。聚类决定哪些原话是同一件事,痛点库决定哪些是真痛点,KANO 表决定痛点的性质,矩阵决定它在哪个人群、在哪个场景。'],
+['拦住什么错', '拦住「辣 39 次 = 用户嫌辣」这种被打标带偏的判断,也拦住四层混杂导致的「一句话当整个需求」。'],
+['沉淀什么资产', '四张表是下一次选题的「用户资产库」:未来任何一个新品,先从这里取,再补新证据。']
+],
+handoff: [
+'<b>D2-03:</b>矩阵的每一格直接进入「需求矩阵」,与供给矩阵交叉。',
+'<b>D2-04:</b>机会卡的「用户原声」一栏,要从痛点库里挑,不从搜索结果里现抓。',
+'<b>D2-07:</b>卖点的「用户语言」,直接从原话里取,不用 AI 另编。'
+],
+flow: ['D2-02', '四张表', 'D2-03 需求矩阵', 'D2-04 用户原声', 'D2-07 用户语言']
+},
+
+d203: {
+name: '产品机会及指标初表', form: '机会 × 指标表:空白格 / 类别 / 供给证据 / 需求证据 / 指标', owner: '本组产品经理 · 每组 1 张',
+legend: [['#C8102E', '「未覆盖」必须有同格竞品说明,否则不算空白']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>产品机会及指标初表</b><span>本组:四维交叉</span><span class="doc-tag">结构 / 变化 / 未覆盖 分列</span></div>
+<div class="doc-h">一行一个机会 · 五列</div>
+<div class="doc-body"><table>
+<thead><tr><th>空白格<br><span class="doc-micro">人群 × 场景 × 价格 × 工艺</span></th><th>类别</th><th>供给证据</th><th>需求证据</th><th>需要验证的指标</th></tr></thead>
+<tbody>
+<tr><td>健康控卡 × 夜宵 × ≤4 元 × 非油炸</td><td><b>未覆盖</b><br>(康师傅 0 个,同格对手 14 个)</td><td>非油炸 105 个 SKU,29 个有有效价,其中 ≤4 元带 14 个</td><td>G4 健康 29 / 39 篇;≤4 元带价格原话 &lt;3 条</td><td>① ≤4 元带非油炸的真实单价水平;② 价格敏感性原话</td></tr>
+<tr><td>学生宿舍 × 夜宵 × 4–6 元 × 拌面</td><td><b>结构</b></td><td>拌面标题词 255 个(含营销词)</td><td>G2 方便/快手 23 / 39 篇</td><td>① 拌面搜索里真实形态的占比</td></tr>
+<tr><td>地域风味 × 6 元以上</td><td><b>未覆盖(待查同格)</b></td><td>陕西 11 个有效价,中位 3.38</td><td>G6 正宗/地域 8 / 40 篇</td><td>① ≥6 元地域风味商品的真实 SKU 数</td></tr>
+<tr><td>—</td><td class="warn">变化(本次不验证)</td><td>—</td><td>—</td><td>需要同一关键词的两次快照</td></tr>
+</tbody></table>
+<p class="doc-micro">判定原则:有原话、没供给 ≠ 机会;有供给、没原话 ≠ 需求;两者都标「待验证」,交 D2-04。</p></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「哪几个空白格值得进入三源交叉」。它把需求与供给放到同一张表上,并为每一格写明验证指标。'],
+['拦住什么错', '拦住把结构、变化、未覆盖混为一谈——尤其是「在涨」和「空白」这两个最容易被误读的结论。'],
+['沉淀什么资产', '四维交叉表是品类结构资产:每季度更新一次,就能看到自己家的覆盖是否在扩。']
+],
+handoff: [
+'<b>D2-04:</b>选 2 个空白格进入三源交叉,并带上对应指标。',
+'<b>D2-05:</b>「需要验证的指标」直接作为排序时的依据之一。',
+'<b>D2-06:</b>「成本带能否达成」的指标,进入回推表。'
+],
+flow: ['D2-03', '机会及指标表', 'D2-04 选 2 格', 'D2-05 打分', 'D2-06 回推']
+},
+
+d204: {
+name: '候选机会清单 V1.0', form: '机会卡,每张 6 字段:结论 / 三源证据 / 反例 / 缺什么 / 下一步 / 工艺注释', owner: '本组产品经理 · 每组 2–3 张',
+legend: [['#C8102E', '一句话结论必须能被推翻;工艺注释只由研发侧写']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>机会卡 #03</b><span>候选机会清单 V1.0 · 证据强度 2 / 3</span><span class="doc-tag">候选(三源齐全但薄)</span></div>
+<div class="doc-h">6 字段</div>
+<div class="doc-body">
+<dl class="doc-kv">
+<dt>一句话结论</dt><dd><b>4 元以下非油炸汤面可能是个空缺;但「愿意多付」尚未被证实。</b></dd>
+<dt>三源证据</dt><dd>· 商品:电商 125 个有效价里 ≤4 元占 42.4%;非油炸有效价 29 个里 ≤4 元带 14 个<br>· 用户:G4 健康需求 29 / 39 篇;价格相关原话 &lt;3 条<br>· 工艺:非油炸热风三段控温 80–90℃ / 90–100℃ / 70–80℃,含水 8–12%(待工艺确认)</dd>
+<dt>反例</dt><dd>非油炸在 4 元以下成本可能做不出;同格 14 个对手多是低价散牌,说明这一格可能以「低价」取胜而非「非油炸」。</dd>
+<dt>还缺什么</dt><dd>待确认:≤4 元带非油炸的真实单包价、用户价格敏感性原话。</dd>
+<dt>下一步验证</dt><dd>先补:≤4 元带同类商品评论 10 条,验证价格敏感。</dd>
+<dt>工艺注释</dt><dd><b>研发侧手写:</b>换线成本取决于现有产线是否能切热风干燥段;若走挤压熟化,单机投入低,但复水口感待测。</dd>
+</dl>
+</div></div></div>`,
+purpose: [
+['支持什么决定', '决定「哪几个方向进入下午」。每张卡要么达成三源交叉,要么写明缺的是什么,不能含混。'],
+['拦住什么错', '拦住「只有一条线就写机会」和「把 AI 的工艺判断当自己的判断」。工艺注释一栏逼着研发侧亲手写。'],
+['沉淀什么资产', '机会卡是后续整个产品流程的通用母卡;V2.0、V3.0 都是在它上面迭代的版本。']
+],
+handoff: [
+'<b>D2-05:</b>每张卡先打三个维度的分,再定主攻 1–2 个。',
+'<b>D2-06:</b>主攻卡进回推,单包价与成本两条缺一不可。',
+'<b>D2-08:</b>全案里的机会部分,直接引用机会卡的结论与你自己的工艺注释。'
+],
+flow: ['D2-04', '候选清单 V1.0', 'D2-05 排序', 'D2-06 回推 → V2.0', 'D2-08 → V3.0']
+},
+
+d205: {
+name: '优先级机会清单 + 未知项单列', form: '排序表(三维分值 + 依据)+ 未知项表', owner: '本组产品经理 · 每组 1 张排序表 + 1 张未知项表',
+legend: [['#C8102E', '任何一维 1 分的机会不得排进前三']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>优先级机会清单</b><span>三维:证据强度 × 可做性 × 商业价值</span><span class="doc-tag">每题注明:课堂证据 / 本组经验</span></div>
+<div class="doc-h">排序表 · 1–3 分</div>
+<div class="doc-body"><table>
+<thead><tr><th>机会</th><th>证据强度</th><th>可做性</th><th>商业价值</th><th>依据一句话</th><th>排序</th></tr></thead>
+<tbody>
+<tr><td>#03 ≤4 元非油炸汤面</td><td class="c"><span class="score s2">2</span></td><td class="c"><span class="score s1">1</span></td><td class="c"><span class="score s2">2</span></td><td>三源薄;需改线(经验);≤4 元带大但毛利薄</td><td class="down">第 3</td></tr>
+<tr><td>#05 6–9 元地域风味拌面</td><td class="c"><span class="score s2">2</span></td><td class="c"><span class="score s3">3</span></td><td class="c"><span class="score s3">3</span></td><td>现有线可做;6–9 元 13 个有效价;地域原话 8 / 40</td><td class="up">第 1</td></tr>
+<tr><td>#02 宿舍夜宵小包</td><td class="c"><span class="score s3">3</span></td><td class="c"><span class="score s3">3</span></td><td class="c"><span class="score s2">2</span></td><td>G2 方便/快手 23 / 39;包材 + 小克重</td><td class="up">第 2</td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">未知项表 · 不是低分项</div>
+<table style="margin-top:6px">
+<thead><tr><th>机会</th><th>缺什么数据</th><th>怎么补</th><th>本次能补吗</th></tr></thead>
+<tbody><tr class="mark"><td>#03</td><td>≤4 元带非油炸用户的支付意愿</td><td>概念测试 / 价格测试</td><td>本次不补,随 V3.0 带走</td></tr></tbody></table></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「先做哪个、放哪个,以及哪个根本做不了」。三个维度、一个硬性规则,让排序有据可依。'],
+['拦住什么错', '拦住「凭感觉,「我觉得」的排序」;也拦住把「不知道」硬写成「不好」。'],
+['沉淀什么资产', '三维打分表可以复用;未知项表把它变成一个活的待验证清单。']
+],
+handoff: [
+'<b>D2-06:</b>主攻机会进回推表,其余机会留在清单里备查。',
+'<b>D2-07:</b>价值主张只服务主攻机会,避免一个卖点服务多个机会。',
+'<b>D2-08:</b>排序依据直接进入提案结论页「为什么选这个」。'
+],
+flow: ['D2-05', '优先级清单', 'D2-06 主攻机会', 'D2-08 为什么选它']
+},
+
+d206: {
+name: '回推表 + 候选机会清单 V2.0', form: '成本表(B0 / O1 · 三条费用)+ 更新版机会卡', owner: '本组产品经理 · 研发侧主笔',
+legend: [['#C8102E', 'V 2 . 0 新增栏:成本区间 / 价格带 / 两条路 / 合规']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>回推表 · 主攻机会 #05</b><span>6–9 元地域风味拌面</span><span class="doc-tag">课堂估算 · 待内部确认</span></div>
+<div class="doc-h">两条路 · 三条费用(元/千包,课堂估算)</div>
+<div class="doc-body"><table>
+<thead><tr><th>口径</th><th>B0 现状(现有配比)</th><th>O1 方案(地域风味)</th><th>来源</th></tr></thead>
+<tbody>
+<tr><td>代工价(袋装)</td><td>2.1–3.2 / 袋</td><td>2.1–3.2 / 袋</td><td>知识库 · 2026-10-29 1688 询价</td></tr>
+<tr><td>一次费用</td><td>—</td><td>配方开发 + 感官测试</td><td class="warn">本组经验值</td></tr>
+<tr><td>资本投入</td><td>0</td><td>改线(无新增)</td><td class="warn">待内部确认</td></tr>
+<tr><td>营运资金</td><td>—</td><td>包材 / 新品铺货</td><td class="warn">待确认</td></tr>
+<tr><td>合规</td><td>现有品类标准覆盖</td><td>GB 17400-2015(水分 ≤10% / 酸价 ≤1.8 / 过氧化值 ≤0.25);GB 2760-2024 添加剂</td><td>标准正文</td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">V2.0 机会卡新增栏</div>
+<div class="doc-body" style="padding:6px 12px"><div class="doc-box"><ul>
+<li><b>成本区间:</b>课堂估算 —— 视觉设计上袋装成本结构中,面饼 34–38%、调料 24–30%、包材 12–13%</li>
+<li><b>目标价格带:</b>6–9 元 / 100g,对应 B2 数据中 13 个有效价</li>
+<li><b>两条路:</b>B0 改配方 vs O1 全新地域配方,B0 更省、O1 更差异</li>
+<li><b>合规:</b>配料合规通过,宣称词全部走中性描述</li>
+</ul></div></div></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「做起来要花多少、划不划算」。它把机会从「值得做」推进到「值得立项或进一步论证」。'],
+['拦住什么错', '拦住「只谈成本不谈路线」和「用不同收入假设比较两条路」。三条费用拆开之后,含糊就很难蒙混了。'],
+['沉淀什么资产', '回推表的框架是成本判断的模板;V2.0 机会卡的增量字段,可以直接套进产品立项报告。']
+],
+handoff: [
+'<b>D2-07:</b>卖点表达要跟价格带、成本带匹配——6 元的卖点不能按 3 元的成本说。',
+'<b>D2-08:</b>回推表的成本与合规,进提案的「风险」部分。',
+'<b>结营后:</b>「待确认」项需要拿到内部真实数据后才能正式立项。'
+],
+flow: ['D2-06', '回推表 + V2.0', 'D2-07 卖点匹配', 'D2-08 风险页']
+},
+
+d207: {
+name: '价值主张卡 + 卖点清单', form: '一页卡(主张 + 收益 + 证据 + 边界)+ 卖点表(多版本)', owner: '本组产品经理 · 每组 1 卡 + 1 清单',
+legend: [['#C8102E', '「不能说的话」也进清单,防止越界']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>价值主张卡 · #05</b><span>主攻:6–9 元地域风味拌面</span><span class="doc-tag">主推版</span></div>
+<div class="doc-h">一句主张 · 三条收益 · 三条证据 · 证据边界</div>
+<div class="doc-body">
+<dl class="doc-kv">
+<dt>主主张</dt><dd><b>「一碗像家里做的面。」</b></dd>
+<dt>三条收益</dt><dd>① 面宽有嚼劲 · ② 地域风味(如陕西油泼)· ③ 不用等很久</dd>
+<dt>三条证据</dt><dd>① 工艺:复合压延 6–8 道、终轧 1.0–1.2mm(技术背书)<br>② 商品事实:6–9 元带 13 个有效价,竞品较少<br>③ 用户原话:G6「口味新鲜」23 / 40 篇</dd>
+<dt>能说</dt><dd>「宽面」「地道风味」「泡 5 分钟」——带参数或可验证信息</dd>
+<dt>不能说</dt><dd>「健康」「无添加」「比 X 好吃」(无对照测评或无合规依据)</dd>
+</dl>
+<div class="doc-h" style="margin-top:6px">卖点清单 · 按渠道</div>
+<table style="margin-top:6px">
+<thead><tr><th>渠道 / 人群</th><th>版本</th><th>说明</th></tr></thead>
+<tbody>
+<tr><td>全家便利店 · 上班族</td><td>「加班回家,煮个面像点了一份外卖。」</td><td>便利店需要“快 + 情绪”</td></tr>
+<tr class="mark"><td>线上 · 学生宿舍</td><td>「深夜宿舍一碗油泼面,不用开火。」</td><td>宿舍场景 + 不用开火</td></tr>
+<tr><td colspan="3" class="muted">已删版本:「健康好面」——无合规依据;「比泡面更好吃」——无对照测评</td></tr>
+</tbody></table></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「用户为什么买它」。这是研发语言向市场语言的最后一次翻译:参数变成感知,工艺变成故事,同时不越过证据边界。'],
+['拦住什么错', '拦住「研发人员讲故事的老毛病」——把参数当卖点,或者为了好听越界。边界写在同一页上,越过就看见了。'],
+['沉淀什么资产', '价值主张卡的格式可以复用到每一款新品;多版本卖点清单可以直接提供给渠道与品牌团队共创。']
+],
+handoff: [
+'<b>D2-08:</b>提案第一页的一句话,用的就是价值主张卡的主主张。',
+'<b>展演:</b>每组要能读出主主张,让别组复述——复述差异本身就是测试。',
+'<b>结营后:</b>卖点清单进入与品牌方的共创,不需要重新从零开始写。'
+],
+flow: ['D2-07', '价值主张卡 + 卖点', 'D2-08 提案首句', '展演复述', '品牌共创']
+},
+
+d208: {
+name: '概念提案 + 候选清单 V3.0 + 成果导航', form: '提案文档(一句话 / 一页 / 全案)+ 更新版机会卡 + 导航页', owner: '本组产品经理 · 每组 1 套',
+legend: [['#C8102E', '质询记录里「答不出」的问题必须留在 V 3 . 0 里,作为下一步']],
+look: `<div class="doc-scroll"><div class="doc">
+<div class="doc-bar"><b>概念提案 · 第 3 组</b><span>6–9 元地域风味拌面</span><span class="doc-tag">课堂成果 · 未经正式确认</span></div>
+<div class="doc-h">提案首屏:结论先讲</div>
+<div class="doc-body">
+<p class="doc-title">做什么:做一款 6–9 元带的陕西风味拌面,现有产线可做。<br>为什么现在:6–9 元带只有 13 个有效价,竞品集中度低。<br>要什么资源:配方开发 + 一轮概念测试。</p>
+<div class="doc-grid2">
+<div class="doc-box"><h5>决策圈可能问</h5><ul><li>这条带的用户接受度测过吗?<span class="warn">答不出</span></li><li>属于三类创新中的哪一类?→ 长尾溢价拓利</li></ul></div>
+<div class="doc-box"><h5>协同圈可能问</h5><ul><li>现有产线改不改?→ 不改</li><li>成本能否落在 6–9 元?→ 课堂估算,待确认</li></ul></div>
+</div>
+<div class="doc-h" style="margin-top:6px">候选清单 V3.0 · 质询后修改记录</div>
+<table style="margin-top:6px"><thead><tr><th>字段</th><th>V2.0</th><th>V3.0 修改</th><th>理由</th></tr></thead><tbody>
+<tr><td>一句话结论</td><td>空缺需填补</td><td>同口味“陕西油泼 xx”已有 1 个 SKU</td><td>质询时邻组指出</td></tr>
+<tr><td>反例</td><td>价格带未被占满</td><td>同格对手集中度高,可能挤压新品</td><td>决策圈问题的回答</td></tr>
+</tbody></table>
+<div class="doc-h" style="margin-top:6px">成果导航</div>
+<table style="margin-top:6px"><thead><tr><th>产出物</th><th>位置</th><th>结营后第一周先看哪一份</th></tr></thead><tbody><tr><td>V3.0 + 提案</td><td>本组项目目录 / D2-08</td><td class="mark"><b>先看 V3.0「答不出」的问题</b></td></tr></tbody></table></div>
+</div></div>`,
+purpose: [
+['支持什么决定', '决定「这个产品能不能进入下一步」——展演中答得出来的问题,就是可以推进的部分;答不出的问题,就是需要补的部分。'],
+['拦住什么错', '拦住「堆证据不讲结论」「藏起矛盾」「质询后悄悄改数」三种常见错误。'],
+['沉淀什么资产', '提案本身、V3.0 和成果导航,是结营后 7 周陪练以及未来新项目的交接物。']
+],
+handoff: [
+'<b>结营与陪练:</b>V3.0 的「答不出」清单就是第一周的任务。',
+'<b>下一次立项:</b>这次提案的结论页与风险页,可以直接作为立项报告的前两页草稿。',
+'<b>组织沉淀:</b>成果导航可以合并进产品中心的「创新资产目录」。'
+],
+flow: ['D2-08', '提案 + V3.0 + 导航', '结营展演', '训后第一周']
+}
+
+};
+
+// 渲染 + 交互:原生 JS,无依赖。v3 在 v2 基础上新增:大课分段、产出物规范板、推送语、三层架构。
+(function () {
+  'use strict';
+
+  var SEGS = window.SEGS || [];
+  var PROMPTS = window.PROMPTS || {};
+  var DELIV = window.DELIV || {};
+  function esc(s) {
+    return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+  }
+  function promptBlock(id) {
+    var p = PROMPTS[id];
+    if (!p) return '<p class="muted">[提示词缺失:' + esc(id) + ']</p>';
+    return '<div class="prompt" data-id="' + id + '">' +
+      '<div class="prompt-bar"><span class="prompt-label">提示词 · ' + esc(p.name) + '</span>' +
+      '<button class="copy" type="button" data-copy="' + id + '">复制</button></div>' +
+      '<pre class="prompt-body">' + esc(p.text) + '</pre></div>';
+  }
+
+  var HTML = [];
+  var NAV = [];        // {kind,id,title,group}
+  var SEC_IDS = [];    // 13 个环节
+  var HALVES = [];     // {id,label,theme,sections:[]}
+  var DELIV_COUNT = 0;
+
+  function h(s) { HTML.push(s); }
+
+  // ---------- 封面 ----------
+  function renderCover(s) {
+    h('<header class="cover" id="top">' +
+      '<div class="cover-mark">康师傅 · 智研先锋计划 · 学员手册 v3</div>' +
+      '<h1>' + s.title + '</h1>' +
+      '<p class="cover-sub">' + esc(s.sub) + '</p>' +
+      '<p class="cover-lead">' + s.lead + '</p>' +
+      '<div class="cover-thesis">' + s.thesis + '</div>' +
+      '<div class="cover-facts">' + s.facts.map(function (f) { return '<div><span>' + esc(f[0]) + '</span><b>' + esc(f[1]) + '</b></div>'; }).join('') + '</div>' +
+      '<div class="cover-cta"><a href="#overview" class="btn primary">三个半天总览</a><a href="#pm" class="btn">你是未来品类负责人</a><a href="#sop" class="btn">八步 SOP</a><a class="btn" href="../overview/index.html">总览图 ↗</a></div>' +
+      '</header>');
+  }
+
+  // ---------- 通用块段 ----------
+  function renderMeta(s) {
+    NAV.push({ kind: 'meta', id: s.id, title: s.title, group: s.group });
+    h('<section class="seg sec" id="' + s.id + '"><h2 class="seg-title">' + esc(s.title) + '</h2>');
+    if (s.lead) h('<p class="lead">' + s.lead + '</p>');
+    (s.blocks || []).forEach(function (b) {
+      h('<div class="block' + (b.cls ? ' ' + b.cls : '') + '"><h3>' + esc(b.t) + '</h3>' + (b.html || ''));
+    });
+    if (s.render) h(s.render());
+    h('</section>');
+  }
+
+  // ---------- 半天头 ----------
+  function renderHalf(s) {
+    HALVES.push({ id: s.id, label: s.label, theme: s.theme, sections: [] });
+    h('<section class="half" id="' + s.id + '"><div class="half-head">' +
+      '<div class="half-top"><span class="half-label">' + esc(s.label) + '</span><span class="half-time">' + esc(s.time) + '</span></div>' +
+      '<h2>' + esc(s.theme) + '</h2><p>' + esc(s.lead) + '</p>' +
+      '<div class="half-goal"><b>本半天结束,每组应该有:</b><ol>' + s.goal.map(function (g) { return '<li>' + g + '</li>'; }).join('') + '</ol></div>' +
+      '<div class="band-note">' + (s.note || '') + '</div></div></section>');
+  }
+
+  // ---------- 大课详案 ----------
+  function renderBig(s) {
+    NAV.push({ kind: 'big', id: s.id, title: s.title, group: s.group });
+    h('<article class="seg big" id="' + s.id + '">' +
+      '<div class="big-head"><span class="big-no">' + esc(s.no) + '</span><h2>' + esc(s.title) + '</h2></div>' +
+      '<div class="meta-row">' + s.meta.map(function (m) { return '<span class="chip' + (m[1] ? ' ' + m[1] : '') + '">' + esc(m[0]) + '</span>'; }).join('') + '</div>' +
+      '<p class="lead">' + s.lead + '</p>');
+    if (s.outline) {
+      h('<div class="segments">' + s.outline.map(function (o) {
+        return '<div class="seg-row' + (o[3] ? ' onair' : '') + '"><span class="sr-t">' + esc(o[0]) + '</span><b>' + esc(o[1]) + '</b><span class="sr-q">' + esc(o[2]) + '</span></div>';
+      }).join('') + '</div>');
+    }
+    if (s.before) s.before.forEach(function (b) { h('<div class="block' + (b.cls ? ' ' + b.cls : '') + '"><h3>' + esc(b.t) + '</h3>' + (b.html || '')); });
+    (s.parts || []).forEach(function (p) {
+      h('<section class="lecture" id="' + p.id + '"><div class="lecture-head"><span class="lecture-no">' + esc(p.no) + '</span><h3>' + esc(p.title) + '</h3>' +
+        '<span class="chip">' + esc(p.time) + '</span>' + (p.goal ? '<span class="chip tag">' + esc(p.goal) + '</span>' : '') + '</div><div class="lecture-body">');
+      (p.pts || []).forEach(function (pt) {
+        h('<div class="lp"><div class="lp-head"><span class="lp-time">' + esc(pt.t) + '</span><h4>' + esc(pt.ti) + '</h4></div>' +
+          (pt.html || '') + (pt.prompt ? promptBlock(pt.prompt) : '') + '</div>');
+      });
+      if (p.blocks) p.blocks.forEach(function (b) { h('<div class="block' + (b.cls ? ' ' + b.cls : '') + '"><h3>' + esc(b.t) + '</h3>' + (b.html || '')); });
+      if (p.takeaway) h('<div class="block note"><h3>这一段的落点</h3>' + p.takeaway + '</div>');
+      h('</div></section>');
+    });
+    if (s.after) s.after.forEach(function (b) { h('<div class="block' + (b.cls ? ' ' + b.cls : '') + '"><h3>' + esc(b.t) + '</h3>' + (b.html || '')); });
+    h('</article>');
+  }
+
+  // ---------- 环节 ----------
+  function specHTML(id) {
+    var d = DELIV[id];
+    if (!d) return '<p class="muted">[产出物规范缺失:' + esc(id) + ']</p>';
+    DELIV_COUNT++;
+    var flow = d.flow.map(function (f, i) {
+      return (i ? '<i>→</i>' : '') + '<span>' + (f[0] ? '<b>' + esc(f) + '</b>' : esc(f)) + '</span>';
+    }).join('');
+    return '<div class="spec" id="spec-' + id + '">' +
+      '<div class="spec-head"><span class="spec-k">产出物规范</span><h3>' + esc(d.name) + '</h3><span class="spec-meta">' + esc(d.form) + ' · ' + esc(d.owner) + '</span></div>' +
+      '<div class="spec-body">' +
+        '<div class="spec-block"><h4><span class="spec-n">1</span>它长什么样<span class="spec-form">' + esc(d.form) + '</span></h4>' + d.look +
+          '<p class="spec-legend">' + (d.legend || []).map(function (l) { return '<span><em style="background:' + l[0] + '"></em>' + esc(l[1]) + '</span>'; }).join('') +
+          '<span><em style="background:#1F1F1F"></em>黑条 = 文档抬头(谁做的、给谁用、什么状态)</span></p>' +
+          '<p class="muted">样卡用课堂数据包的真实数字写成,示范的是格式与判断方式,不是本组答案。</p></div>' +
+        '<div class="spec-block"><h4><span class="spec-n">2</span>它是用来干什么的</h4><div class="uses">' +
+          d.purpose.map(function (p) { return '<div class="use"><b>' + esc(p[0]) + '</b>' + p[1] + '</div>'; }).join('') + '</div></div>' +
+        '<div class="spec-block"><h4><span class="spec-n">3</span>它交给谁、怎么被下一环用</h4>' +
+          '<div class="flow-mini">' + flow + '</div><div class="handoff-box"><span class="hb">下一环具体用法</span><ul>' +
+          d.handoff.map(function (x) { return '<li>' + x + '</li>'; }).join('') + '</ul></div></div>' +
+      '</div></div>';
+  }
+
+  function pushHTML(s) {
+    var p = s.push;
+    return '<div class="push"><div class="push-bar"><b>AI 推送</b><span>' + esc(p.who || '本组数字分身 · 环节结束自动输出') + '</span></div><div class="push-rows">' +
+      '<div class="push-row"><b>【本轮产出】</b><p>' + p.out + '</p></div>' +
+      '<div class="push-row"><b>【还缺什么】</b><p>' + p.gap + '</p></div>' +
+      '<div class="push-row"><b>【下一步】</b><p class="ask">' + p.next + '</p></div>' +
+      '</div></div>';
+  }
+
+  function renderSection(s) {
+    NAV.push({ kind: 'sec', id: s.id, title: s.no + ' · ' + s.title, group: s.group });
+    SEC_IDS.push(s.id);
+    var cur = HALVES[HALVES.length - 1];
+    if (cur) cur.sections.push(s.id);
+    var dl = DELIV[s.id] || {};
+    h('<article class="seg sec" id="' + s.id + '">' +
+      '<div class="sec-head"><div class="sec-no">' + esc(s.no) + '</div><div><h2>' + esc(s.title) + '</h2>' +
+      '<div class="meta-row"><span class="chip">⏱ ' + esc(s.time) + '</span>' +
+      '<span class="chip deliver">产出物:' + esc(dl.name || '') + '</span>' +
+      '<span class="chip">形态:' + esc(dl.form || '') + '</span>' +
+      (s.type ? '<span class="chip tag">' + esc(s.type) + '</span>' : '') + '</div></div></div>' +
+      '<div class="from">↑ 承接:' + s.from + '</div>');
+
+    h('<div class="block"><h3><span class="step-no">一</span>先想清楚(3 分钟,自己填)</h3>' +
+      '<div class="pillars">' + s.pillars.map(function (p, i) {
+        return '<div class="pillar' + (i === 1 ? ' key' : '') + '"><div class="p-head"><b>' + esc(p.name) + '</b>' + (i === 1 ? '<span class="p-flag">最值钱</span>' : '') + '</div>' +
+          '<p class="p-tip">' + esc(p.tip) + '</p><p class="p-sample"><span>示例</span>' + esc(p.sample) + '</p>' +
+          '<div class="p-lines" aria-hidden="true"><i></i><i></i><i></i></div></div>';
+      }).join('') + '</div></div>');
+
+    h('<div class="block"><h3><span class="step-no">二</span>这一节要解决什么</h3>' + s.problem + '</div>');
+    if (s.industry) h('<div class="block industry"><h3><span class="step-no">背景</span>' + esc(s.industry.title) + '</h3>' + s.industry.html + '</div>');
+
+    h('<div class="block"><h3><span class="step-no">三</span>怎么做</h3>' +
+      (s.prompts || []).map(function (id) { return promptBlock(id); }).join('') + s.how + '</div>');
+
+    h('<div class="block"><h3><span class="step-no">四</span>你会拿到什么</h3>' + (s.deliver || '') + specHTML(s.id) + '</div>');
+
+    if (s.discuss) h('<div class="block"><h3><span class="step-no">五</span>小组讨论</h3>' + s.discuss + '</div>');
+    if (s.check) h('<div class="block check"><h3><span class="step-no">六</span>本组进度自检</h3><ol>' +
+      s.check.map(function (q) { return '<li><label><input type="checkbox"><span>' + esc(q) + '</span></label></li>'; }).join('') + '</ol>' +
+      '<p class="muted">三条都能打勾,才算这一节真推进了;有一项打不了勾,回到对应部分补,不要硬往下走。</p></div>');
+    if (s.right) h('<div class="right-wrong"><div class="rw ok"><h3>✓ 这样做是对的</h3><ul>' + s.right.map(function (x) { return '<li>' + x + '</li>'; }).join('') + '</ul></div>' +
+      '<div class="rw bad"><h3>✗ 常见的错法</h3><ul>' + s.wrong.map(function (x) { return '<li>' + x + '</li>'; }).join('') + '</ul></div></div>');
+    h('<div class="block"><h3><span class="step-no">七</span>环节收尾:AI 推送</h3>' + pushHTML(s) + '</div>');
+    if (s.handoff) h('<div class="handoff"><span>↓ 交给下一环节</span><p>' + s.handoff + '</p></div>');
+    h('</article>');
+  }
+
+  // ---------- 附录 ----------
+  function renderAppx(s) {
+    NAV.push({ kind: 'appx', id: s.id, title: s.title.replace(/^附录 [A-D] · /, ''), group: '附录' });
+    h('<section class="seg sec appx" id="' + s.id + '"><h2 class="seg-title">' + esc(s.title) + '</h2>');
+    if (s.lead) h('<p class="lead">' + s.lead + '</p>');
+    if (s.traps) {
+      h('<div class="traps">' + s.traps.map(function (t) {
+        return '<div class="trap"><div class="trap-head"><span class="trap-no">反常识 ' + t.n + '</span><h3>' + esc(t.title) + '</h3><span class="trap-tag">' + esc(t.tag) + '</span></div>' +
+          '<div class="trap-cols"><div class="tc ai"><h4>AI 初版结论</h4>' + tp(t.ai) + '</div><div class="arrow">→</div><div class="tc human"><h4>人工复核后</h4>' + tp(t.human) + '</div></div>' +
+          '<div class="trap-foot"><p><b>原文</b> ' + esc(t.quote) + '</p><p><b>照这样做</b> ' + esc(t.where) + '</p><p class="muted">' + t.note + '</p></div></div>';
+      }).join('') + '</div>');
+      if (s.practice) h('<div class="block accent"><h3>' + esc(s.practice.title) + '</h3>' + s.practice.html + '</div>');
+    }
+    (s.blocks || []).forEach(function (b) {
+      h('<div class="block' + (b.cls ? ' ' + b.cls : '') + '"><h3>' + esc(b.t) + '</h3>' + (b.html || '') + (b.prompt ? promptBlock(b.prompt) : ''));
+    });
+    if (s.faq) {
+      h('<div class="faq">' + s.faq.map(function (g) {
+        return '<div class="faq-group"><h3>' + esc(g.g) + '</h3>' + g.qs.map(function (q) {
+          return '<details class="q"><summary>' + esc(q[0]) + '</summary><p>' + q[1] + '</p></details>';
+        }).join('') + '</div>';
+      }).join('') + '</div>');
+    }
+    if (s.tips) h('<div class="tips"><h3>' + esc(s.tips.title) + '</h3><ol>' + s.tips.items.map(function (x) { return '<li>' + esc(x) + '</li>'; }).join('') + '</ol></div>');
+    h('</section>');
+  }
+
+  function tp(html) {
+    var t = String(html).trim();
+    if (t.charAt(0) !== '<') return '<p>' + esc(t) + '</p>';
+    return t;
+  }
+
+  // ---------- 主渲染 ----------
+  SEGS.forEach(function (s) {
+    switch (s.kind) {
+      case 'cover': renderCover(s); break;
+      case 'meta': renderMeta(s); break;
+      case 'half': renderHalf(s); break;
+      case 'big': renderBig(s); break;
+      case 'section': renderSection(s); break;
+      case 'appx': renderAppx(s); break;
+      case 'raw': h(s.html); break;
+    }
+  });
+
+  h('<footer class="foot"><p><b>康师傅 · 产品创新工作坊 学员手册 v3</b> · 产品经理 = 未来品类负责人</p>' +
+    '<p>数据口径:课堂数据包 2026-11-01 单次快照(电商 400 SKU、用户笔记 260 篇、竞品社媒 120 篇、工艺知识库 49 条),手册中的数字均可在 <a href="#appx-a">附录 A</a> 找到出处与复核方法。</p>' +
+    '<p>课堂过程成果一律标注「未经正式确认」,不代替正式研究报告。</p><a href="#top">回到顶部 ↑</a></footer>');
+
+  var content = document.getElementById('content');
+  content.innerHTML = HTML.join('')
+    .replace(/<table class="tbl((?:" [^>]*|)(?: )?)>/g, function (_, cls) {
+      return '<div class="tbl-scroll"><table class="tbl' + (cls || '') + '">';
+    });
+
+  // ---------- 目录 ----------
+  var GROUP_ORDER = ['开始之前', '大课详案', 'D1 下午', 'D2 上午', 'D2 下午', '附录'];
+  var tocHTML = '', lastGroup = '';
+  NAV.forEach(function (n) {
+    var g = n.group || '其他';
+    if (g !== lastGroup) { tocHTML += '<div class="toc-group">' + esc(g) + '</div>'; lastGroup = g; }
+    tocHTML += '<a href="#' + n.id + '" data-toc="' + n.id + '" class="toc-' + n.kind + '">' + esc(n.title) + '</a>';
+  });
+  document.getElementById('toc-list').innerHTML = tocHTML;
+
+  // ---------- 进度 ----------
+  var prog = document.getElementById('progress');
+  var TOTAL = SEC_IDS.length;
+  prog.innerHTML = HALVES.map(function (hv) {
+    return '<a href="#' + hv.id + '" class="pg" data-half="' + hv.id + '" title="' + esc(hv.theme) + '"><span class="pg-bar"><i></i></span><span class="pg-label">' + esc(hv.label) + '</span></a>';
+  }).join('') + '<span class="pg-count" id="pg-count">0 / ' + TOTAL + '</span>';
+
+  // ---------- 滚动 ----------
+  var tocLinks = {};
+  Array.prototype.forEach.call(document.querySelectorAll('[data-toc]'), function (a) { tocLinks[a.getAttribute('data-toc')] = a; });
+  var progBars = Array.prototype.slice.call(document.querySelectorAll('.pg'));
+  var ticking = false;
+  function navActive() {
+    var y = window.scrollY + 140, cur = null;
+    NAV.forEach(function (n) { var el = document.getElementById(n.id); if (el && el.offsetTop <= y) cur = n.id; });
+    return cur;
+  }
+  function onScroll() {
+    if (ticking) return; ticking = true;
+    requestAnimationFrame(function () {
+      ticking = false;
+      var a = navActive();
+      Object.keys(tocLinks).forEach(function (k) { tocLinks[k].classList.toggle('active', k === a); });
+      var halfPos = -1, secPos = 0;
+      HALVES.forEach(function (hv, i) {
+        if (document.getElementById(hv.id).offsetTop <= window.scrollY + 200) halfPos = i;
+        hv.sections.forEach(function (id) {
+          var el = document.getElementById(id);
+          if (el && el.offsetTop <= window.scrollY + window.innerHeight * 0.5) secPos = Math.max(secPos, SEC_IDS.indexOf(id) + 1);
+        });
+      });
+      progBars.forEach(function (b, i) {
+        b.classList.toggle('active', i === halfPos);
+        b.classList.toggle('done', i < halfPos);
+        b.querySelector('i').style.width = i < halfPos ? '100%' : (i === halfPos ? '35%' : '0');
+      });
+      document.getElementById('pg-count').textContent = secPos + ' / ' + TOTAL;
+    });
+  }
+  window.addEventListener('scroll', onScroll, { passive: true });
+  window.addEventListener('resize', onScroll);
+  onScroll();
+  if (location.hash) {
+    var ht = document.getElementById(decodeURIComponent(location.hash.slice(1)));
+    if (ht) ht.scrollIntoView();
+    onScroll();
+  }
+
+  // ---------- 复制 ----------
+  function copyText(text) {
+    if (navigator.clipboard && window.isSecureContext) return navigator.clipboard.writeText(text);
+    return new Promise(function (resolve, reject) {
+      var ta = document.createElement('textarea');
+      ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
+      document.body.appendChild(ta); ta.select();
+      try { document.execCommand('copy') ? resolve() : reject(); } catch (e) { reject(e); }
+      document.body.removeChild(ta);
+    });
+  }
+  document.addEventListener('click', function (e) {
+    var btn = e.target.closest && e.target.closest('[data-copy]');
+    if (!btn) return;
+    var p = PROMPTS[btn.getAttribute('data-copy')];
+    if (!p) return;
+    copyText(p.text).then(function () {
+      btn.textContent = '已复制 ✓'; btn.classList.add('ok');
+      setTimeout(function () { btn.textContent = '复制'; btn.classList.remove('ok'); }, 1600);
+    }, function () {
+      btn.textContent = '复制失败,请长按选择';
+      setTimeout(function () { btn.textContent = '复制'; }, 2200);
+    });
+  });
+
+  // ---------- 主题 ----------
+  var root = document.documentElement;
+  var saved = null;
+  try { saved = localStorage.getItem('ksf3-theme'); } catch (e) {}
+  if (saved) root.setAttribute('data-theme', saved);
+  document.getElementById('theme-toggle').addEventListener('click', function () {
+    var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
+    root.setAttribute('data-theme', next);
+    try { localStorage.setItem('ksf3-theme', next); } catch (e) {}
+  });
+
+  // ---------- 抽屉 ----------
+  var drawer = document.getElementById('drawer');
+  var scrim = document.getElementById('scrim');
+  function closeDrawer() { document.body.classList.remove('nav-open'); }
+  document.getElementById('menu-btn').addEventListener('click', function () { document.body.classList.toggle('nav-open'); });
+  document.getElementById('drawer-close').addEventListener('click', closeDrawer);
+  scrim.addEventListener('click', closeDrawer);
+  drawer.addEventListener('click', function (e) {
+    var a = e.target.closest('a[href^="#"]');
+    if (!a) return;
+    e.preventDefault(); closeDrawer();
+    var t = document.getElementById(a.getAttribute('href').slice(1));
+    if (t) t.scrollIntoView({ behavior: 'auto' });
+  });
+  window.addEventListener('keydown', function (e) { if (e.key === 'Escape') closeDrawer(); });
+  document.getElementById('toc-list').addEventListener('click', function (e) {
+    var a = e.target.closest('a[href^="#"]');
+    if (!a) return;
+    var t = document.getElementById(a.getAttribute('href').slice(1));
+    if (!t) return;
+    e.preventDefault(); t.scrollIntoView({ behavior: 'smooth' });
+  });
+
+  // ---------- 搜索:过滤目录 + 搜正文 ----------
+  var search = document.getElementById('search');
+  var results = document.createElement('div');
+  results.className = 'toc';
+  results.id = 'search-results';
+  results.style.display = 'none';
+  document.getElementById('toc-list').parentNode.insertBefore(results, document.getElementById('toc-list'));
+  var INDEX = NAV.map(function (n) {
+    var el = document.getElementById(n.id);
+    var text = '';
+    if (el) {
+      var walk = el;
+      for (var i = 0; i < 3 && walk; i++) {
+        if (/^(ARTICLE|SECTION)$/.test(walk.tagName)) { text = walk.textContent; break; }
+        walk = walk.nextElementSibling;
+      }
+    }
+    return { id: n.id, title: n.title, text: (n.title + ' ' + (text || '').replace(/\s+/g, ' ')).toLowerCase() };
+  });
+  function runSearch() {
+    var q = search.value.trim().toLowerCase();
+    Array.prototype.forEach.call(document.querySelectorAll('.toc-group, [data-toc]'), function (x) { x.style.display = q ? 'none' : ''; });
+    document.querySelectorAll('.toc-group').forEach(function (g) { g.style.display = q ? 'none' : ''; });
+    if (!q) { results.style.display = 'none'; results.innerHTML = ''; return; }
+    var hits = [];
+    INDEX.forEach(function (it) {
+      var t = it.text, from = 0, k;
+      while ((k = t.indexOf(q, from)) >= 0 && hits.length < 60) {
+        var s0 = Math.max(0, k - 18), e0 = Math.min(t.length, k + q.length + 28);
+        hits.push({ id: it.id, title: it.title, snip: (s0 > 0 ? '…' : '') + t.slice(s0, e0).replace(/</g, '&lt;') + (e0 < t.length ? '…' : '') });
+        from = k + q.length;
+        if (hits.length >= 60) break;
+      }
+    });
+    results.style.display = 'block';
+    results.innerHTML = '<div class="toc-group">找到 ' + hits.length + ' 处' + (hits.length >= 60 ? '(显示前 60 处)' : '') + '</div>' +
+      hits.map(function (x) { return '<a href="#' + x.id + '">' + esc(x.title) + '<br><span style="color:var(--ink-3);font-size:12px;white-space:normal">' + x.snip + '</span></a>'; }).join('');
+  }
+  if (search) search.addEventListener('input', runSearch);
+
+  window.__manual = { sections: SEC_IDS.slice(), nav: NAV.length, deliverables: DELIV_COUNT };
+})();
+
+</script>
+</body>
+</html>

+ 58 - 0
docs/workshop-v3-alignment-20261112/source-prompts-v3.json

@@ -0,0 +1,58 @@
+{
+  "source": "https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html",
+  "sourceSha256": "e8ed9dbd979c17f5caa88fb820f64f94a2e54518f810d7482b6b82f39d88041d",
+  "prompts": {
+    "d101": {
+      "name": "D1-01 品类全景扫描",
+      "text": "【D1-01 品类全景扫描】\n承接:本组课题是「(粘贴本组课题:使用情境 + 产品范围)」,本组要支持的产品决定是「(粘贴练习四写下的决定)」。\n\n先看我下面填的认知盘点(不要跳过、不要替我改):\n1. 我已经知道的:\n2. 我还不知道的:\n3. 我希望搞清楚的:\n4. 我的真实限制:\n\n本节请建立「品类全景图谱」,它是后面所有环节的底座:\n- 供给树:按形态、工艺、价格带、地域风味四个维度,说明本组课题涉及的格子分别有什么商品(带计数);\n- 需求树:按人群(G1–G6)、场景、需求,说明本组课题的人群在哪一格里说过什么;\n- 供需缺口:左右两栏对照,指出「有商品、没需求原话」和「有需求原话、没商品」的格子;\n- 每个分支标注来源(数据文件 / 商品链接 / 笔记 ID)和覆盖范围(样本条数、平台、关键词)。\n\n要求:\n- 不虚构市场规模、销量或份额;数据里没有的,写「待确认」;\n- 「未标注」不等于「没有」,分清楚;\n- 先复用资料库已有材料;只有当缺口会改变图谱结构时,再说明需要补什么;\n- 「我还不知道的」那几条优先回答,并标出哪些已回答、哪些仍是缺口。\n\n最后输出:一张三栏图谱 + 一段 100 字以内的话,说明「本组所在的格子里,哪一格证据最薄」。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-02 的具体缺口)\n【下一步】接下来要做 D1-02 验证纪律。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d102": {
+      "name": "D1-02 验证纪律",
+      "text": "【D1-02 验证纪律】\n承接:本组 D1-01 的品类全景图谱(引用保存编号或粘贴表格)。\n\n本节请为本题定制一张「本题验证配置卡」,之后所有环节都按这张卡执行:\n1. 资料资格:哪些数据可以用、什么条件下可引用、什么情况下必须换口径;\n2. 统计与引文口径:分母怎么写、中位数用哪一种、价格用哪个口径(125 条与 71 条双报)、原文引用规范;\n3. 模型分工:哪些判断由你给证据、哪些必须由本组人来拍板;\n4. 分歧处理:两种说法冲突时怎么判,判不了怎么写;\n5. 回查记录:拿上面 1–4 回查 D1-01 图谱,挑出最容易被反驳的 3 条主张,说明换口径后结论变不变。\n\n企业标准(成本、产线、配方、价格政策)一律标「待确认」,不要替我猜。\n词典打标词(辣、贵、量大等)未抽读原文的,一律降级为「假设」。\n\n最后输出:一张配置卡(不超过一页)+ 一张回查记录。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-03 的具体缺口)\n【下一步】接下来要做 D1-03 竞品格局。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d103": {
+      "name": "D1-03 竞品格局",
+      "text": "【D1-03 竞品格局】\n承接:D1-01 品类全景图谱 + D1-02 验证配置卡。\n本组课题:(粘贴)。本组最关心的竞品 / 品牌:___。\n\n本节请按验证配置卡的口径,做「竞品图谱 + 待验证痛点假设」。\n\n一、商品层面(同格商品矩阵)\n对与本组课题同一格子的商品,比较:品牌、商品链接、规格(克重/件数)、价格条件(单价、百克价、整箱/单份)、形态、定位、卖点组合(哪些卖点叠加)、风味。\n每个卖点格子只标三种之一:【宣称】(标题/详情)、【回应】(用户原话所说)、【推断】(你的判断)。\n找不到新品时间字段就写「无字段,无法判断」,不要用标题推测。\n\n二、社媒层面\n- 每个竞品提取卖点组合,严格区分宣称 / 回应 / 推断;\n- 找出「正反都有」的原话:同一主题上有人说好、有人说不好,各给原文;\n- 对本组最关心的 2–3 个问题,提出可证伪的痛点假设(编号 H1、H2、H3),每条写清:凭什么怀疑、什么情况推翻它。\n\n口径要求:\n- 竞品社媒样本是每品牌一个关键词、约 20 篇,写明这个样本能代表什么、不能代表什么;\n- 不要用总赞排品牌声量;单条点赞特别高的,先检查是不是活动帖、表情包或重复抓取;\n- 碰到「辣」这类口味词,抽读原文再判断是正面还是负面。\n\n最后输出:一张竞品矩阵 + 一张假设清单。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响下一环 D1-04 的具体缺口)\n【下一步】接下来要做 D1-04 假设定稿与任务下达。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d104": {
+      "name": "D1-04 假设定稿与任务下达",
+      "text": "【D1-04 假设定稿与任务下达】\n承接:D1-01 图谱、D1-02 配置卡、D1-03 竞品图谱与 H1–H3 待验证痛点假设。\n本组要支持的决定:(粘贴)。今晚最想得到答案的一条:(粘贴)。\n\n请把它们整理成「增强 AI 自驱任务卡」,每条主线假设一行,字段固定:\n- 假设键(H1 起编号,之后所有成果都用它引用)\n- 原假设(一句话,可被证伪)\n- 现有支持(带来源与编号)\n- 支持路径(查什么能支持它)\n- 反证路径(查什么能推翻它)\n- 停止条件(必须是程序可判定的东西,例如「找到 N 条反例」「读完某组全部笔记」)\n- 数据来源与权限(先复用资料库;外部补证是否授权、去哪里补)\n\n今晚的任务边界:\n- 只执行这张任务卡里的假设,不扩展新方向;\n- 最多 3 条主线假设,其余放「备查」;\n- 资料库不够、且缺口会改变结论时,才调用外部补证;不需要补证就直接成报;\n- 没查到、没权限、数据确实不存在,三类分开报。\n\n先给我一版任务卡草稿,并指出:哪些字段你拿不准、需要我回答?(只问会改变结论的问题)\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出今晚执行前还差什么)\n【下一步】今晚执行 D1-N 第二轮调研。请在交卡前回答:___(只问一个会改变结论的问题)"
+    },
+    "d1n": {
+      "name": "D1-N 第二轮调研(晚间执行)",
+      "text": "【D1-N 第二轮调研 · 晚间执行】\n按 D1-04 的任务卡执行今晚的调研。任务卡:(引用编号)验证配置卡:(引用编号)\n\n执行顺序:\n1. 先复用资料库原件:已有的商品、用户笔记、工艺知识、竞品资料;\n2. 检查覆盖与资格:每条假设被支持到什么程度,哪些是缺口;\n3. 只对「会改变判断的真实缺口」决定是否外部补证,并说明补什么、去哪里补;\n4. 按假设键做 VOC 预聚类,每条原话带笔记标题 / ID;提及率初表写清分母;\n5. 资料够用、不需要补证时,直接成报,不要为凑形式机械采集;\n6. 缺口清单分三类:没查到 / 没权限 / 数据确实不存在;\n7. 达到停止条件就停,并在战报中写明停在哪个条件;\n8. 保存后用真实编号回读,确认正文一致。\n\n最后输出:调研战报(按假设键一页)+ 缺口清单 + VOC 预聚类。\n\n【推送格式】战报生成时,在最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(明早最值得先读的缺口)\n【下一步】明早先做 D2-01 调研验收。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d201": {
+      "name": "D2-01 调研验收",
+      "text": "【D2-01 调研验收】\n承接:D1-N 的调研战报与缺口清单(引用编号)。\n\n请从战报中抽取「战报验收记录」,三列检查:\n1. 假设回应率:H1–H3 每条回应程度(支持 / 部分支持 / 推翻 / 未回应),并说明依据;\n2. 原件覆盖:支撑每条结论的原件是否能点开读到(附笔记 ID / 商品链接);读不到的标「待补证」;\n3. 分母口径:所有比例是否写明分母;没有的,补上或降级;\n另外:\n- 词典打标词是否抽读原文(辣 / 贵 / 量大等);未读的结论降到「假设」;\n- 缺口是否分了「没查到 / 没权限 / 不存在」三类;\n- 「AI 推断」是否与「原件证据」分开写。\n\n最后输出:一张验收记录 + 一份「可用资料集合」(合格的、能回读的原件清单)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-02 的具体缺口)\n【下一步】先听大课二,然后做 D2-02 VOC 证词聚类。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d202": {
+      "name": "D2-02 VOC 证词聚类",
+      "text": "【D2-02 VOC 证词聚类】\n承接:D2-01 战报验收记录 + 可用资料集合(附笔记 ID)。\n本组人群与场景范围:(粘贴)。\n\n请把可用资料的原话按四层拆开,四层不能混:\n1. 人群(G1–G6 或更细);\n2. 场景(具体时间、地点、行为);\n3. JTBD(用户要完成的事);\n4. 痛点(具体不满)。\n对每个打标痛点词(辣、贵、量大等),抽读原文,标注态度:正 / 负 / 读不出。\n\n输出四张表:\n- 聚类表:每条原话落在哪一层、哪一格;\n- 痛点库:痛点、原话(带 ID)、频次、态度分布;\n- KANO 表:每条痛点的需求类型(基本型 / 期望型 / 兴奋型),标明「频次先验」;\n- 人群 × 场景矩阵:每一格写原话条数与代表原话。\n\n禁止:按打标频次直接排名次;把「读不出态度」的原话删除。\n最后输出:四张表 + 3 个「有原话、没产品」的格子。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-03 的具体缺口)\n【下一步】接下来要做 D2-03 风味趋势与矩阵空白。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d203": {
+      "name": "D2-03 风味趋势与矩阵空白",
+      "text": "【D2-03 风味趋势与矩阵空白】\n承接:D2-02 四张表 + D1-01 品类全景图谱。\n\n请把「需求矩阵」和「供给矩阵」叠在一起,按三类列出空白:\n1. 结构:现在长什么样(价格带、工艺、形态、地域的分布);\n2. 变化:本批数据是单次快照,不能判涨跌;如要判「在变」,必须说明时间序列来源,没有就写「本次不验证」;\n3. 未覆盖:该有的东西还没有——但每个「未覆盖」都必须先查同格竞品,写明「同格已有 N 个,其中谁」。\n\n每个空白格给一行「机会指标」:要验证什么、用什么数据能验证、本次能不能验证。\n禁止把三类放在同一张排序表里比较;禁止把「搜索页找不到」写成「市场空白」。\n\n最后输出:产品机会及指标初表(一行一个机会,五列:空白格 / 类别 / 供给证据 / 需求证据 / 需要验证的指标)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-04 的具体缺口)\n【下一步】接下来要做 D2-04 三源交叉推理。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d204": {
+      "name": "D2-04 三源交叉推理",
+      "text": "【D2-04 三源交叉推理】\n承接:D2-03 机会及指标初表 + D2-02 四张表 + 本组研发侧对工艺的判断。\n本组最想先认证的 2 个空白格:(粘贴)。\n\n对每个空白格做三源交叉:\n- 源一 商品事实:同格有哪些商品、价格带、卖点组合(带商品链接);\n- 源二 用户原声:有哪些原话直接指向这一格(带笔记 ID 与态度);\n- 源三 工艺条件:这一格做不做得出来(参数、成本、稳定性)——你写你判断的,其余标「待工艺确认」。\n\n每张「机会卡」固定 6 个字段:\n1. 一句话结论(可被推翻的判断);\n2. 三源证据(每条带来源与编号);\n3. 反例(什么情况下这个结论不成立);\n4. 还缺什么(写成「待确认:……」并说明影响哪个结论);\n5. 下一步验证(先补哪一条证据);\n6. 工艺注释(研发侧亲手写:参数、条件、风险;AI 不得代写为「可行」)。\n\n评级:三源齐全 → 候选;两条线 → 候选(弱);一条线 → 线索。\n最后输出:候选机会清单 V1.0(2–3 张机会卡)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出下午 D2-05 排序前还差什么)\n【下一步】先听大课三,然后做 D2-05 机会验证与排序。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d205": {
+      "name": "D2-05 机会验证与排序",
+      "text": "【D2-05 机会验证与排序】\n承接:候选机会清单 V1.0(2–3 张机会卡)。\n\n请对每张机会卡打三个维度分(1–3):\n- 证据强度:三源各有多少条证据;\n- 可做性:现有产线 / 工艺 / 供应商能不能做;\n- 商业价值:价格带、毛利、量级(这一项标注「需本组复核」)。\n每个分数后写一句话依据,并标注依据是「课堂证据」还是「本组经验」。\n\n排序规则:任何一维得 1 分的机会,不得排进前三。\n无法打分的,单独列入「未知项表」:缺什么数据、能用什么方式补、本次能不能补。未知项不是低分项。\n\n最后输出:优先级机会清单(含分值、依据、排序理由)+ 未知项单列。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-06 的具体缺口)\n【下一步】接下来要做 D2-06 商业及供应链回推。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d206": {
+      "name": "D2-06 商业及供应链回推",
+      "text": "【D2-06 商业及供应链回推】\n承接:D2-05 优先级机会清单,本组主攻机会:(粘贴)工艺路径:改现有配比(B0)/ 新增并行产品线(O1)/ 两者对比。\n\n请对主攻机会做「回推表 + 候选机会清单 V2.0」:\n1. 两条路:B0 现状、O1 目标方案;只有收入、渠道费用、损耗比例都相同时,两者才可直接比较,否则写明差异;\n2. 三条费用分开:一次费用 / 资本投入 / 营运资金;\n3. 成本结构:按知识库行业通行值拆(面饼 34–38% / 调料 24–30% / 包材 12–13%……),换算到单位成本与目标价格带;\n4. 供应商:代工价 2.1–3.2 元/袋、验厂比例 42%、区域分工;缺装箱/外箱/配送/损耗的标「待确认」;\n5. 工艺与合规:工艺参数、GB 17400-2015(水分 ≤10%、酸价 ≤1.8、过氧化值 ≤0.25)、GB 2760-2024 添加剂限量;以标准正文为准。\n\n所有估算标「课堂估算」;本组经验值标「经验值」;缺的标「待确认」。\n最后输出:回推表 + V2.0 机会卡(在 V1.0 六字段外增加:成本区间 / 目标价格带 / 两条路对比 / 合规条件)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-07 的具体缺口)\n【下一步】接下来要做 D2-07 价值主张与核心卖点。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d207": {
+      "name": "D2-07 价值主张与核心卖点",
+      "text": "【D2-07 价值主张与核心卖点】\n承接:候选机会清单 V2.0 + D2-02 痛点库原话。\n本组主推版本面向的价格带 / 人群 / 场景:(粘贴)。\n\n第一步:写价值主张卡\n- 一句主主张(不超过 20 字,用户能复述);\n- 三条收益(用户能感知到的好处,不是工艺参数);\n- 三条证据(对应组件 / 原话 / 商品事实,带 ID);\n- 证据边界:能说什么 / 不能说什么 / 合规标示。\n\n第二步:卖点清单,按价格带 × 人群 × 场景各 2–3 个版本。\n要求:\n- 每一句卖点都要对到一条原话或一个商品事实;\n- 研发术语(非油炸、热风三段控温、含水 8–12%)翻译成市场语言,必要时保留一个“技术背书”小注;\n- 「健康 / 减脂 / 养胃」等功效宣称在无合规依据时一律不写;\n- 标出让本组删掉的那些版本,并说明为什么删(例如「技术上说得过去但做不到」)。\n\n最后输出:价值主张卡 + 卖点清单(主推版 + 备选版 + 不能说的话)。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出影响 D2-08 的具体缺口)\n【下一步】接下来要做 D2-08 概念提案与分享。请先回答:___(只问一个会改变结论的问题)"
+    },
+    "d208": {
+      "name": "D2-08 概念提案与分享",
+      "text": "【D2-08 概念提案与分享】\n承接:候选机会清单 V2.0 + 回推表 + 价值主张卡 + 卖点清单。\n\n请按「结论 → 依据 → 风险 → 行动」串成一份提案,并生成三个版本:\n- 一句话版(决策圈用,不超过 40 字,说清做什么、为什么现在、要什么资源);\n- 一页版(协同圈用,5 页以内);\n- 全案版(归档用)。\n\n同时输出:\n1. 质询清单:决策圈 / 协同圈 / 生态圈各 3 个最可能问到的问题,标出哪些本组能答、哪些答不出;\n2. 矛盾清单:三段分析互相打架的地方,都保留下来,不要删;\n3. 候选清单 V3.0:质询后更新版本,记录每处修改理由;\n4. 成果导航:13 份产出物各自的保存位置、一句话用途、结营后第一周先看哪一份。\n\n要求:只做减法,每条留给结论的都是支撑结论的那几条证据。示意图类内容标注「生成示意,需设计确认」,不出现任何真实品牌 Logo。\n\n【推送格式】结束本环节时,在回复最后用这三行总结:\n【本轮产出】你手上有:___\n【还缺什么】___(指出结营后第一周最该补的那个缺口)\n【下一步】结营后第一周陪练:拿 V3.0 回来先补一个「答不出」的问题。请先回答:___(只问一个会改变结论的问题)"
+    }
+  }
+}

+ 34 - 0
docs/workshop-v3-skill-manual-release-20261112/README.md

@@ -0,0 +1,34 @@
+# Skill r15-local.3、v3 手册与账号关联发行
+
+本次按用户要求先修复账号与报告身份,再发行最新 Skill/v3 手册。其他看板界面改动留在本地。
+
+## 已完成
+
+- 生产定向更新4个云函数,新增ksfWorkshopAccount;不改表结构/ACL/账号,不部署看板静态文件。
+- 果鹏guopeng的旧参与者关联到注册账号;匿名公开接口、分组接口与真实浏览器的成员页/小组成果页均为27人,果鹏一人且挂原报告JLF4v5MpyR。原报告整条记录深比较不变,旧参与者键保留。
+- 首次调用先确认称呼和账号,经本人平台登录确认后绑定;未绑定/账号不存在/跨企业/冲突拒绝提交。后续会话/课题/档案别名均投影至同一注册成员。
+- v3手册及13段原提示词保留;首次身份归属规则由Skill落实,不改刘总教学内容。
+
+## 固定交付
+
+| 对象 | SHA256 |
+|---|---|
+| final-康师傅工作坊.skill,374834 B,55个公开文件 | c7fc15321281064deec680f30451757218b393796de8085650f7def178c6764d |
+| SKILL.md,r15-local.3 | b798b417de70c0d9c15d1eefe72ca069179bb3d2686402399f3aa4e3830c103b |
+| ksf-secure.mjs | 25e42387ea9e3cbf5b60c431eaaf09bc381dcc04acbb82d0f0a7dd071f357fea |
+
+入口维护源为skills/ksf-workshop-runtime/final-SKILL.md;完整包在docs/workshop-final-files-20261111/。逐文件指纹见release.json。
+
+## 运维上线范围
+
+使用本次固定源码提交,更新kangshifu/workshop-config中的Skill payload、final别名、v3手册、提示词及相应版本/清单,保留VOC 0.3.45和当前组织库适配器。普通提交推送并回读;按固定组织提交刷新fmode01映射,再受控升级agent-node-kangshifu。保留所有私有凭据、信封、Matrix/企微、员工/Agent档案、研究通道与其他技能。
+
+本次新增scripts/ksf-account.mjs及account-prepare/account-status命令,ksf-secure.mjs新增该独立入口的哈希校验,ksf-identity.mjs补私有绑定字段脱敏。ksf-workshop.mjs及旧ksf.mjs保持原冻结字节。旧安装器固定旧wrapper哈希,因此旧升级套件18项在RUNTIME_BASELINE_MISMATCH停止;不要关闭保护或使用旧安装器强装。当前组织库采用清单驱动适配器,需核实已知旧基线后将本次明确的新文件/哈希纳入发行。
+
+空闲后只受控重载gateway-default。核安装包全部55个公开文件,再从真实网关任务读取r15-local.3、入口哈希及首次账号绑定规则;核workshop-contract.accountBinding.enabled与新命令受控连通。果鹏旧档案应复用现有profileKey,勿删旧报告或再建成员。
+
+## 如实边界
+
+本机企业组织库现有Git身份返回HTTP403,也无已授权容器运维通道。源码库推送不等于组织库或数字人已升级;后两项等待运维回执。首次绑定页面的登录交互仅做合成响应版式测试,本人登录确认仍待真实首次使用验证;匿名确认已实测401,未伪造员工会话。
+
+验证:工作坊124项通过;绑定/身份/凭据31项通过;分组与平台认证24项通过。静态检查与浏览器结果见对应回执。生产曾因补丁误带旧版未定义bootstrap调用而返回错误,已立即回退、缩小补丁并重新发布;最终线上复验通过。完整私有备份仅在work/account-binding-private,不入库。

+ 268 - 0
docs/workshop-v3-skill-manual-release-20261112/release.json

@@ -0,0 +1,268 @@
+{
+  "schema": "ksf.skill-manual-release.v1",
+  "date": "2026-11-12",
+  "skillVersion": "r15-local.3",
+  "publicFileCount": 55,
+  "publicFiles": [
+    {
+      "file": "SKILL.md",
+      "sha256": "b798b417de70c0d9c15d1eefe72ca069179bb3d2686402399f3aa4e3830c103b"
+    },
+    {
+      "file": "references/business-data-dictionary.json",
+      "sha256": "11863b16216f8746f24189444fc5ffd40512d313cfddd6fa99111b84ac3acfc2"
+    },
+    {
+      "file": "references/full-schema-and-intake.md",
+      "sha256": "08859f32fa51399c638cb9cc0669e69f53a630ebdfa0ad965b1d360115b3a901"
+    },
+    {
+      "file": "references/identity.md",
+      "sha256": "1f7ee67333604603497494e4247d28987db0fab0b80913eae8d5e06246ba558d"
+    },
+    {
+      "file": "references/research-library/data-contract.md",
+      "sha256": "a9af25da32e769443af4565ca400c9136745c9d30c2c190dedf978841bf977c1"
+    },
+    {
+      "file": "references/research-library/full-schema-and-intake.md",
+      "sha256": "78dedd84d8560ee3f0492769db81562841193fa40bef7028836745b0958ab6b8"
+    },
+    {
+      "file": "references/research-library/operations.md",
+      "sha256": "a154e01d3f3efb47f643c27adf22fe963d507dc68a50f8747e8ffda8bb7180bb"
+    },
+    {
+      "file": "references/research-library/product-overview-and-intake.md",
+      "sha256": "fe3462b121fc3f8d5ec0392f68229c463e05a5b3bed985b3d356a1b975f5602e"
+    },
+    {
+      "file": "references/research-library/query-rules.md",
+      "sha256": "3de4f2aeca43792a37e2d514defebf641b80db11639853ff60e48843dc3405bd"
+    },
+    {
+      "file": "references/research-library/research-data-dictionary.json",
+      "sha256": "270b998fca0d4dcd0ad53ff0bc7e2b5a11f88016133965053cf54f5a50bc525f"
+    },
+    {
+      "file": "references/research-library/retrieval-rules.md",
+      "sha256": "c00b9a1520866f36f1f4bf26865ee20b4e461d5a998447136bce31cc42fc9b7f"
+    },
+    {
+      "file": "references/workshop-analysis.md",
+      "sha256": "c41219e3f0d48dd687af253475f6971f4929e650450bad7995ffd60770208de6"
+    },
+    {
+      "file": "references/workshop-autonomous-research.md",
+      "sha256": "5af981a8a10acc39470482a09397ea26e8be42d1416efff1e6b2e2baf3bd797f"
+    },
+    {
+      "file": "references/workshop-category-scan.md",
+      "sha256": "b2c6aa939aa4801c77146430f099d3973bf5961cc9291d03a345a9d6a4fe74f6"
+    },
+    {
+      "file": "references/workshop-commercial-feasibility.md",
+      "sha256": "c75a97ec3d31ed626d7e447d3621351a966eb7f953cc7aa7eee5a40a7a71ebec"
+    },
+    {
+      "file": "references/workshop-competitor-landscape.md",
+      "sha256": "d67158d7294bb0581489e01182d0a5fafd121bf6a2fced5a0926263cdfb0dbaf"
+    },
+    {
+      "file": "references/workshop-concept-presentation.md",
+      "sha256": "464977265ed0cd1367f6f478a318ab115738af22793e0b97c4930b4f52d5e694"
+    },
+    {
+      "file": "references/workshop-course-flow.md",
+      "sha256": "85c29ea6798868d5515386e73cc008a228b45a19aa9d072bf4217781207f4300"
+    },
+    {
+      "file": "references/workshop-deliverable-contracts.md",
+      "sha256": "5966a9efd787ab86eae6b78dd28634a6130f2e4dfba3509a7716a67201dfbfc5"
+    },
+    {
+      "file": "references/workshop-delivery.md",
+      "sha256": "8dff9e307769f5cd40f10115dabe02d68ae678de5398db5d5fdaef7bddba073f"
+    },
+    {
+      "file": "references/workshop-dialogue.md",
+      "sha256": "27498cf6b48a8fe3f28aab88c9d5e1fabb5357570a15a06f313d4db9c1c694b6"
+    },
+    {
+      "file": "references/workshop-evidence-counting.md",
+      "sha256": "b741b244f1a1c3cce205aa0c92ac12bd303f015f4bf9ffda87ec520141508e8a"
+    },
+    {
+      "file": "references/workshop-feedback.md",
+      "sha256": "e6613c6f55858f326c2fed5b9b61d6b376871c92b9216d1c9155cb4ed79bac3c"
+    },
+    {
+      "file": "references/workshop-innovation-reasoning.md",
+      "sha256": "19de27e102f8ed0c00c4a1457e7b1902680f2c79201dc274ad22ae66301a1c12"
+    },
+    {
+      "file": "references/workshop-intake.md",
+      "sha256": "13345a8a554256d94db730bae70701be02c3d2a7becf8c7c12b44909cb88465e"
+    },
+    {
+      "file": "references/workshop-opportunity-discovery.md",
+      "sha256": "0c413a47ef1dfbc496280c29a4141568b1a28c58ad3dc92509336748ba2480ec"
+    },
+    {
+      "file": "references/workshop-opportunity-validation.md",
+      "sha256": "db66616e1011e2855d920725242e4a6af086f315e38310efd11f89d5cb2b3453"
+    },
+    {
+      "file": "references/workshop-output-navigation.md",
+      "sha256": "1498f3d19f42ee921ef45559fce7d63e9c7fd5c3062c79d489814cdb96d0a412"
+    },
+    {
+      "file": "references/workshop-report-design.md",
+      "sha256": "d2b02e0ea74e35a32994e5ac11beeccf1c48f4b0903a6ce4e425fdc3e92af7ad"
+    },
+    {
+      "file": "references/workshop-report-parity.md",
+      "sha256": "4df8aaeb0a9587c4b987a5902c6ab3e91b5307daee5c7978eeb6d68b83c6b5e2"
+    },
+    {
+      "file": "references/workshop-research-acceptance.md",
+      "sha256": "26a2fdcae8631a0a66d41d159442525f950835b6057bd1475b4d131f97a10aba"
+    },
+    {
+      "file": "references/workshop-research-loop.md",
+      "sha256": "c480f229baf5d3d84b145649f9cf8a992a2bb7c4a44e2baf11ccedf530eb6786"
+    },
+    {
+      "file": "references/workshop-research-tasking.md",
+      "sha256": "f8b7fbb72b57ae088c411e510dd2cd371aac98d10903a0b4b6e2ce16caae4a51"
+    },
+    {
+      "file": "references/workshop-tasks.md",
+      "sha256": "a4e0bc238966ea7a119986f383f4f6ea99dd8d9de63bdc32571a35b740d8f96d"
+    },
+    {
+      "file": "references/workshop-three-source-opportunities.md",
+      "sha256": "e0200259e92644bf55ca2fe3f60b1eea4c7df512b1300f2643b8b6991ebc6ca3"
+    },
+    {
+      "file": "references/workshop-v3-outputs.md",
+      "sha256": "3d9855fccf3250c54317e7bb4060d3185e77e61be82c0494df5fb1d21d67fee2"
+    },
+    {
+      "file": "references/workshop-value-proposition.md",
+      "sha256": "1589247eade7243f430be161ed987ecbddf9eb9fdcf1873a5d1f5a141ac89c05"
+    },
+    {
+      "file": "references/workshop-verification.md",
+      "sha256": "01451f1565983eba85f26d3403b35f67c19cf501b5b5da29f52270dc68fd55f6"
+    },
+    {
+      "file": "references/workshop-voc-clustering.md",
+      "sha256": "d1c04203dde6a7eb424b2316a13964d2d63a6e91836dd5c1eef55f858f59fe02"
+    },
+    {
+      "file": "references/write-tasks.md",
+      "sha256": "a685c3a1c2b907e19cc7e94e42325012a82e09978e267219a0938a42fb9beace"
+    },
+    {
+      "file": "runtime-lock.json",
+      "sha256": "2605cbe8fd7be43b5969a4991f978dc0768dee5b4d65d18f7af15f75e9004a79"
+    },
+    {
+      "file": "scripts/course-assessment.mjs",
+      "sha256": "7ad2aebd30fbc244f4617c9559f076ff7df4196901a31465b5a70bfe5055bb55"
+    },
+    {
+      "file": "scripts/course-deliverables.mjs",
+      "sha256": "7200354296d2b605247ac0cd41927e55fd741f5dd29beb1387b92373f88df617"
+    },
+    {
+      "file": "scripts/describe-business-schema.mjs",
+      "sha256": "e96e8c3fc1a71f1edc39dfc250199aacfb1457aec851d29e6f3b2c35e918a279"
+    },
+    {
+      "file": "scripts/ksf-account.mjs",
+      "sha256": "9bfda45c53192d70fefb31b378851aeb19e075b6f5adcd8217ba4838cc133f7d"
+    },
+    {
+      "file": "scripts/ksf-identity-bridge.mjs",
+      "sha256": "6ba3f0cb6527bc4a0a6218a898472ac65aa3dd9f3f57b597d77efcee641a7540"
+    },
+    {
+      "file": "scripts/ksf-identity.mjs",
+      "sha256": "ab6838afd140e4b84ef39a255fcbdd80ece9b0b7c245f65cd8ba81d892036513"
+    },
+    {
+      "file": "scripts/ksf-secure.mjs",
+      "sha256": "25e42387ea9e3cbf5b60c431eaaf09bc381dcc04acbb82d0f0a7dd071f357fea"
+    },
+    {
+      "file": "scripts/ksf-workshop.mjs",
+      "sha256": "7a04eb22d3429cdced23513717f36594f639539738994d45712a8bea738100a1"
+    },
+    {
+      "file": "scripts/ksf.mjs",
+      "sha256": "7ef128f7d022bfbc15c0ec813bfd87995c6297c6efe407a563c840f014aba477"
+    },
+    {
+      "file": "scripts/render-report-html.mjs",
+      "sha256": "246588294da6975d80d0f1b1e338bc30cf737421c43cea38cf33745eb52e40a9"
+    },
+    {
+      "file": "scripts/report-contract.mjs",
+      "sha256": "4c6e05ca3f6e65d57d55f743de39307181f8427626e355a5d2698905c17dd8c4"
+    },
+    {
+      "file": "scripts/report-statistics.mjs",
+      "sha256": "ede7e98ee941e4ca2ce867d53eb29fa289b9047070e9e6797d20d5d547d24325"
+    },
+    {
+      "file": "scripts/save-report.mjs",
+      "sha256": "022c1833f733ac321ce588ea1dd74e12a1609370f35fe3749c35bf8059a97d17"
+    }
+  ],
+  "skillManifest": {
+    "file": "skills/ksf-workshop-runtime/FILES.sha256",
+    "bytes": 5514,
+    "sha256": "9c3c8fc60af395d6ee808cc33bef26e8f76d9d9588b690655dcfe91ce6ade53e"
+  },
+  "artifacts": [
+    {
+      "file": "docs/workshop-final-files-20261111/final-康师傅工作坊.skill",
+      "bytes": 374834,
+      "sha256": "c7fc15321281064deec680f30451757218b393796de8085650f7def178c6764d"
+    },
+    {
+      "file": "docs/workshop-quality-r13-20261110/final-康师傅工作坊操作手册.html",
+      "bytes": 303679,
+      "sha256": "51d182e50b97143e196e60e62fcc289380abb013d2899239912876f0db18521b"
+    },
+    {
+      "file": "docs/workshop-quality-r13-20261110/manual/workshop-dialogue-prompts.json",
+      "bytes": 19569,
+      "sha256": "a02b29765de4c238540c5c918440fcbdcf44a827a30794b90c5ba46d6f1e1ae0"
+    }
+  ],
+  "boardDeployment": false,
+  "siteDeployment": false,
+  "databaseMigration": false,
+  "organizationSynced": false,
+  "runtimeInstalled": false,
+  "runtimeLoadingVerified": false,
+  "organizationAccess": "current Git identity denied: HTTP 403",
+  "runtimeAccess": "no authorized host connection available in this workspace",
+  "vocPolicy": "preserve existing 0.3.45; do not overwrite with stale enterprise templates",
+  "identityBackendDeployed": true,
+  "identityBindingPageDeployed": true,
+  "guopengHistoricalLinkRepaired": true,
+  "frozenWorkshopEntryUnchanged": true,
+  "secureWrapperChangedForAccountCommands": true,
+  "accountIdentityRedactionUpdated": true,
+  "tests": {
+    "workshop": 124,
+    "identityAndCredentialAndBinding": 31,
+    "memberGroupsAndPlatformAuth": 24,
+    "legacyFrozenUpgradeSuite": "18 failures: pins previous wrapper digest; old installer must not be used for this release; use current organization manifest-driven adapter with known prior and explicit new hashes"
+  },
+  "productionVerification": "docs/account-binding-fix-20261112/live-verification.json"
+}

+ 7 - 1
scripts/build-workshop-skill.mjs

@@ -4,18 +4,24 @@ const root='skills/ksf-workshop-runtime',sha=x=>crypto.createHash('sha256').upda
 // Maintain final-SKILL.md; keep the conventional loader entry synchronized.
 const finalEntry=fs.readFileSync(root+'/final-SKILL.md');
 if(!fs.existsSync(root+'/SKILL.md')||!fs.readFileSync(root+'/SKILL.md').equals(finalEntry))fs.writeFileSync(root+'/SKILL.md',finalEntry);
+// Ship a self-contained browser copy in src/; both renderers use this one maintained source.
+const browserStatistics='// Generated by scripts/build-workshop-skill.mjs; maintain the Skill report-statistics.mjs source.\n'+fs.readFileSync(root+'/scripts/report-statistics.mjs','utf8');
+if(!fs.existsSync('src/core/report-statistics.js')||fs.readFileSync('src/core/report-statistics.js','utf8')!==browserStatistics)fs.writeFileSync('src/core/report-statistics.js',browserStatistics);
+const browserAssessment='// Generated by scripts/build-workshop-skill.mjs; maintain the Skill course-assessment.mjs source.\n'+fs.readFileSync(root+'/scripts/course-assessment.mjs','utf8');
+if(!fs.existsSync('src/core/course-assessment.js')||fs.readFileSync('src/core/course-assessment.js','utf8')!==browserAssessment)fs.writeFileSync('src/core/course-assessment.js',browserAssessment);
 const hash=sha(fs.readFileSync(root+'/scripts/ksf-workshop.mjs'));
 const identityHash=sha(fs.readFileSync(root+'/scripts/ksf-identity.mjs'));
 const file=root+'/scripts/ksf-secure.mjs';
 fs.writeFileSync(file,fs.readFileSync(file,'utf8')
  .replace(/const WORKSHOP_ENTRY_HASH = '[^']+';/,"const WORKSHOP_ENTRY_HASH = '"+hash+"';")
+ .replace(/const ACCOUNT_ENTRY_HASH = '[^']+';/,"const ACCOUNT_ENTRY_HASH = '"+sha(fs.readFileSync(root+'/scripts/ksf-account.mjs'))+"';")
  .replace(/const IDENTITY_MODULE_HASH = '[^']+';/,"const IDENTITY_MODULE_HASH = '"+identityHash+"';"));
 // Keep the declared public package complete; never enumerate local identity/credential files.
 const declared=fs.existsSync(root+'/FILES.sha256')?fs.readFileSync(root+'/FILES.sha256','utf8').trim().split(/\r?\n/).filter(Boolean).map(line=>{
  const match=line.match(/^[a-f0-9]{64}\s+\*?(.+)$/);if(!match||match[1].includes('..')||/^[\\/]|:/.test(match[1]))throw Error('非法公开清单路径');return match[1];
 }).filter(file=>!['references/workshop-dialogue-prompts.json','references/workshop-case-evidence.md'].includes(file)):[];
 const files=[...new Set([...declared,'SKILL.md','references/identity.md','references/workshop-tasks.md','references/write-tasks.md','references/business-data-dictionary.json','references/full-schema-and-intake.md','runtime-lock.json','scripts/describe-business-schema.mjs','scripts/ksf-identity.mjs','scripts/ksf-identity-bridge.mjs','scripts/ksf-secure.mjs','scripts/ksf-workshop.mjs','scripts/ksf.mjs','scripts/report-contract.mjs','scripts/save-report.mjs','references/workshop-report-parity.md'])].sort();
-for (const file of ['references/workshop-dialogue.md','references/workshop-evidence-counting.md','scripts/render-report-html.mjs']) if (!files.includes(file)) files.push(file);
+for (const file of ['references/workshop-dialogue.md','references/workshop-evidence-counting.md','references/workshop-v3-outputs.md','scripts/course-deliverables.mjs','scripts/course-assessment.mjs','scripts/ksf-account.mjs','scripts/render-report-html.mjs','scripts/report-statistics.mjs']) if (!files.includes(file)) files.push(file);
 files.sort();
 const entries=files.map(file=>sha(fs.readFileSync(root+'/'+file))+'  '+file);
 fs.writeFileSync(root+'/FILES.sha256',entries.join('\n')+'\n');

+ 70 - 0
scripts/deploy-account-binding.mjs

@@ -0,0 +1,70 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import crypto from 'node:crypto';
+import {fileURLToPath} from 'node:url';
+const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
+const sha=x=>crypto.createHash('sha256').update(x).digest('hex');
+const source=s=>s.replaceAll('\r\n','\n').replace(/^import .*;\n/gm,'').replace(/^export /gm,'');
+const baseline={
+ ksfStartWorkshopSession:['yKpUay6RDG','08fb43393d88351e50e7b73d296d4675bbc22d266bc73ed22db57446fd702c68'],
+ ksfSaveWorkshopTask:['f0faHuk5Br','5ff81e847857dd869522a065423978fc7744b3a80dad900bd18d58850d3fa531'],
+ ksfGetPublicBoard:['inPfC51rvn','e5067736cd5c5f6d8b2244e2a7757ed23719dc0a85b9b2fba2c0e0b83cc437fb'],
+ ksfGetIngestContract:['dWSrHp4FfQ','84aa7bfd086308f6d59711c4c4cd6e7a068688f7b98c7b4773ba0ef1580a3586']
+};
+export function patchAccountBinding(code){
+ if(code.includes('// KSF_ACCOUNT_BINDING_V1'))return code;
+ let next=code.replaceAll('\r\n','\n');
+ const replace=(a,b)=>{if(next.split(a).length!==2)throw Error('ACCOUNT_PATCH_BASELINE_MISMATCH');next=next.replace(a,b);};
+ replace('attribution:{participantName:p.participant.name,participantKey:',"attribution:{...(participantAccount?.platform==='fmode'?{accountProfileKey:p.participant.key}:{}),participantName:p.participant.name,participantKey:");
+ const bootstrap=fs.readFileSync(path.join(root,'server/src/bootstrap.mjs'),'utf8').replaceAll('\r\n','\n');
+ const page=bootstrap.slice(bootstrap.indexOf("    if(name==='ksfWorkshopAccount'"),bootstrap.indexOf('    attachBoardActionHandlers(app'));
+ replace("    if(name==='ksfConfirmationPage'){","    attachAccountBindingHandlers(app,{store,settings});\n"+page+"    if(name==='ksfConfirmationPage'){");
+ replace('    const actor=await app.authenticate(request.headers);\n    return response.json',"    const actor=name==='ksfWorkshopAccount'&&params.action==='confirm'\n      ?await app.authenticateWorkshopPlatform(request.headers):await app.authenticate(request.headers);\n    return response.json");
+ next='// KSF_ACCOUNT_BINDING_V1\n'+source(fs.readFileSync(path.join(root,'src/core/workshop-roster.js'),'utf8'))+'\nconst ACCOUNT_LINK_HTML='+JSON.stringify(fs.readFileSync(path.join(root,'server/web/account-link.html'),'utf8').replaceAll('\r\n','\n'))+';\n'+source(fs.readFileSync(path.join(root,'server/src/account-binding.mjs'),'utf8'))+'\n'+next;
+ new Function(next);return next;
+}
+export async function deployAccountBinding({request,apply=false,outDir=path.join(root,'work/account-binding-private')}){
+ const manifest=JSON.parse(fs.readFileSync(path.join(root,'deploy/account-binding-20261112/functions.json'),'utf8'));
+ const plans=[];
+ for(const[name,[id,hash]]of Object.entries(baseline)){
+  const row=await request('GET','/classes/Function/'+id);
+  if(row.name!==name||row.path!=='/'+name)throw Error('FUNCTION_IDENTITY_MISMATCH');
+  const expected=manifest.functions.find(p=>p.name===name);
+  if(!expected||expected.objectId!==id||expected.beforeSha256!==hash||![hash,expected.afterSha256].includes(sha(row.code)))throw Error('UNKNOWN_ACCOUNT_FUNCTION_VERSION');
+  const code=patchAccountBinding(row.code);if(sha(code)!==expected.afterSha256)throw Error('ACCOUNT_PAYLOAD_HASH_MISMATCH');
+  plans.push({row,code});
+ }
+ const name='ksfWorkshopAccount',existing=(await request('GET','/classes/Function?'+new URLSearchParams({where:JSON.stringify({name})}))).results;
+ if(existing.length>1)throw Error('DUPLICATE_ACCOUNT_FUNCTION');
+ const code=plans[0].code.replace('runDatabaseFunction("ksfStartWorkshopSession",request','runDatabaseFunction("ksfWorkshopAccount",request');
+ if(!code.includes('runDatabaseFunction("ksfWorkshopAccount",request'))throw Error('NEW_FUNCTION_HANDLER_MISMATCH');new Function(code);
+ if(sha(code)!==manifest.functions.find(p=>p.name===name)?.afterSha256)throw Error('ACCOUNT_PAYLOAD_HASH_MISMATCH');
+ if(existing[0]&&existing[0].code!==code)throw Error('ACCOUNT_ENDPOINT_ALREADY_EXISTS');
+ plans.push({row:existing[0]||{name,path:'/'+name,ACL:{}},code});
+ const receipt={ok:true,readOnly:!apply,schemaChanges:0,permissionsChanged:false,staticBoardDeployed:false,functions:plans.map(p=>({name:p.row.name,objectId:p.row.objectId||null,beforeSha256:p.row.code?sha(p.row.code):null,afterSha256:sha(p.code),action:p.row.code===p.code?'unchanged':p.row.objectId?'update':'create'}))};
+ if(!apply)return receipt;
+ fs.mkdirSync(outDir,{recursive:true,mode:0o700});
+ const backup=path.join(outDir,'deployment-before-'+crypto.randomUUID()+'.private.json');fs.writeFileSync(backup,JSON.stringify(plans.map(p=>p.row)),{mode:0o600,flag:'wx'});receipt.backup=backup;
+ const done=[];
+ try{
+  // Publish the binding endpoint before enabling the new-session guard.
+  for(const p of [...plans].reverse()){
+   if(p.row.code===p.code)continue;
+   if(p.row.objectId){const current=await request('GET','/classes/Function/'+p.row.objectId);if(current.code!==p.row.code)throw Error('CONCURRENT_FUNCTION_CHANGE');}
+   const route='/classes/Function'+(p.row.objectId?'/'+p.row.objectId:'');
+   const result=await request(p.row.objectId?'PUT':'POST',route,p.row.objectId?{code:p.code}:{...p.row,code:p.code});
+   p.appliedId=p.row.objectId||result.objectId;done.push(p);
+   const read=await request('GET','/classes/Function/'+p.appliedId);
+   if(read.code!==p.code||read.name!==p.row.name||read.path!==p.row.path||JSON.stringify(read.ACL)!==JSON.stringify(p.row.ACL))throw Error('FUNCTION_READBACK_MISMATCH');
+  }
+  receipt.readbackVerified=true;receipt.functions.forEach(p=>{p.objectId||=plans.find(x=>x.row.name===p.name).appliedId;});return receipt;
+ }catch(e){
+  let rollbackComplete=true;
+  for(const p of done.reverse())try{const route='/classes/Function/'+p.appliedId,r=await request('GET',route);if(r.code!==p.code){rollbackComplete=false;continue;}if(p.row.objectId)await request('PUT',route,{code:p.row.code});else await request('DELETE',route);}catch{rollbackComplete=false;}
+  throw Object.assign(Error('ACCOUNT_DEPLOYMENT_STOPPED'),{receipt:{...receipt,ok:false,rollbackComplete}});
+ }
+}
+if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
+ try{if(!['plan','apply'].includes(process.argv[2])||process.argv.length!==3)throw Error('USAGE_PLAN_OR_APPLY');const{request}=await import('../server/scripts/platform-client.mjs');const r=await deployAccountBinding({request,apply:process.argv[2]==='apply'});fs.mkdirSync(path.join(root,'work/account-binding-private'),{recursive:true,mode:0o700});fs.writeFileSync(path.join(root,'work/account-binding-private/deploy-'+process.argv[2]+'.json'),JSON.stringify(r,null,2),{mode:0o600});console.log(JSON.stringify(r,null,2));}
+ catch(e){console.error(JSON.stringify(e.receipt||{ok:false,error:/^[A-Z_]+$/.test(e.message)?e.message:'ACCOUNT_DEPLOYMENT_STOPPED'}));process.exitCode=1;}
+}

+ 50 - 0
scripts/repair-guopeng-account-link.mjs

@@ -0,0 +1,50 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import crypto from 'node:crypto';
+import {fileURLToPath} from 'node:url';
+import {WORKSHOP_ROSTER} from '../src/core/workshop-roster.js';
+const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
+const sha=x=>crypto.createHash('sha256').update(x).digest('hex');
+const canonical=x=>x&&typeof x==='object'?Array.isArray(x)?'['+x.map(canonical).join(',')+']':'{'+Object.keys(x).sort().map(k=>JSON.stringify(k)+':'+canonical(x[k])).join(',')+'}':JSON.stringify(x);
+export async function repairGuopengLink({request,apply=false,outDir=path.join(root,'work/account-binding-private')}){
+ const sessionId='z-nFIa3y5m',artifactId='JLF4v5MpyR';
+ const [session,artifact]=await Promise.all([request('GET','/classes/KfSession/'+sessionId),request('GET','/classes/KfArtifact/'+artifactId)]);
+ const audit=JSON.parse(fs.readFileSync(path.join(root,'docs/board-login-20261111/account-verification.json')));
+ const account=audit.results.find(r=>r.username==='guopeng'),m=WORKSHOP_ROSTER.members.find(r=>r.username==='guopeng');
+ if(audit.appId!=='ncloudmaster'||audit.expectedCompanyObjectId!=='FKieRbIoGt'||!account?.loginOk||!account.companyMatched||!account.profileNameMatched||m.id!=='platform-account:'+sha(JSON.stringify(['ncloudmaster','FKieRbIoGt',account.userId])))throw Error('ACCOUNT_AUDIT_MISMATCH');
+ const a=session.meta?.attribution;
+ if(artifact.sessionRef?.objectId!==sessionId||artifact.title!=='居家囤货|D1-01 品类全景扫描'||a?.participantAccount?.platform!=='fmode'||a.participantAccount.tenantId!=='FKieRbIoGt'||a.participantAccount.accountName!=='guopeng'||a.participantAccount.accountId!=='guopeng'||artifact.meta?.attribution?.participantKey!==a.participantKey)throw Error('REPAIR_TARGET_MISMATCH');
+ const profileKey='participant-account:'+sha(canonical({kind:'channel_account',platform:'fmode',tenantId:'FKieRbIoGt',id:'guopeng'}));
+ if(a.participantKey!=='participant:'+sha(canonical([session.workshopKey,profileKey])))throw Error('ORIGINAL_PROFILE_KEY_MISMATCH');
+ const key='workshop-account-alias:'+sha(canonical([session.meta.ownerId,profileKey]));
+ const rows=(await request('GET','/classes/KsfRuntimeConfig?'+new URLSearchParams({where:JSON.stringify({key}),limit:'2'}))).results;
+ if(rows.length>1)throw Error('DUPLICATE_BINDING');
+ const prior=rows[0];
+ if(prior&&(prior.value?.binding?.memberKey!==m.id||prior.value?.profileKey!==profileKey||prior.value.ownerId!==session.meta.ownerId))throw Error('EXISTING_ACCOUNT_LINK_CONFLICT');
+ if(a.accountBinding&&a.accountBinding.memberKey!==m.id)throw Error('HISTORICAL_ACCOUNT_LINK_CONFLICT');
+ const binding=prior?.value.binding||a.accountBinding||{schema:'ksf.workshop-account-binding.v1',memberKey:m.id,username:'guopeng',platformUserId:account.userId,companyId:'FKieRbIoGt',displayName:'果鹏',verifiedAt:new Date().toISOString(),source:'verified_historical_repair'};
+ const nextMeta={...session.meta,attribution:{...a,accountProfileKey:profileKey,accountBinding:binding}};
+ const value={schema:binding.schema,ownerId:session.meta.ownerId,profileKey,companyId:'FKieRbIoGt',binding,pending:null};
+ const receipt={ok:true,readOnly:!apply,sessionId,artifactId,memberKey:m.id,participantKeyPreserved:true,reportContentHash:sha(canonical(artifact)),reportWrites:0,accountChanges:0,sessionChange:canonical(session.meta)!==canonical(nextMeta),aliasChange:!prior};
+ if(!apply)return receipt;
+ fs.mkdirSync(outDir,{recursive:true,mode:0o700});const backup=path.join(outDir,'repair-before-'+crypto.randomUUID()+'.private.json');fs.writeFileSync(backup,JSON.stringify({session,artifact,alias:prior||null}),{mode:0o600,flag:'wx'});receipt.backup=backup;
+ let aliasId=prior?.objectId,sessionWritten=false,createdAlias=false;
+ try{
+  if(!prior){const result=await request('POST','/classes/KsfRuntimeConfig',{key,value,ACL:{}});aliasId=result.objectId;createdAlias=true;}
+  const current=await request('GET','/classes/KfSession/'+sessionId);if(canonical(current)!==canonical(session))throw Error('SESSION_CHANGED_CONCURRENTLY');
+  if(receipt.sessionChange){await request('PUT','/classes/KfSession/'+sessionId,{meta:nextMeta});sessionWritten=true;}
+  const[read,report,alias]=await Promise.all([request('GET','/classes/KfSession/'+sessionId),request('GET','/classes/KfArtifact/'+artifactId),request('GET','/classes/KsfRuntimeConfig/'+aliasId)]);
+  if(canonical(read.meta)!==canonical(nextMeta)||canonical(report)!==canonical(artifact)||canonical(alias.value)!==canonical(value))throw Error('REPAIR_READBACK_MISMATCH');
+  for(const k of Object.keys(session).filter(k=>!['meta','updatedAt'].includes(k)))if(canonical(read[k])!==canonical(session[k]))throw Error('HISTORICAL_SESSION_CHANGED');
+  return{...receipt,readbackVerified:true};
+ }catch(e){
+  let rollbackComplete=true;
+  try{if(sessionWritten){const read=await request('GET','/classes/KfSession/'+sessionId);if(canonical(read.meta)===canonical(nextMeta))await request('PUT','/classes/KfSession/'+sessionId,{meta:session.meta});else rollbackComplete=false;}}catch{rollbackComplete=false;}
+  try{if(createdAlias){const read=await request('GET','/classes/KsfRuntimeConfig/'+aliasId);if(canonical(read.value)===canonical(value))await request('DELETE','/classes/KsfRuntimeConfig/'+aliasId);else rollbackComplete=false;}}catch{rollbackComplete=false;}
+  throw Object.assign(Error('REPAIR_STOPPED'),{receipt:{...receipt,ok:false,rollbackComplete}});
+ }
+}
+if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
+ try{if(!['plan','apply'].includes(process.argv[2])||process.argv.length!==3)throw Error('USAGE_PLAN_OR_APPLY');const{request}=await import('../server/scripts/platform-client.mjs');const r=await repairGuopengLink({request,apply:process.argv[2]==='apply'});fs.mkdirSync(path.join(root,'work/account-binding-private'),{recursive:true,mode:0o700});fs.writeFileSync(path.join(root,'work/account-binding-private/repair-'+process.argv[2]+'.json'),JSON.stringify(r,null,2),{mode:0o600});console.log(JSON.stringify(r,null,2));}
+ catch(e){console.error(JSON.stringify(e.receipt||{ok:false,error:/^[A-Z_]+$/.test(e.message)?e.message:'REPAIR_STOPPED'}));process.exitCode=1;}
+}

+ 53 - 0
scripts/sync-workshop-manual-v3.mjs

@@ -0,0 +1,53 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import crypto from 'node:crypto';
+import vm from 'node:vm';
+import { fileURLToPath } from 'node:url';
+
+const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
+const evidence = path.join(root, 'docs/workshop-v3-alignment-20261112');
+const target = path.join(root, 'docs/workshop-quality-r13-20261110/final-康师傅工作坊操作手册.html');
+const promptsFile = path.join(path.dirname(target), 'manual/workshop-dialogue-prompts.json');
+const sha = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
+const source = fs.readFileSync(path.join(evidence, 'source-manual-v3.html'));
+const sourceSha256 = sha(source);
+if (sourceSha256 !== 'e8ed9dbd979c17f5caa88fb820f64f94a2e54518f810d7482b6b82f39d88041d') throw Error('V3_SOURCE_CHANGED');
+const url = 'https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html';
+const sourceText = source.toString('utf8');
+const promptBlock = sourceText.match(/window\.PROMPTS\s*=\s*(\{[\s\S]*?\n\});/);
+if (!promptBlock) throw Error('V3_PROMPTS_NOT_FOUND');
+const prompts = vm.runInNewContext('(' + promptBlock[1] + ')', {}, { timeout: 1000 });
+const archived = JSON.parse(fs.readFileSync(path.join(evidence, 'source-prompts-v3.json'), 'utf8'));
+if (JSON.stringify(prompts) !== JSON.stringify(archived.prompts) || Object.keys(prompts).length !== 13) throw Error('V3_PROMPTS_DIFFER');
+// Preserve in-page anchors; resolve only the overview links for the local final filename.
+const linked = sourceText.replaceAll('href="../overview/index.html"',
+  'href="https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/overview/index.html"');
+if (linked === sourceText) throw Error('OVERVIEW_LINK_NOT_FOUND');
+// Some source tables lack the existing scroll wrapper; preserve their content and columns.
+const responsiveTables = `<script id="ksf-v3-responsive-tables">
+document.querySelectorAll('table.tbl').forEach(function(table) {
+  if (table.closest('.tbl-scroll')) return;
+  var wrapper = document.createElement('div');
+  wrapper.className = 'tbl-scroll';
+  wrapper.tabIndex = 0;
+  wrapper.setAttribute('role', 'region');
+  wrapper.setAttribute('aria-label', '表格,可横向滚动');
+  table.before(wrapper);
+  wrapper.appendChild(table);
+});
+</script>\n`;
+const html = linked.replace('</body>', responsiveTables + '</body>');
+const backup = path.join(evidence, 'retired-manual-before-v3');
+fs.mkdirSync(backup, { recursive: true });
+for (const file of [target, promptsFile]) {
+  const name = path.join(backup, path.basename(file));
+  if (!fs.existsSync(name)) fs.copyFileSync(file, name);
+}
+fs.writeFileSync(target, html);
+fs.writeFileSync(promptsFile, JSON.stringify({ schema: 'ksf.workshop-prompts.v3', source: url, sourceSha256, prompts }, null, 2) + '\n');
+const receipt = { ok: true, source: url, sourceSha256, finalManualSha256: sha(Buffer.from(html)),
+  finalManualBytes: Buffer.byteLength(html), promptCount: 13, teachingContentChanged: false,
+  adjustment: 'absolute overview links and scroll wrappers for unwrapped tables; all teaching text and prompts preserved',
+  oldManualArchived: true, deployed: false };
+fs.writeFileSync(path.join(evidence, 'manual-sync.json'), JSON.stringify(receipt, null, 2) + '\n');
+console.log(JSON.stringify(receipt, null, 2));

+ 2 - 2
server/scripts/build.mjs

@@ -5,10 +5,10 @@ import crypto from 'node:crypto';
 const ROOT=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
 const data=JSON.parse(fs.readFileSync(path.join(ROOT,'references/runtime-data.json'),'utf8'));
 fs.mkdirSync(path.join(ROOT,'dist'),{recursive:true});
-const common=[path.join(ROOT,'../skills/ksf-workshop-runtime/scripts/report-contract.mjs'),...['postgres.mjs','files.mjs','core.mjs','confirmation.mjs','workshop.mjs','board-actions.mjs','bootstrap.mjs'].map(file=>path.join(ROOT,'src',file))].map(file=>fs.readFileSync(file,'utf8').replace(/^import .*;\r?\n/gm,'').replace(/^export /gm,'')).join('\n');
+const common="const ACCOUNT_LINK_HTML = "+JSON.stringify(fs.readFileSync(path.join(ROOT,'web/account-link.html'),'utf8'))+";\n"+fs.readFileSync(path.join(ROOT,'../src/core/workshop-roster.js'),'utf8').replace(/^export /gm,'')+'\n'+[path.join(ROOT,'../skills/ksf-workshop-runtime/scripts/report-contract.mjs'),...['postgres.mjs','files.mjs','core.mjs','confirmation.mjs','workshop.mjs','account-binding.mjs','board-actions.mjs','bootstrap.mjs'].map(file=>path.join(ROOT,'src',file))].map(file=>fs.readFileSync(file,'utf8').replace(/^import .*;\r?\n/gm,'').replace(/^export /gm,'')).join('\n');
 const helpers={ksfUploadFile:'/ksf/upload',ksfReadFile:'/ksf/file',ksfConfirmationPage:'/ksf/confirm',ksfCreateReportPreview:'/ksfCreateReportPreview',ksfGetReportPreview:'/ksfGetReportPreview',ksfEmployeeConfirmation:'/ksfEmployeeConfirmation',ksfGetPreviewConfirmation:'/ksfGetPreviewConfirmation'};
 const html=fs.readFileSync(path.join(ROOT,'web/confirm.html'),'utf8');const manifest=[];
-for(const name of [...new Set([...data.functionNames,...Object.keys(helpers),'ksfCheckDuplicates','ksfStartWorkshopSession','ksfSaveWorkshopTask','ksfSaveWorkshopConcept','ksfGetWorkshopProject','ksfGetPublicBoard','ksfSetPublicOpportunityStatus','ksfRatePublicOpportunity'])]){
+for(const name of [...new Set([...data.functionNames,...Object.keys(helpers),'ksfCheckDuplicates','ksfWorkshopAccount','ksfStartWorkshopSession','ksfSaveWorkshopTask','ksfSaveWorkshopConcept','ksfGetWorkshopProject','ksfGetPublicBoard','ksfSetPublicOpportunityStatus','ksfRatePublicOpportunity'])]){
  const code=common+'\nasync function handler(request,response){return runDatabaseFunction('+JSON.stringify(name)+',request,response,'+JSON.stringify(data)+','+JSON.stringify(html)+');}\n';
  new Function(code); // Syntax check the exact code that will be stored in Function.code.
  fs.writeFileSync(path.join(ROOT,'dist',name+'.js'),code);

+ 155 - 0
server/src/account-binding.mjs

@@ -0,0 +1,155 @@
+import { WORKSHOP_ROSTER } from '../../src/core/workshop-roster.js';
+
+/** Explicit account links, never name-based merging. Original attribution stays intact. */
+export function attachAccountBindingHandlers(app, { store, settings, roster = WORKSHOP_ROSTER, fetchImpl = fetch, now = Date.now }) {
+  const { fail, need, hash, canonical } = app;
+  const schema = 'ksf.workshop-account-binding.v1';
+  const companyId = roster.companyId;
+  const exact = (p, keys) => { if (!p || typeof p !== 'object' || Array.isArray(p) || Object.keys(p).some(k => !keys.includes(k))) fail('VALIDATION_FAILED', '身份请求包含未允许字段'); };
+  const profileKey = key => { if (!/^participant-(?:account:[a-f0-9]{64}|registration:[a-f0-9-]{36})$/.test(key || '')) fail('VALIDATION_FAILED', '员工档案键无效'); return key; };
+  const aliasKey = (owner, key) => 'workshop-account-alias:' + hash(canonical([owner, profileKey(key)]));
+  const memberKey = id => 'platform-account:' + hash(JSON.stringify([roster.platformAppId, companyId, id]));
+  const member = username => {
+    const matches = roster.members.filter(r => r.username === username);
+    if (matches.length !== 1) fail('ACCOUNT_NOT_REGISTERED', '该账号不在工作坊名册,请核对账号或联系管理员');
+    return matches[0];
+  };
+  const read = async (s, key, lock = false) => {
+    const rows = await s.list('KsfRuntimeConfig', { where: { key }, limit: 2, forUpdate: lock });
+    if (rows.length > 1) fail('ACCOUNT_BINDING_CONFLICT', '账号绑定记录冲突,请联系管理员');
+    return rows[0];
+  };
+  const checked = (value, owner, key) => {
+    if (value?.schema !== schema || value.ownerId !== owner || value.profileKey !== key || value.companyId !== companyId) fail('ACCOUNT_BINDING_CONFLICT', '账号绑定归属冲突');
+    return value;
+  };
+  const bindingOf = value => {
+    if (!value?.binding) fail('ACCOUNT_BINDING_REQUIRED', '请先完成本人账号绑定,再保存成果');
+    const b = value.binding, m = member(b.username);
+    if (b.schema !== schema || b.memberKey !== m.id || b.memberKey !== memberKey(b.platformUserId) || b.companyId !== companyId || !['platform_session', 'verified_historical_repair'].includes(b.source)) fail('ACCOUNT_BINDING_CONFLICT', '账号绑定校验失败');
+    return b;
+  };
+  const summary = b => ({ schema, status: 'bound', memberKey: b.memberKey, username: b.username, displayName: b.displayName, companyId, verifiedAt: b.verifiedAt, source: b.source });
+
+  // Called only by the HTTP adapter for confirmation, never from model-supplied params.
+  app.authenticateWorkshopPlatform = async headers => {
+    const h = Object.fromEntries(Object.entries(headers || {}).map(([k,v]) => [k.toLowerCase(),v]));
+    const token = h['x-fmode-session-token'];
+    if (typeof token !== 'string' || !token || token.length > 4000) fail('AUTH_REQUIRED', '请在绑定页面登录本人账号');
+    let response;
+    try { response = await fetchImpl('https://server.fmode.cn/parse/users/me', { headers: { 'X-Parse-Application-Id': roster.platformAppId, 'X-Parse-Session-Token': token }, redirect: 'error', signal: AbortSignal.timeout(10000) }); }
+    catch { fail('ACCOUNT_VERIFICATION_UNAVAILABLE', '暂时无法核验登录,请稍后重试'); }
+    if (!response.ok) fail('AUTH_REQUIRED', '登录已失效,请重新登录');
+    let user; try { user = await response.json(); } catch { fail('ACCOUNT_VERIFICATION_UNAVAILABLE', '登录服务返回不完整'); }
+    if (user.company?.__type !== 'Pointer' || user.company.className !== 'Company' || user.company.objectId !== companyId) fail('COMPANY_FORBIDDEN', '请使用康师傅工作坊账号');
+    const m = member(user.username);
+    if (!user.objectId || memberKey(user.objectId) !== m.id) fail('ACCOUNT_BINDING_CONFLICT', '账号编号与名册不一致,请联系管理员');
+    return { id: user.objectId, kind: 'workshop-platform', username: user.username, memberKey: m.id, companyId };
+  };
+  app.handlers.ksfWorkshopAccount = async (p, actor) => {
+    if (p.action === 'confirm') {
+      exact(p, ['requestId', 'action', 'ticket']);
+      if (actor?.kind !== 'workshop-platform') fail('AUTH_REQUIRED', '必须由本人登录确认绑定');
+      const ticket = app.readReceipt(p.ticket);
+      if (ticket.type !== 'workshop-account-link' || ticket.expiresAt <= now()) fail('ACCOUNT_LINK_EXPIRED', '绑定链接已过期,请回对话重新获取');
+      if (ticket.username !== actor.username) fail('ACCOUNT_BINDING_CONFLICT', '当前登录账号与对话中确认的账号不一致');
+      return store.transaction(async s => {
+        await s.lock(ticket.aliasKey);
+        const row = await read(s, ticket.aliasKey, true);
+        if (!row) fail('ACCOUNT_LINK_EXPIRED', '绑定链接已失效');
+        const v = checked(row.value, ticket.ownerId, ticket.profileKey);
+        if (v.binding) {
+          const b = bindingOf(v);
+          if (b.memberKey !== actor.memberKey) fail('ACCOUNT_BINDING_CONFLICT', '此对话身份已绑定其他账号');
+          return summary(b);
+        }
+        if (v.pending?.nonce !== ticket.nonce || v.pending.expiresAt <= now()) fail('ACCOUNT_LINK_EXPIRED', '绑定链接已更新,请使用最新链接');
+        const m = member(actor.username), b = { schema, memberKey: actor.memberKey, username: actor.username, platformUserId: actor.id, companyId, displayName: v.pending.displayName || m.name, verifiedAt: new Date(now()).toISOString(), source: 'platform_session' };
+        await s.update('KsfRuntimeConfig', row.objectId, { value: { ...v, binding: b, pending: null } });
+        return summary(b);
+      });
+    }
+    exact(p, ['requestId', 'action', 'participantProfileKey', ...(p.action === 'prepare' ? ['username', 'displayName'] : [])]);
+    if (!['prepare', 'status'].includes(p.action)) fail('VALIDATION_FAILED', '身份操作无效');
+    need(actor, p.action === 'prepare' ? 'ingest:write' : 'data:read');
+    const key = profileKey(p.participantProfileKey), alias = aliasKey(actor.id, key);
+    if (p.action === 'status') {
+      const row = await read(store, alias);
+      return row?.value.binding ? summary(bindingOf(checked(row.value, actor.id, key))) : { schema, status: 'unbound', readOnly: true, databaseWrites: 0 };
+    }
+    member(p.username);
+    if (typeof p.displayName !== 'string' || !p.displayName.trim() || [...p.displayName.trim()].length > 40 || /[\p{Cc}\p{Cf}]/u.test(p.displayName)) fail('VALIDATION_FAILED', '请提供1至40字称呼');
+    return store.transaction(async s => {
+      await s.lock(alias);
+      const row = await read(s, alias, true);
+      const v = row ? checked(row.value, actor.id, key) : { schema, ownerId: actor.id, profileKey: key, companyId };
+      if (v.binding) {
+        const b = bindingOf(v);
+        if (b.username !== p.username) fail('ACCOUNT_BINDING_CONFLICT', '此身份已绑定其他账号,不得覆盖');
+        return summary(b);
+      }
+      const pending = { username: p.username, displayName: p.displayName.trim(), nonce: hash(canonical([alias, now(), p.requestId])), expiresAt: now() + 30 * 60000 };
+      const value = { ...v, pending };
+      if (row) await s.update('KsfRuntimeConfig', row.objectId, { value }); else await s.create('KsfRuntimeConfig', { key: alias, value });
+      const ticket = app.signedReceipt({ type: 'workshop-account-link', aliasKey: alias, ownerId: actor.id, profileKey: key, ...pending });
+      return { schema, status: 'awaiting_account_confirmation', username: p.username, expiresAt: new Date(pending.expiresAt).toISOString(), confirmationUrl: settings.functionsUrl + '?path=/ksfWorkshopAccount#ticket=' + encodeURIComponent(ticket) };
+    });
+  };
+  async function resolve(ownerId, key, account) {
+    const row = await read(store, aliasKey(ownerId, key));
+    if (!row) fail('ACCOUNT_BINDING_REQUIRED', '请先完成本人账号绑定,再保存成果');
+    const b = bindingOf(checked(row.value, ownerId, key));
+    if (account?.platform !== 'fmode' || account.tenantId !== companyId || account.accountName !== b.username || ![null,b.username,b.platformUserId].includes(account.accountId ?? null)) fail('ACCOUNT_BINDING_CONFLICT', '提交身份与已绑定账号不一致');
+    return b;
+  }
+  const originalStart = app.handlers.ksfStartWorkshopSession;
+  app.handlers.ksfStartWorkshopSession = async (p, actor) => {
+    if (p.participant?.account?.platform !== 'fmode') return originalStart(p, actor);
+    need(actor, 'ingest:write');
+    const b = await resolve(actor.id, p.participant.key, p.participant.account);
+    const result = await originalStart(p, actor);
+    // The alias is authoritative and immutable; no need to rewrite historical session keys.
+    return { ...result, memberKey: b.memberKey, accountBinding: summary(b) };
+  };
+  const originalSave = app.handlers.ksfSaveWorkshopTask;
+  app.handlers.ksfSaveWorkshopTask = async (p, actor) => {
+    need(actor, 'ingest:write');
+    const session = await store.get('KfSession', p.sessionId);
+    const a = session?.meta?.attribution;
+    if (a?.participantAccount?.platform === 'fmode') await sessionBinding(session);
+    return originalSave(p, actor);
+  };
+  async function sessionBinding(session) {
+    const a = session?.meta?.attribution;
+    if (!a || a.participantAccount?.platform !== 'fmode') return null;
+    // Stored full binding is used only for the narrowly audited historical repair.
+    if (a.accountBinding) return bindingOf({ binding: a.accountBinding });
+    // The local profile key is part of the original hash; start records it privately.
+    if (!a.accountProfileKey) fail('ACCOUNT_BINDING_REQUIRED', '旧会话需要核对账号关联,请联系管理员');
+    return resolve(session.meta.ownerId, a.accountProfileKey, a.participantAccount);
+  }
+  const originalBoard = app.handlers.ksfGetPublicBoard;
+  app.handlers.ksfGetPublicBoard = async (p, actor) => {
+    const board = await originalBoard(p, actor), cached = new Map();
+    async function lookup(id) {
+      if (!id) return null;
+      if (!cached.has(id)) cached.set(id, (async () => {
+        const row = await store.get('KfSession', id);
+        if (!row || row.recordState === 'archived') return null;
+        try { return await sessionBinding(row); } catch (e) { if (e.code === 'ACCOUNT_BINDING_REQUIRED') return null; throw e; }
+      })());
+      return cached.get(id);
+    }
+    for (const kind of ['session','artifact','project','opportunity']) for (const row of board[kind] || []) {
+      const id = kind === 'session' ? row.objectId : row.sessionRef?.objectId || row.ownerSession || row.sourceSession;
+      const b = await lookup(id);
+      if (b) row.memberKey = b.memberKey;
+    }
+    return board;
+  };
+  const originalContract = app.handlers.ksfGetIngestContract;
+  app.handlers.ksfGetIngestContract = async (p, actor) => {
+    const r = await originalContract(p, actor);
+    return { ...r, workshop: { ...r.workshop, accountBinding: { schema, enabled: true, requiredFor: ['fmode'], function: 'ksfWorkshopAccount', firstUse: 'confirm-display-name-and-account', proof: 'platform-session', canonicalMember: 'platform-account', oneMemberPerAccount: true, unboundSubmission: 'reject', historicalAttributionPreserved: true } } };
+  };
+}

+ 9 - 1
server/src/bootstrap.mjs

@@ -12,6 +12,13 @@ export async function runDatabaseFunction(name,request,response,DATA,confirmatio
     const files=createFileAdapter({store,crypto,Parse,data:DATA,settings});
     const app=createApplication({store,crypto,Parse,data:DATA,settings,files});attachConfirmationHandlers(app,{store,files,settings,data:DATA});
     attachWorkshopHandlers(app,{store,data:DATA,files});
+    attachAccountBindingHandlers(app,{store,settings});
+    if(name==='ksfWorkshopAccount'&&request.method==='GET'){
+      const nonce=crypto.randomBytes(24).toString('base64');
+      response.setHeader('Content-Security-Policy',"default-src 'none'; script-src 'nonce-"+nonce+"'; style-src 'unsafe-inline'; connect-src 'self' https://server.fmode.cn; base-uri 'none'; form-action 'self'; frame-ancestors 'none'");
+      response.setHeader('Referrer-Policy','no-referrer');
+      return response.type('html').send(ACCOUNT_LINK_HTML.replace('__NONCE__',nonce));
+    }
     attachBoardActionHandlers(app,{store});
     if (typeof attachMemberGroupHandlers === 'function') attachMemberGroupHandlers(app, { store,
       loadBoard: () => readMemberGroupBoard({ url: settings.functionsUrl, appId: DATA.appId }) });
@@ -30,7 +37,8 @@ export async function runDatabaseFunction(name,request,response,DATA,confirmatio
     }
     const params=request.body?.params??request.query?.params??{};
     if(!params||typeof params!=='object'||Array.isArray(params))app.fail('VALIDATION_FAILED','params 必须是对象');
-    const actor=await app.authenticate(request.headers);
+    const actor=name==='ksfWorkshopAccount'&&params.action==='confirm'
+      ?await app.authenticateWorkshopPlatform(request.headers):await app.authenticate(request.headers);
     return response.json({result:await app.dispatch(name,params,actor)});
   }catch(e){
     const known=typeof e.code==='string'&&/^[A-Z][A-Z0-9_]+$/.test(e.code);

+ 1 - 1
server/src/workshop.mjs

@@ -69,7 +69,7 @@ export function attachWorkshopHandlers(app,{store,data,files}) {
       }
       if(p.participant.userId&&!await s.get('_User',p.participant.userId))fail('REFERENCE_NOT_FOUND','实际账号不存在;不能创建模拟员工');
       if(p.conversation.messageCount!==undefined&&(!Number.isInteger(p.conversation.messageCount)||p.conversation.messageCount<0))fail('VALIDATION_FAILED','messageCount 必须为实际消息计数');
-      const row=await s.create('KfSession',{...metadata(key,p.dataMode),studentName:p.participant.name,groupId:p.groupId||'',workshopKey:p.workshopKey,stageCode:'S1',stage:label('S1'),step:'started',lastActiveAt:now(),...(p.conversation.messageCount!==undefined?{msgCount:p.conversation.messageCount}:{}),...(p.participant.userId?{userRef:pointer('_User',p.participant.userId)}:{}),meta:{ownerId:actor.id,workshop:{visibility:'public'},attribution:{participantName:p.participant.name,participantKey:'participant:'+hash(canonical([p.workshopKey,p.participant.key])),identityBasis:p.participant.identityBasis,...(participantAccount?{participantAccount}:{}),agentName:p.agent.name,agentKey:p.agent.key||'name:'+p.agent.name,agentKeyOrigin:agentBasis,...(agentAccount?{agentAccount}:{}),agentRole:p.agent.role??null,agentRuntimePlatform:p.agent.runtimePlatform??null,agentChannel:p.agent.channel??null,agentCollectedAt:p.agent.collectedAt??null,agentAccountVerified:false,conversationKey:p.conversation.key,channel:p.conversation.channel}}});
+      const row=await s.create('KfSession',{...metadata(key,p.dataMode),studentName:p.participant.name,groupId:p.groupId||'',workshopKey:p.workshopKey,stageCode:'S1',stage:label('S1'),step:'started',lastActiveAt:now(),...(p.conversation.messageCount!==undefined?{msgCount:p.conversation.messageCount}:{}),...(p.participant.userId?{userRef:pointer('_User',p.participant.userId)}:{}),meta:{ownerId:actor.id,workshop:{visibility:'public'},attribution:{...(participantAccount?.platform==='fmode'?{accountProfileKey:p.participant.key}:{}),participantName:p.participant.name,participantKey:'participant:'+hash(canonical([p.workshopKey,p.participant.key])),identityBasis:p.participant.identityBasis,...(participantAccount?{participantAccount}:{}),agentName:p.agent.name,agentKey:p.agent.key||'name:'+p.agent.name,agentKeyOrigin:agentBasis,...(agentAccount?{agentAccount}:{}),agentRole:p.agent.role??null,agentRuntimePlatform:p.agent.runtimePlatform??null,agentChannel:p.agent.channel??null,agentCollectedAt:p.agent.collectedAt??null,agentAccountVerified:false,conversationKey:p.conversation.key,channel:p.conversation.channel}}});
       return{sessionId:row.objectId,participantKey:row.meta.attribution.participantKey,agentName:p.agent.name,reused:false};
     });
   };

+ 24 - 0
server/test/account-binding-deploy.test.mjs

@@ -0,0 +1,24 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import {patchAccountBinding} from '../../scripts/deploy-account-binding.mjs';
+const base=`
+function attachWorkshopHandlers(app){const meta={attribution:{participantName:p.participant.name,participantKey:'x'}};}
+async function runDatabaseFunction(name,request,response,DATA,confirmationHtml){
+    if(name==='ksfConfirmationPage'){
+      return response.type('html').send(confirmationHtml);
+    }
+    const actor=await app.authenticate(request.headers);
+    return response.json({result:await app.dispatch(name,{},actor)});
+}
+async function handler(request,response){return runDatabaseFunction("ksfStartWorkshopSession",request,response,{},'');}
+`;
+test('补丁保留现网独立包装,只添加账号关联模块;不带入其他bootstrap调用',()=>{
+ const code=patchAccountBinding(base);
+ assert.ok(code.includes("attachAccountBindingHandlers(app,{store,settings});"));
+ assert.ok(!code.includes('attachBoardActionHandlers(app'));assert.ok(!code.includes('attachMemberGroupHandlers(app'));
+ assert.ok(code.includes("accountProfileKey:p.participant.key"));assert.equal(patchAccountBinding(code),code);
+ new Function(code);
+});
+test('缺少精确补丁锚点时在任何远程写入前停止',()=>{
+ assert.throws(()=>patchAccountBinding(base.replace("if(name==='ksfConfirmationPage')", "if(name==='another')")),/BASELINE/);
+});

+ 70 - 0
server/test/account-binding.test.mjs

@@ -0,0 +1,70 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import crypto from 'node:crypto';
+import fs from 'node:fs';
+import { createApplication } from '../src/core.mjs';
+import { attachWorkshopHandlers } from '../src/workshop.mjs';
+import { attachAccountBindingHandlers } from '../src/account-binding.mjs';
+import { indexBoardMembers } from '../../src/core/member-groups.js';
+import { WORKSHOP_ROSTER } from '../../src/core/workshop-roster.js';
+const data=JSON.parse(fs.readFileSync(new URL('../references/runtime-data.json',import.meta.url)));
+const audit=JSON.parse(fs.readFileSync(new URL('../../docs/board-login-20261111/account-verification.json',import.meta.url)));
+const service={id:'trusted-service',kind:'service',scopes:['ingest:write','data:read'],projectIds:['*']};
+const key='participant-account:'+'a'.repeat(64),otherKey='participant-account:'+'b'.repeat(64);
+function fixture(){
+ let rows={},seq=0,clock=Date.now(),current=audit.results.find(x=>x.username==='guopeng');
+ let queue=Promise.resolve();
+ const store={async lock(){},async transaction(fn){const run=async()=>{const before=structuredClone(rows);try{return await fn(store);}catch(e){rows=before;throw e;}};const r=queue.then(run);queue=r.catch(()=>{});return r;},
+  async list(name,{where={},limit=10000}={}){return structuredClone((rows[name]||[]).filter(r=>Object.entries(where).every(([k,v])=>JSON.stringify(r[k])===JSON.stringify(v))).slice(0,limit));},
+  async get(name,id){return structuredClone((rows[name]||[]).find(r=>r.objectId===id)||null);},
+  async create(name,p){const r={...structuredClone(p),objectId:'object'+ ++seq};(rows[name]||=[]).push(r);return structuredClone(r);},
+  async update(name,id,p){const r=(rows[name]||[]).find(x=>x.objectId===id);assert.ok(r);Object.assign(r,structuredClone(p));return structuredClone(r);}};
+ const app=createApplication({store,crypto,Parse:{},data,settings:{signingSecret:'fixture'},files:{}});
+ attachWorkshopHandlers(app,{store,data});
+ attachAccountBindingHandlers(app,{store,settings:{functionsUrl:'https://kangshifu.fmode.cn/api/functions'},now:()=>clock,
+  fetchImpl:async(url,options)=>{assert.equal(url,'https://server.fmode.cn/parse/users/me');return{ok:options.headers['X-Parse-Session-Token']==='fixture-session',json:async()=>({objectId:current.userId,username:current.username,company:{__type:'Pointer',className:'Company',objectId:current.companyId||'FKieRbIoGt'}})};}});
+ const call=async(name,p,actor=service)=>(await app.dispatch(name,p,actor)).data;
+ const account=p=>call('ksfWorkshopAccount',{requestId:crypto.randomUUID(),...p});
+ const prepare=(profile=key,username='guopeng')=>account({action:'prepare',participantProfileKey:profile,username,displayName:'果鹏'});
+ const confirm=async link=>call('ksfWorkshopAccount',{action:'confirm',ticket:new URL(link.confirmationUrl).hash.slice(8)},await app.authenticateWorkshopPlatform({'X-Fmode-Session-Token':'fixture-session'}));
+ const start=(profile=key,workshop='topic-one')=>call('ksfStartWorkshopSession',{requestId:crypto.randomUUID(),workshopKey:workshop,participant:{key:profile,name:'果鹏',identityBasis:'existing_record',account:{platform:'fmode',tenantId:'FKieRbIoGt',accountId:current.username,accountName:current.username}},agent:{key:'agent-account:'+'c'.repeat(64),name:'助手',identityBasis:'runtime_config',role:'workshop',runtimePlatform:'hermes',channel:'matrix',account:{platform:'matrix',accountId:'fixture-agent'}},conversation:{key:'fixture-room',channel:'matrix'},dataMode:'live'});
+ return{store,app,call,account,prepare,confirm,start,setUser:user=>current=user,advance:ms=>clock+=ms};
+}
+test('首次绑定必须本人平台会话,未绑定提交被拦截且不创建成员或报告',async()=>{
+ const f=fixture();await assert.rejects(()=>f.start(),{code:'ACCOUNT_BINDING_REQUIRED'});
+ assert.equal((await f.store.list('KfSession')).length,0);
+ const prepared=await f.prepare();assert.equal(prepared.status,'awaiting_account_confirmation');
+ await assert.rejects(()=>f.call('ksfWorkshopAccount',{action:'confirm',ticket:new URL(prepared.confirmationUrl).hash.slice(8)}),{code:'AUTH_REQUIRED'});
+ await assert.rejects(()=>f.app.authenticateWorkshopPlatform({}),{code:'AUTH_REQUIRED'});
+ assert.equal((await f.store.list('KfArtifact')).length,0);
+});
+test('同账号跨课题、会话和档案别名仍27人;报告ID、内容和历史参与键不变',async()=>{
+ const f=fixture(),binding=await f.confirm(await f.prepare());
+ const first=await f.start(),second=await f.start(key,'topic-two');
+ await f.confirm(await f.prepare(otherKey));const third=await f.start(otherKey,'topic-three');
+ assert.equal(new Set([first.memberKey,second.memberKey,third.memberKey]).size,1);
+ const saved=await f.store.create('KfArtifact',{externalKey:'workshop:artifact:fixture',meta:{workshop:{visibility:'public'}},recordState:'active',title:'真实报告原题',rawText:'原文',version:1,ownerSession:first.sessionId,uploadedByKey:first.participantKey,ownerName:'果鹏'});
+ const before=await f.store.get('KfArtifact',saved.objectId),board=await f.call('ksfGetPublicBoard',{},null);
+ const members=indexBoardMembers({...board,member:WORKSHOP_ROSTER.members});
+ assert.equal(members.members.length,27);assert.equal(members.members.filter(m=>m.username==='guopeng').length,1);
+ assert.equal(members.memberId('artifact',board.artifact[0]),binding.memberKey);
+ assert.deepEqual(await f.store.get('KfArtifact',saved.objectId),before);
+ assert.equal(board.artifact[0].uploadedByKey,first.participantKey);
+ assert.ok(!JSON.stringify(board).includes('platformUserId'));assert.ok(!JSON.stringify(board).includes('fixture-room'));
+});
+test('不存在账号、跨企业、同名不同账号及已绑定改绑均不静默合并',async()=>{
+ const f=fixture();await assert.rejects(()=>f.prepare(key,'doesnotexist'),{code:'ACCOUNT_NOT_REGISTERED'});
+ const p=await f.prepare();f.setUser({...audit.results.find(x=>x.username==='guopeng'),companyId:'other-company'});
+ await assert.rejects(()=>f.confirm(p),{code:'COMPANY_FORBIDDEN'});
+ f.setUser(audit.results.find(x=>x.username==='liuna'));await assert.rejects(()=>f.confirm(p),{code:'ACCOUNT_BINDING_CONFLICT'});
+ f.setUser(audit.results.find(x=>x.username==='guopeng'));await f.confirm(p);
+ await assert.rejects(()=>f.prepare(key,'liuna'),{code:'ACCOUNT_BINDING_CONFLICT'});
+ const foreign=await f.account({action:'status',participantProfileKey:otherKey});assert.equal(foreign.status,'unbound');
+});
+test('过期与替换链接失效,绑定重复确认幂等且服务隔离',async()=>{
+ const f=fixture(),old=await f.prepare();f.advance(1);const next=await f.prepare();
+ await assert.rejects(()=>f.confirm(old),{code:'ACCOUNT_LINK_EXPIRED'});
+ const bound=await f.confirm(next);assert.deepEqual(await f.confirm(next),bound);
+ const status=await f.call('ksfWorkshopAccount',{action:'status',participantProfileKey:key},{...service,id:'another-service'});assert.equal(status.status,'unbound');
+ const g=fixture(),expired=await g.prepare();g.advance(31*60000);await assert.rejects(()=>g.confirm(expired),{code:'ACCOUNT_LINK_EXPIRED'});
+});

+ 35 - 0
server/web/account-link.html

@@ -0,0 +1,35 @@
+<!doctype html>
+<html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer">
+<title>确认本人账号 · 康师傅工作坊</title>
+<style>
+*{box-sizing:border-box}body{margin:0;padding:36px 18px;background:#f2f5f9;color:#19304b;font:16px/1.75 system-ui,sans-serif}main{max-width:560px;margin:5vh auto;background:white;border:1px solid #dce4ef;border-radius:24px;padding:32px;box-shadow:0 16px 55px #102d4810}.brand{color:#2869a5;font-size:14px}h1{font-size:28px;line-height:1.4;margin:14px 0}p{color:#526479}label{display:block;margin:16px 0 5px}input,button{font:inherit;width:100%;padding:12px 14px;border-radius:10px;border:1px solid #bdccdc}button{margin-top:22px;background:#176bba;color:white;border:0;cursor:pointer}button:disabled{opacity:.5;cursor:wait}.message{padding:14px;background:#f0f6fc;border-radius:10px;overflow-wrap:anywhere;margin-top:18px}.small{font-size:13px}[hidden]{display:none!important}@media(max-width:400px){main{padding:22px}h1{font-size:24px}}
+</style>
+<main><div class="brand">康师傅 · 产品创新工作坊</div><h1>把成果关联到本人账号</h1><p>仅首次关联时确认。后续课题、会话和报告都归入同一位成员。</p>
+<div id="message" class="message" role="status">正在检查登录状态…</div>
+<form id="login" hidden><label for="username">工作坊账号</label><input id="username" autocomplete="username" autocapitalize="none" spellcheck="false" required maxlength="200"><label for="password">密码</label><input id="password" type="password" autocomplete="current-password" required maxlength="1024"><button>登录本人账号</button></form>
+<button id="confirm" hidden>确认关联到此账号</button><button id="switch" hidden>改用其他账号登录</button>
+<p class="small">密码仅交给平台登录服务。请勿把密码、验证码或 Token 发给数字人。确认成功后回到原对话,告诉数字人“已完成账号绑定”。</p>
+</main>
+<script nonce="__NONCE__">
+const ticket=new URLSearchParams(location.hash.slice(1)).get('ticket');
+history.replaceState(null,'',location.pathname+location.search);
+const el=id=>document.getElementById(id),say=s=>{el('message').textContent=s;};
+const base='https://server.fmode.cn/parse',headers={'X-Parse-Application-Id':'ncloudmaster','Content-Type':'application/json'};
+let token='',username='',busy=false;
+async function platform(path,body){
+ const r=await fetch(base+path,{method:body?'POST':'GET',headers:{...headers,...(token?{'X-Parse-Session-Token':token}:{})},...(body?{body:JSON.stringify(body)}:{}),credentials:'omit',redirect:'error',cache:'no-store',signal:AbortSignal.timeout(15000)});
+ const j=await r.json();if(!r.ok)throw Error('账号登录失败或已过期,请核对账号和密码。');return j;
+}
+function loggedOut(){token='';el('login').hidden=false;el('confirm').hidden=true;el('switch').hidden=true;say('请登录在对话中确认的本人工作坊账号。');}
+async function showUser(){const u=await platform('/users/me');if(u.company?.objectId!=='FKieRbIoGt')throw Error('请使用康师傅工作坊账号登录。');username=u.username;el('login').hidden=true;el('confirm').hidden=false;el('switch').hidden=false;say('当前登录账号:'+username+'。请确认这是您在数字人对话中提供的账号。');}
+el('login').onsubmit=async e=>{e.preventDefault();if(busy)return;busy=true;el('login').querySelector('button').disabled=true;try{token='';const u=await platform('/login',{username:el('username').value.trim(),password:el('password').value});token=u.sessionToken;await showUser();}catch{loggedOut();say('登录未成功,请核对账号、密码及企业归属后重试。');}finally{el('password').value='';busy=false;el('login').querySelector('button').disabled=false;}};
+el('switch').onclick=()=>{loggedOut();};
+el('confirm').onclick=async()=>{if(busy)return;busy=true;el('confirm').disabled=true;try{
+ const r=await fetch(location.pathname+location.search,{method:'POST',headers:{'Content-Type':'application/json','X-Parse-Application-Id':'FKieRbIoGt_main','X-Fmode-Session-Token':token},body:JSON.stringify({path:'/ksfWorkshopAccount',params:{action:'confirm',ticket}}),credentials:'omit',redirect:'error',cache:'no-store',signal:AbortSignal.timeout(20000)});
+ const j=await r.json(),result=j.result;if(!r.ok||!result?.ok)throw Error(result?.errors?.[0]?.message||'绑定暂未完成,请回到对话核对。');
+ if(result.data.status!=='bound')throw Error('绑定回执不完整,请回到对话核对。');
+ say('已关联:'+result.data.displayName+'('+result.data.username+')。请回到数字人对话回复“已完成账号绑定”。');el('confirm').hidden=true;el('switch').hidden=true;token='';
+ }catch(e){say(e.message||'绑定暂未完成,请稍后重试。');}finally{busy=false;el('confirm').disabled=false;}};
+if(!ticket){say('缺少绑定链接。请回到数字人对话获取新的链接。');}
+else{try{token=JSON.parse(sessionStorage.getItem('ksf-board:platform-session.v1')||'null')?.token||'';}catch{}if(token)showUser().catch(loggedOut);else loggedOut();}
+</script></html>

+ 26 - 21
skills/ksf-workshop-runtime/FILES.sha256

@@ -1,7 +1,7 @@
-183b5b8248cf4e7d45b3f62a8cae67dd85b9c86dda22b1e19dadffff2dd4fa12  SKILL.md
+b798b417de70c0d9c15d1eefe72ca069179bb3d2686402399f3aa4e3830c103b  SKILL.md
 11863b16216f8746f24189444fc5ffd40512d313cfddd6fa99111b84ac3acfc2  references/business-data-dictionary.json
 08859f32fa51399c638cb9cc0669e69f53a630ebdfa0ad965b1d360115b3a901  references/full-schema-and-intake.md
-19ef268f43f55499a6593ecde7c0d58707b16f84cad3d9984e2d102852c1f267  references/identity.md
+1f7ee67333604603497494e4247d28987db0fab0b80913eae8d5e06246ba558d  references/identity.md
 a9af25da32e769443af4565ca400c9136745c9d30c2c190dedf978841bf977c1  references/research-library/data-contract.md
 78dedd84d8560ee3f0492769db81562841193fa40bef7028836745b0958ab6b8  references/research-library/full-schema-and-intake.md
 a154e01d3f3efb47f643c27adf22fe963d507dc68a50f8747e8ffda8bb7180bb  references/research-library/operations.md
@@ -9,41 +9,46 @@ fe3462b121fc3f8d5ec0392f68229c463e05a5b3bed985b3d356a1b975f5602e  references/res
 3de4f2aeca43792a37e2d514defebf641b80db11639853ff60e48843dc3405bd  references/research-library/query-rules.md
 270b998fca0d4dcd0ad53ff0bc7e2b5a11f88016133965053cf54f5a50bc525f  references/research-library/research-data-dictionary.json
 c00b9a1520866f36f1f4bf26865ee20b4e461d5a998447136bce31cc42fc9b7f  references/research-library/retrieval-rules.md
-143a73f48d27b7630b6fdd286c1e37ba8bcc207a4bf9ddd8a2682a1de53dac46  references/workshop-analysis.md
+c41219e3f0d48dd687af253475f6971f4929e650450bad7995ffd60770208de6  references/workshop-analysis.md
 5af981a8a10acc39470482a09397ea26e8be42d1416efff1e6b2e2baf3bd797f  references/workshop-autonomous-research.md
 b2c6aa939aa4801c77146430f099d3973bf5961cc9291d03a345a9d6a4fe74f6  references/workshop-category-scan.md
-88d22c34781ba284fabe5ae597ff44b3c0859e316ef3227c8d36201704dc4092  references/workshop-commercial-feasibility.md
+c75a97ec3d31ed626d7e447d3621351a966eb7f953cc7aa7eee5a40a7a71ebec  references/workshop-commercial-feasibility.md
 d67158d7294bb0581489e01182d0a5fafd121bf6a2fced5a0926263cdfb0dbaf  references/workshop-competitor-landscape.md
-c49130963a29ada0cff5daef604a73a4b428fd62afad88be4b1f2689894d0207  references/workshop-concept-presentation.md
-4e79a5a73672ea403d4d728578949cc1e8a041d78d202ea06c727898e74a0f94  references/workshop-course-flow.md
-a13a9746974803e749ae380bda6ef04eff3638428070244e2b8f08fb6ad11ad1  references/workshop-deliverable-contracts.md
-de010951e04ea456c5b4a9e621c4bf7b512a38d5b8223a1e39adb1fa16f09be8  references/workshop-delivery.md
+464977265ed0cd1367f6f478a318ab115738af22793e0b97c4930b4f52d5e694  references/workshop-concept-presentation.md
+85c29ea6798868d5515386e73cc008a228b45a19aa9d072bf4217781207f4300  references/workshop-course-flow.md
+5966a9efd787ab86eae6b78dd28634a6130f2e4dfba3509a7716a67201dfbfc5  references/workshop-deliverable-contracts.md
+8dff9e307769f5cd40f10115dabe02d68ae678de5398db5d5fdaef7bddba073f  references/workshop-delivery.md
 27498cf6b48a8fe3f28aab88c9d5e1fabb5357570a15a06f313d4db9c1c694b6  references/workshop-dialogue.md
-003f8e40a04c391026e183d4a09c9b5b70f8b33acde83a998fc24b52eab07908  references/workshop-evidence-counting.md
-5136d6ffdc9530e37834a90b1b547cccae55bbb8670d24e38a668cf74e7b2ab2  references/workshop-feedback.md
+b741b244f1a1c3cce205aa0c92ac12bd303f015f4bf9ffda87ec520141508e8a  references/workshop-evidence-counting.md
+e6613c6f55858f326c2fed5b9b61d6b376871c92b9216d1c9155cb4ed79bac3c  references/workshop-feedback.md
 19de27e102f8ed0c00c4a1457e7b1902680f2c79201dc274ad22ae66301a1c12  references/workshop-innovation-reasoning.md
 13345a8a554256d94db730bae70701be02c3d2a7becf8c7c12b44909cb88465e  references/workshop-intake.md
 0c413a47ef1dfbc496280c29a4141568b1a28c58ad3dc92509336748ba2480ec  references/workshop-opportunity-discovery.md
-d0e5e654cb0b116c0f24d2523c01fa6eb9e7c26d1581e2c2f0d5e8851fa7cfe1  references/workshop-opportunity-validation.md
-ccbd1af9cc67847ede396296476887eb19a9c17fba448988c62327f817e4c7ce  references/workshop-output-navigation.md
-c23f9cd276a40db1ac432a5221c1ab8a577e20dab5acfc536bfbe3585be80cb9  references/workshop-report-design.md
-898fee4587d3e389126f77e5564aed5226048883caf6b17891832670c4a540bb  references/workshop-report-parity.md
+db66616e1011e2855d920725242e4a6af086f315e38310efd11f89d5cb2b3453  references/workshop-opportunity-validation.md
+1498f3d19f42ee921ef45559fce7d63e9c7fd5c3062c79d489814cdb96d0a412  references/workshop-output-navigation.md
+d2b02e0ea74e35a32994e5ac11beeccf1c48f4b0903a6ce4e425fdc3e92af7ad  references/workshop-report-design.md
+4df8aaeb0a9587c4b987a5902c6ab3e91b5307daee5c7978eeb6d68b83c6b5e2  references/workshop-report-parity.md
 26a2fdcae8631a0a66d41d159442525f950835b6057bd1475b4d131f97a10aba  references/workshop-research-acceptance.md
 c480f229baf5d3d84b145649f9cf8a992a2bb7c4a44e2baf11ccedf530eb6786  references/workshop-research-loop.md
 f8b7fbb72b57ae088c411e510dd2cd371aac98d10903a0b4b6e2ce16caae4a51  references/workshop-research-tasking.md
-b0e2ee97b9446108797a3696636969da6dae61615d0377299fb2efacf8f3dd69  references/workshop-tasks.md
-67cd80eb6aee9df10a0c2c8366f8f8994cb825555ef21aec23fbe5e4ebc57215  references/workshop-three-source-opportunities.md
+a4e0bc238966ea7a119986f383f4f6ea99dd8d9de63bdc32571a35b740d8f96d  references/workshop-tasks.md
+e0200259e92644bf55ca2fe3f60b1eea4c7df512b1300f2643b8b6991ebc6ca3  references/workshop-three-source-opportunities.md
+3d9855fccf3250c54317e7bb4060d3185e77e61be82c0494df5fb1d21d67fee2  references/workshop-v3-outputs.md
 1589247eade7243f430be161ed987ecbddf9eb9fdcf1873a5d1f5a141ac89c05  references/workshop-value-proposition.md
 01451f1565983eba85f26d3403b35f67c19cf501b5b5da29f52270dc68fd55f6  references/workshop-verification.md
-64c0c150a2dd78a3a399bdf56083ad8a168b3955ada71777f5e1b4da2c13680d  references/workshop-voc-clustering.md
+d1c04203dde6a7eb424b2316a13964d2d63a6e91836dd5c1eef55f858f59fe02  references/workshop-voc-clustering.md
 a685c3a1c2b907e19cc7e94e42325012a82e09978e267219a0938a42fb9beace  references/write-tasks.md
 2605cbe8fd7be43b5969a4991f978dc0768dee5b4d65d18f7af15f75e9004a79  runtime-lock.json
+7ad2aebd30fbc244f4617c9559f076ff7df4196901a31465b5a70bfe5055bb55  scripts/course-assessment.mjs
+7200354296d2b605247ac0cd41927e55fd741f5dd29beb1387b92373f88df617  scripts/course-deliverables.mjs
 e96e8c3fc1a71f1edc39dfc250199aacfb1457aec851d29e6f3b2c35e918a279  scripts/describe-business-schema.mjs
+9bfda45c53192d70fefb31b378851aeb19e075b6f5adcd8217ba4838cc133f7d  scripts/ksf-account.mjs
 6ba3f0cb6527bc4a0a6218a898472ac65aa3dd9f3f57b597d77efcee641a7540  scripts/ksf-identity-bridge.mjs
-9224ef89a96425890d54961fda1f4fcae3403aa7c753fe1d70ac62082f2ff77e  scripts/ksf-identity.mjs
-10abc8fcb4c0dd459ff15c086668608b404cc0d61efaf559213a90d0a573ce75  scripts/ksf-secure.mjs
+ab6838afd140e4b84ef39a255fcbdd80ece9b0b7c245f65cd8ba81d892036513  scripts/ksf-identity.mjs
+25e42387ea9e3cbf5b60c431eaaf09bc381dcc04acbb82d0f0a7dd071f357fea  scripts/ksf-secure.mjs
 7a04eb22d3429cdced23513717f36594f639539738994d45712a8bea738100a1  scripts/ksf-workshop.mjs
 7ef128f7d022bfbc15c0ec813bfd87995c6297c6efe407a563c840f014aba477  scripts/ksf.mjs
-a70661dba87755a14eece178033317dbd797f1c76b4a21392d79fccf2c0c4ef2  scripts/render-report-html.mjs
+246588294da6975d80d0f1b1e338bc30cf737421c43cea38cf33745eb52e40a9  scripts/render-report-html.mjs
 4c6e05ca3f6e65d57d55f743de39307181f8427626e355a5d2698905c17dd8c4  scripts/report-contract.mjs
-82963fb0d1eb3fd7b243e2aad9356f3150b6e2300f6126104429f24d457365ad  scripts/save-report.mjs
+ede7e98ee941e4ca2ce867d53eb29fa289b9047070e9e6797d20d5d547d24325  scripts/report-statistics.mjs
+022c1833f733ac321ce588ea1dd74e12a1609370f35fe3749c35bf8059a97d17  scripts/save-report.mjs

+ 14 - 8
skills/ksf-workshop-runtime/SKILL.md

@@ -2,13 +2,15 @@
 name: ksf-workshop-runtime
 description: 康师傅面类研究与产品创新工作坊统一Skill。先用模型专业能力拆题与形成假设,结合已有数据取证,自查关键缺口并调度现有VOC补充外部资料;按课表分析需求、机会、可行性与产品概念,保存成果并回读看板。
 metadata:
-  version: r14-local.6
+  version: r15-local.3
 ---
 
 # 康师傅产品创新工作坊
 
 本Skill统一研究编排、资料库与工作坊成果管理,围绕 S1 品类市场分析 → S2 用户需求与痛点 → S3 机会识别 → S4 验证评估 → S5 场景与卖点设计处理研究任务。先发挥模型的行业知识、问题拆解、比较和推理能力,形成分析框架及待证假设;结合已有数据回答,再自主检查关键缺口,必要时调度现有VOC取得外部资料、回核并修订结论。按课表交付报告及对应结构化成果,保存后用真实编号回读。重点拌面,研究范围限面类;研究范围不以已入库资料为界。
 
+课程流程、复制提示词和应交内容以《学员手册 v3》为当前操作手册,见 [13 份产出与交接](references/workshop-v3-outputs.md)。本Skill负责落实其方法、内容与保存规则,不要求学员换回旧版手册或旧42轮提示词;课堂示例参数仍须核本题来源和适用性。
+
 看板保留公开查看,账号登录用于识别本人,成员选择只控制浏览筛选。看板浏览器的登录状态不自动成为数字人当前消息的身份,须核宿主实际提供的登录上下文。服务凭据授权写入,不代表员工本人完成正式确认。
 
 研究底料、监测台账与业务成果使用康师傅企业数据库,通过各自受控接口访问并以真实来源关联;实际连接及可用操作以contract回读为准。详见 [研究资料操作](references/research-library/operations.md)。
@@ -53,7 +55,9 @@ metadata:
 
 每节接续只更新发生变化的判断、候选和证据,完整核心产出保留在可读正文。按 [反馈的增量与决策用途](references/workshop-feedback.md#每节推进什么而不是重复什么) 区分研究线索、待验证产品设想与当前建议;不能把“先观察是否有问题”包装为已成立的新品机会。手册负责简短发起,方法、计算与补证由本Skill完成,不让员工逐节重述质量规则。
 
-保存阶段成果时按 [七类产出与成果导航](references/workshop-output-navigation.md) 定位已有实质章节,使负责人能从本组课题找到判断、依据和版本。正文先回答业务问题,导航随实际内容建立;空章节和数量不代表质量达标。
+当前课程按刘总总览图及学员手册 v3 的 [13 份环节产出与交接](references/workshop-v3-outputs.md) 验收:每个环节有自己的交付单元,保留形态、最低内容、用途及下游依赖。13 份是环节产出数,不是看板 11 个报告分类、原七类内容索引或固定文件数。保存后分别核每项正文、同版 HTML、证据、统计、归属和页面;已有正文不等于内容验收通过。
+
+保存阶段成果时按 [内容索引与成果导航](references/workshop-output-navigation.md) 定位已有实质章节,使负责人能从本组课题找到判断、依据和版本。七类索引保留兼容,最终交付必须逐项列齐 13 个环节的真实位置和缺项。正文先回答业务问题;空章节和数量不代表质量达标。
 
 面向产品团队,先回答本轮业务问题:实际观察是什么,怎样影响产品选择或使用,现有解决方式及可改之处有什么取舍,下一步怎样判别。趋势、洞察与研发比较按 [从证据到研发选项](references/workshop-innovation-reasoning.md) 深化;已知成本、设备、上市窗口及须保留的体验从起点约束方案。每个环节按 [产品反馈与产出标准](references/workshop-feedback.md) 检查决策价值、具体内容、修改意图和可读性,再按 [业务判断与证据分层](references/workshop-analysis.md#把资料转成产品判断) 核依据。主文先交可讨论的产品认识/比较,限制跟随相关结论,技术路径/JSON/哈希后置;不能只交资料盘点、缺口或纠错清单。
 
@@ -63,7 +67,7 @@ metadata:
 
 正式研究从D1-01品类全景扫描开始;样板课和人机分工讲解由授课PPT承载,不作为独立研究任务或后台成果。执行首节先读 [品类全景扫描](references/workshop-category-scan.md):建立供给树、需求树和供需连接表,关联来源与覆盖,以一份品类全景图谱保存和回读。它是后续市场报告的基础,不以通用行业综述替代图谱。
 
-D1-02按 [验证纪律前置](references/workshop-verification.md) 形成可复用的本题验证配置卡:明确资料资格、统计与引文口径、真实双模型分工及分歧处理,并重点回查前序图谱。模型配置、实际执行、原件核查和判断可引用范围分别留状态;后续任务引用真实卡号/版本并执行适用规则。提示词资产是教学成果,Agent应协助形成可复制的本组任务文本;课题原文随成果保存,不固化成本Skill的案例答案。
+D1-02按 [验证纪律前置](references/workshop-verification.md) 形成可复用的本题验证配置卡:明确资料资格、统计与引文口径、AI取证与本组决策分工及分歧处理,并重点回查前序图谱。本题已约定且真实具备双模型时再执行对应复核,不把第二模型当v3必备条件。模型配置、实际执行、原件核查和判断可引用范围分别留状态;后续任务引用真实卡号/版本并执行适用规则。提示词资产是教学成果,Agent应协助形成可复制的本组任务文本;课题原文随成果保存,不固化成本Skill的案例答案。
 
 D1-03按 [竞品格局掌握](references/workshop-competitor-landscape.md) 比较商品/规格、价格条件、定位、卖点排列组合、风味与新品,形成竞品图谱及可验证的痛点假设初稿。原始卖点顺序、商品宣称、用户回应和推断分列;风味结构不冒充增长,未覆盖不算市场空白,假设保留支持/反对与验证问题,交下一节收敛。
 
@@ -84,10 +88,10 @@ D2下午按以下四段接续完整候选池;每段均保留前序真实编号
 
 | 环节 | 执行细则与核心交接 |
 |---|---|
-| D2-05 | [机会验证与排序](references/workshop-opportunity-validation.md):证据闭环、真实双模型审查及可解释S/A/B初排,形成优先级机会清单,未知单列待评 |
+| D2-05 | [机会验证与排序](references/workshop-opportunity-validation.md):证据闭环、按实际能力复核;v3 依证据强度/可做性/商业价值各 1–3 分,任一维 1 分不进前三,未知单列 |
 | D2-06 | [商业及供应链回推](references/workshop-commercial-feasibility.md):成本/毛利/定价情景、工厂工艺和合规条件,形成回推表及全池有去向的V2.0 |
 | D2-07 | [价值主张与核心卖点](references/workshop-value-proposition.md):需求→产品要素→收益→表达,形成价值主张及卖点清单,区分需求证据与产品验证 |
-| D2-08 | [概念提案与分享](references/workshop-concept-presentation.md):概念提案、真实质询、V3.0、小组案例及七类成果导航;保留决定性待验证问题,独立方案与项目完成分别核验 |
+| D2-08 | [概念提案与分享](references/workshop-concept-presentation.md):三层提案、真实质询、V3.0、13 份环节成果导航;保留决定性待验证问题,独立方案与项目完成分别核验 |
 
 | 课表段落 | Agent主要工作 | 核心产出 |
 |---|---|---|
@@ -100,6 +104,8 @@ D2下午按以下四段接续完整候选池;每段均保留前序真实编号
 
 同一小组沿同一课题、研究范围和成果索引接续,按 [同题接续与课堂判断](references/workshop-course-flow.md#同题接续与课堂判断) 保留业务限制、前序结论和真实选择。每节优先回答本节问题并给依据、建议及决定性待验证项;后台报告首页先呈现这些内容,追溯明细放后。需求主题先形成有依据的研究先后,再进入机会初排;条件变化只回核受影响部分。
 
+“反馈关键资料”指精选展示可解释判断的材料,不缩小统计范围。关键结论须有对应真实采集/已有资料及产品对照支撑,同时按 [证据计数与样本口径](references/workshop-evidence-counting.md#结论依据与全体相关资料总结) 汇总本题全部相关资料的纳入、排除、待核及实际分析覆盖,并对已完成判定的集合统计支持、反对、不同场景与主题分布。主文展示关键统计n/N、解释及代表原话,完整成员索引后置;不得只挑支持结论的几条原话、把抽样称全量,或用采集总条数冒充结论的支持数。统计总结随同版report、rawText和HTML保存,不能只留在对话里。
+
 每个有实质产出的环节立即同步,不等整阶段或结营才上传。按 [逐环节保存与看板核对](references/workshop-delivery.md) 分别处理资料、分析结果和报告,沿用真实来源编号;一环节可有多份资料、报告或机会卡。重复任务先回读恢复,不能重复建会话、项目或成果。讲解和只读检查不创建空报告。
 
 报告属于当前员工个人,小组只组织展示;共用智能体也必须沿各人真实会话隔离保存,不能把小组、智能体或其他员工设为报告作者。七类核心交付物按 [报告交付与展示合同](references/workshop-report-parity.md) 标记正文、分类和状态。每份有实质内容的报告默认交HTML,完整正文同时保存在rawText和report;默认用 `scripts/render-report-html.mjs` 从同版结构化正文生成,`scripts/save-report.mjs` 自动生成并关联HTML,回核同编号业务记录、公开投影及附件字节。其他实现须完成同等内容/文件核对。尚未支持附件的环境保留实际HTML并交员工,明确看板文件未同步,不静默退回只有聊天文字,也不冒称已接通。图片等交付文件须关联同版本报告;仅存在本地不算已到看板。个人交付清单只证明正文提交,不证明内容质量或员工正式确认。
@@ -163,11 +169,11 @@ node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-secure.mjs <命令> --age
 
 每个新数字人、新员工在业务保存前核对独立身份档案。数字人从自身可信运行配置取得身份,消息上下文补充渠道信息;只提取白名单字段,用 ksf-identity.mjs register 登记,已有档案用 check 核对。读取方式按实际运行环境核实,不能声称已接入不存在的自动身份 API,不按名称限定数字人数量或角色槽位。业务写命令传当前执行者的完整档案键,role=workshop 才能执行课堂写入;角色不代表平台授权。详见 [references/identity.md](references/identity.md)。不能将聊天中提及的另一个机器人登记为自己。
 
-员工信息从本条消息可信发送者或当前登录上下文取得,workshop-start 只引用员工 profileKey。fmode 网站账号按 [网站账号与称呼](references/identity.md#网站账号与称呼) 核对本人、企业和稳定账号ID;不从拼音或姓名猜账号,不将平台账号ID当作康师傅业务库的 `_User.objectId`。企微 aibot 有 from.userid 时,调用无参数进程内工具 ksf_register_current_employee;工具成功后仅复用返回的 profile.key 与 agentProfileKey。旧 register-channel-employee --context 已关闭。企微按 botId+发送者标识区分员工,不以手填网站账号替换发送者键;网站账号与企微别名没有受控映射时不合并。企业ID未知仍为null,不拿群chatid替代发送者。其他环境没有可信稳定标识时沿原人工登记规则处理,不为绕过当前身份冲突换键。缺档案停止创建会话,独立研究可继续;取不到身份不等于扫描环境变量或凭据。
+员工信息从本条消息可信发送者或当前登录上下文取得,workshop-start 只引用员工 profileKey。fmode 网站账号按 [网站账号与称呼](references/identity.md#网站账号与称呼) 核对本人、企业和稳定账号ID;不从拼音或姓名猜账号,不将平台账号ID当作康师傅业务库的 `_User.objectId`。企微 aibot 有 from.userid 时,调用无参数进程内工具 ksf_register_current_employee;工具成功后仅复用返回的 profile.key 与 agentProfileKey。旧 register-channel-employee --context 已关闭。企微按 botId+发送者标识区分员工,不以手填网站账号替换发送者键;网站账号与企微别名没有受控映射时不合并。企业ID未知仍为null,不拿群chatid替代发送者。其他环境没有可信稳定标识时可按原规则登记本地待核对资料;账号绑定未完成时不得据此新建公开成员或提交课堂成果,不为绕过当前身份冲突换键。缺档案停止创建会话,独立研究可继续;取不到身份不等于扫描环境变量或凭据。
 
-### 复用称呼与账号归属
+### 首次账号绑定与后续复用
 
-沿用员工通过当前任务或可信上下文已提供的称呼和账号信息;Skill不另设个人资料开场,也不在检索、入库、阶段接续或上传前重复收集。必要的产品目标、真实业务约束及方案确认仍按研究流程处理。
+首次调用工作坊且尚未绑定本人账号时,先进行一轮必要身份确认:询问希望使用的称呼和已开通的工作坊账号;已有信息直接请本人确认,不重复收集。按[首次账号绑定](references/identity.md#网站账号与称呼)核验本人登录、企业归属与注册成员编号,绑定成功并回读后再创建课堂会话和保存报告。此为成果归属规则,不收集其他个人资料。已有绑定直接复用,不因新课题、新会话、改称呼或重试新增看板成员。必要的产品目标、真实业务约束及方案确认仍按研究流程处理。
 
 称呼只作显示,归属以已核对的本人稳定账号/发送者键为准。读取已有绑定并沿用,不按姓名合并人员、重建档案或切换会话。网页账号与称呼的私有接续、当前接口支持范围及待同步处理见 [身份细则](references/identity.md#网站账号与称呼)。没有可信账号上下文时只记本人自报信息为待核对,独立研究继续,不能将成果写到猜测的员工名下。
 

+ 14 - 8
skills/ksf-workshop-runtime/final-SKILL.md

@@ -2,13 +2,15 @@
 name: ksf-workshop-runtime
 description: 康师傅面类研究与产品创新工作坊统一Skill。先用模型专业能力拆题与形成假设,结合已有数据取证,自查关键缺口并调度现有VOC补充外部资料;按课表分析需求、机会、可行性与产品概念,保存成果并回读看板。
 metadata:
-  version: r14-local.6
+  version: r15-local.3
 ---
 
 # 康师傅产品创新工作坊
 
 本Skill统一研究编排、资料库与工作坊成果管理,围绕 S1 品类市场分析 → S2 用户需求与痛点 → S3 机会识别 → S4 验证评估 → S5 场景与卖点设计处理研究任务。先发挥模型的行业知识、问题拆解、比较和推理能力,形成分析框架及待证假设;结合已有数据回答,再自主检查关键缺口,必要时调度现有VOC取得外部资料、回核并修订结论。按课表交付报告及对应结构化成果,保存后用真实编号回读。重点拌面,研究范围限面类;研究范围不以已入库资料为界。
 
+课程流程、复制提示词和应交内容以《学员手册 v3》为当前操作手册,见 [13 份产出与交接](references/workshop-v3-outputs.md)。本Skill负责落实其方法、内容与保存规则,不要求学员换回旧版手册或旧42轮提示词;课堂示例参数仍须核本题来源和适用性。
+
 看板保留公开查看,账号登录用于识别本人,成员选择只控制浏览筛选。看板浏览器的登录状态不自动成为数字人当前消息的身份,须核宿主实际提供的登录上下文。服务凭据授权写入,不代表员工本人完成正式确认。
 
 研究底料、监测台账与业务成果使用康师傅企业数据库,通过各自受控接口访问并以真实来源关联;实际连接及可用操作以contract回读为准。详见 [研究资料操作](references/research-library/operations.md)。
@@ -53,7 +55,9 @@ metadata:
 
 每节接续只更新发生变化的判断、候选和证据,完整核心产出保留在可读正文。按 [反馈的增量与决策用途](references/workshop-feedback.md#每节推进什么而不是重复什么) 区分研究线索、待验证产品设想与当前建议;不能把“先观察是否有问题”包装为已成立的新品机会。手册负责简短发起,方法、计算与补证由本Skill完成,不让员工逐节重述质量规则。
 
-保存阶段成果时按 [七类产出与成果导航](references/workshop-output-navigation.md) 定位已有实质章节,使负责人能从本组课题找到判断、依据和版本。正文先回答业务问题,导航随实际内容建立;空章节和数量不代表质量达标。
+当前课程按刘总总览图及学员手册 v3 的 [13 份环节产出与交接](references/workshop-v3-outputs.md) 验收:每个环节有自己的交付单元,保留形态、最低内容、用途及下游依赖。13 份是环节产出数,不是看板 11 个报告分类、原七类内容索引或固定文件数。保存后分别核每项正文、同版 HTML、证据、统计、归属和页面;已有正文不等于内容验收通过。
+
+保存阶段成果时按 [内容索引与成果导航](references/workshop-output-navigation.md) 定位已有实质章节,使负责人能从本组课题找到判断、依据和版本。七类索引保留兼容,最终交付必须逐项列齐 13 个环节的真实位置和缺项。正文先回答业务问题;空章节和数量不代表质量达标。
 
 面向产品团队,先回答本轮业务问题:实际观察是什么,怎样影响产品选择或使用,现有解决方式及可改之处有什么取舍,下一步怎样判别。趋势、洞察与研发比较按 [从证据到研发选项](references/workshop-innovation-reasoning.md) 深化;已知成本、设备、上市窗口及须保留的体验从起点约束方案。每个环节按 [产品反馈与产出标准](references/workshop-feedback.md) 检查决策价值、具体内容、修改意图和可读性,再按 [业务判断与证据分层](references/workshop-analysis.md#把资料转成产品判断) 核依据。主文先交可讨论的产品认识/比较,限制跟随相关结论,技术路径/JSON/哈希后置;不能只交资料盘点、缺口或纠错清单。
 
@@ -63,7 +67,7 @@ metadata:
 
 正式研究从D1-01品类全景扫描开始;样板课和人机分工讲解由授课PPT承载,不作为独立研究任务或后台成果。执行首节先读 [品类全景扫描](references/workshop-category-scan.md):建立供给树、需求树和供需连接表,关联来源与覆盖,以一份品类全景图谱保存和回读。它是后续市场报告的基础,不以通用行业综述替代图谱。
 
-D1-02按 [验证纪律前置](references/workshop-verification.md) 形成可复用的本题验证配置卡:明确资料资格、统计与引文口径、真实双模型分工及分歧处理,并重点回查前序图谱。模型配置、实际执行、原件核查和判断可引用范围分别留状态;后续任务引用真实卡号/版本并执行适用规则。提示词资产是教学成果,Agent应协助形成可复制的本组任务文本;课题原文随成果保存,不固化成本Skill的案例答案。
+D1-02按 [验证纪律前置](references/workshop-verification.md) 形成可复用的本题验证配置卡:明确资料资格、统计与引文口径、AI取证与本组决策分工及分歧处理,并重点回查前序图谱。本题已约定且真实具备双模型时再执行对应复核,不把第二模型当v3必备条件。模型配置、实际执行、原件核查和判断可引用范围分别留状态;后续任务引用真实卡号/版本并执行适用规则。提示词资产是教学成果,Agent应协助形成可复制的本组任务文本;课题原文随成果保存,不固化成本Skill的案例答案。
 
 D1-03按 [竞品格局掌握](references/workshop-competitor-landscape.md) 比较商品/规格、价格条件、定位、卖点排列组合、风味与新品,形成竞品图谱及可验证的痛点假设初稿。原始卖点顺序、商品宣称、用户回应和推断分列;风味结构不冒充增长,未覆盖不算市场空白,假设保留支持/反对与验证问题,交下一节收敛。
 
@@ -84,10 +88,10 @@ D2下午按以下四段接续完整候选池;每段均保留前序真实编号
 
 | 环节 | 执行细则与核心交接 |
 |---|---|
-| D2-05 | [机会验证与排序](references/workshop-opportunity-validation.md):证据闭环、真实双模型审查及可解释S/A/B初排,形成优先级机会清单,未知单列待评 |
+| D2-05 | [机会验证与排序](references/workshop-opportunity-validation.md):证据闭环、按实际能力复核;v3 依证据强度/可做性/商业价值各 1–3 分,任一维 1 分不进前三,未知单列 |
 | D2-06 | [商业及供应链回推](references/workshop-commercial-feasibility.md):成本/毛利/定价情景、工厂工艺和合规条件,形成回推表及全池有去向的V2.0 |
 | D2-07 | [价值主张与核心卖点](references/workshop-value-proposition.md):需求→产品要素→收益→表达,形成价值主张及卖点清单,区分需求证据与产品验证 |
-| D2-08 | [概念提案与分享](references/workshop-concept-presentation.md):概念提案、真实质询、V3.0、小组案例及七类成果导航;保留决定性待验证问题,独立方案与项目完成分别核验 |
+| D2-08 | [概念提案与分享](references/workshop-concept-presentation.md):三层提案、真实质询、V3.0、13 份环节成果导航;保留决定性待验证问题,独立方案与项目完成分别核验 |
 
 | 课表段落 | Agent主要工作 | 核心产出 |
 |---|---|---|
@@ -100,6 +104,8 @@ D2下午按以下四段接续完整候选池;每段均保留前序真实编号
 
 同一小组沿同一课题、研究范围和成果索引接续,按 [同题接续与课堂判断](references/workshop-course-flow.md#同题接续与课堂判断) 保留业务限制、前序结论和真实选择。每节优先回答本节问题并给依据、建议及决定性待验证项;后台报告首页先呈现这些内容,追溯明细放后。需求主题先形成有依据的研究先后,再进入机会初排;条件变化只回核受影响部分。
 
+“反馈关键资料”指精选展示可解释判断的材料,不缩小统计范围。关键结论须有对应真实采集/已有资料及产品对照支撑,同时按 [证据计数与样本口径](references/workshop-evidence-counting.md#结论依据与全体相关资料总结) 汇总本题全部相关资料的纳入、排除、待核及实际分析覆盖,并对已完成判定的集合统计支持、反对、不同场景与主题分布。主文展示关键统计n/N、解释及代表原话,完整成员索引后置;不得只挑支持结论的几条原话、把抽样称全量,或用采集总条数冒充结论的支持数。统计总结随同版report、rawText和HTML保存,不能只留在对话里。
+
 每个有实质产出的环节立即同步,不等整阶段或结营才上传。按 [逐环节保存与看板核对](references/workshop-delivery.md) 分别处理资料、分析结果和报告,沿用真实来源编号;一环节可有多份资料、报告或机会卡。重复任务先回读恢复,不能重复建会话、项目或成果。讲解和只读检查不创建空报告。
 
 报告属于当前员工个人,小组只组织展示;共用智能体也必须沿各人真实会话隔离保存,不能把小组、智能体或其他员工设为报告作者。七类核心交付物按 [报告交付与展示合同](references/workshop-report-parity.md) 标记正文、分类和状态。每份有实质内容的报告默认交HTML,完整正文同时保存在rawText和report;默认用 `scripts/render-report-html.mjs` 从同版结构化正文生成,`scripts/save-report.mjs` 自动生成并关联HTML,回核同编号业务记录、公开投影及附件字节。其他实现须完成同等内容/文件核对。尚未支持附件的环境保留实际HTML并交员工,明确看板文件未同步,不静默退回只有聊天文字,也不冒称已接通。图片等交付文件须关联同版本报告;仅存在本地不算已到看板。个人交付清单只证明正文提交,不证明内容质量或员工正式确认。
@@ -163,11 +169,11 @@ node /opt/data/skills/ksf-workshop-runtime/scripts/ksf-secure.mjs <命令> --age
 
 每个新数字人、新员工在业务保存前核对独立身份档案。数字人从自身可信运行配置取得身份,消息上下文补充渠道信息;只提取白名单字段,用 ksf-identity.mjs register 登记,已有档案用 check 核对。读取方式按实际运行环境核实,不能声称已接入不存在的自动身份 API,不按名称限定数字人数量或角色槽位。业务写命令传当前执行者的完整档案键,role=workshop 才能执行课堂写入;角色不代表平台授权。详见 [references/identity.md](references/identity.md)。不能将聊天中提及的另一个机器人登记为自己。
 
-员工信息从本条消息可信发送者或当前登录上下文取得,workshop-start 只引用员工 profileKey。fmode 网站账号按 [网站账号与称呼](references/identity.md#网站账号与称呼) 核对本人、企业和稳定账号ID;不从拼音或姓名猜账号,不将平台账号ID当作康师傅业务库的 `_User.objectId`。企微 aibot 有 from.userid 时,调用无参数进程内工具 ksf_register_current_employee;工具成功后仅复用返回的 profile.key 与 agentProfileKey。旧 register-channel-employee --context 已关闭。企微按 botId+发送者标识区分员工,不以手填网站账号替换发送者键;网站账号与企微别名没有受控映射时不合并。企业ID未知仍为null,不拿群chatid替代发送者。其他环境没有可信稳定标识时沿原人工登记规则处理,不为绕过当前身份冲突换键。缺档案停止创建会话,独立研究可继续;取不到身份不等于扫描环境变量或凭据。
+员工信息从本条消息可信发送者或当前登录上下文取得,workshop-start 只引用员工 profileKey。fmode 网站账号按 [网站账号与称呼](references/identity.md#网站账号与称呼) 核对本人、企业和稳定账号ID;不从拼音或姓名猜账号,不将平台账号ID当作康师傅业务库的 `_User.objectId`。企微 aibot 有 from.userid 时,调用无参数进程内工具 ksf_register_current_employee;工具成功后仅复用返回的 profile.key 与 agentProfileKey。旧 register-channel-employee --context 已关闭。企微按 botId+发送者标识区分员工,不以手填网站账号替换发送者键;网站账号与企微别名没有受控映射时不合并。企业ID未知仍为null,不拿群chatid替代发送者。其他环境没有可信稳定标识时可按原规则登记本地待核对资料;账号绑定未完成时不得据此新建公开成员或提交课堂成果,不为绕过当前身份冲突换键。缺档案停止创建会话,独立研究可继续;取不到身份不等于扫描环境变量或凭据。
 
-### 复用称呼与账号归属
+### 首次账号绑定与后续复用
 
-沿用员工通过当前任务或可信上下文已提供的称呼和账号信息;Skill不另设个人资料开场,也不在检索、入库、阶段接续或上传前重复收集。必要的产品目标、真实业务约束及方案确认仍按研究流程处理。
+首次调用工作坊且尚未绑定本人账号时,先进行一轮必要身份确认:询问希望使用的称呼和已开通的工作坊账号;已有信息直接请本人确认,不重复收集。按[首次账号绑定](references/identity.md#网站账号与称呼)核验本人登录、企业归属与注册成员编号,绑定成功并回读后再创建课堂会话和保存报告。此为成果归属规则,不收集其他个人资料。已有绑定直接复用,不因新课题、新会话、改称呼或重试新增看板成员。必要的产品目标、真实业务约束及方案确认仍按研究流程处理。
 
 称呼只作显示,归属以已核对的本人稳定账号/发送者键为准。读取已有绑定并沿用,不按姓名合并人员、重建档案或切换会话。网页账号与称呼的私有接续、当前接口支持范围及待同步处理见 [身份细则](references/identity.md#网站账号与称呼)。没有可信账号上下文时只记本人自报信息为待核对,独立研究继续,不能将成果写到猜测的员工名下。
 

+ 24 - 12
skills/ksf-workshop-runtime/references/identity.md

@@ -4,23 +4,35 @@
 
 ## 本人提供的看板称呼
 
-身份细则只处理员工已提供的称呼、账号归属和保存,不另发个人资料开场,不在入库或上传前追问称呼。发送者登记、显示称呼、通讯录实名是三个独立事实,不把通讯录查询作为使用自报称呼的前置条件。
+首次工作坊调用只进行必要的称呼与账号绑定确认;已绑定后不在入库、上传或阶段接续时重复追问。发送者登记、显示称呼、通讯录实名是三个独立事实,不把通讯录查询作为使用自报称呼的前置条件。
 
 `employee-name` 只接受当前可信消息登记的员工profileKey和其已有会话;服务端校验服务owner、工作坊参与键派生关系及Agent。读取只用data:read;保存称呼或明确跳过使用既有ingest:write,无需identity:write或运维凭据。私有运行配置 `workshopDisplayNames` 按bot作用域+发送者摘要存储,跨工作坊复用,同名不合并。更新只涉及称呼注册表及操作审计,不改员工/Agent档案、会话索引、报告、项目或旧归属快照。
 
 `provided`直接复用,`skipped`继续业务不再追问;`promptState=not_asked`只表示尚无记录,不授权Skill额外提问。用户主动改名时可更新。自报姓名与昵称均标source=self_reported、nameVerified=false,不写入employee.name,也不冒称企微显示名或实名。看板在employee.displayName展示称呼,标“本人提供的称呼 · 未经通讯录核验”;已有可信通讯录姓名优先。历史本地占位名可保持原样,不代表保存昵称失败。
 
-## 网站账号与称呼
-
-员工明确要求关联称呼与fmode登录账号时,处理其实际输入并核对下述身份依据。未给出的信息标待核对,不替员工填写,不据姓名拼音生成账号;不索要密码、验证码或其他无关个人资料,不创建平台账号或修改平台姓名。
-
-账号依据优先使用当前数字人宿主对本条消息提供的可信登录上下文,核对用户名、稳定平台用户ID及企业 `FKieRbIoGt`。员工自报用户名与当前登录账号不一致时先说明冲突,不代为切换账号或覆盖旧归属。受控账号名册可核账号是否存在及企业归属,但不能单独证明发言者就是该账号本人。当前环境没有可信登录身份时标“账号归属待核对”,独立研究可继续,不把待核对信息写成已认证身份。
-
-fmode平台账号库的公开App ID为 `ncloudmaster`,康师傅业务库App ID为 `FKieRbIoGt_main`。平台用户ID不得填入 `participant.userId` 或构造业务库 `_User` 指针。既有身份模块可承载已核对的平台账号:`identityBasis=existing_record`、`account.platform=fmode`、`account.tenantId=FKieRbIoGt`、`account.accountId=实际平台用户ID`、`account.accountName=实际用户名`、`userId=null`;稳定归属使用channel_account锚点。仅在实际取得可信依据且入口允许时登记;不得将模型抄写的自报资料标成channel_context。身份模块的accountAuthenticated=false表示它不执行平台认证,不能改写为true冒充登录验证。
-
-已有档案直接核对复用;称呼改变不改稳定账号键、不重建员工或旧会话、不改旧报告。当前会话的私有接续可记录实际用户名、员工档案键(已取得时)、本人提供的displayName、账号核对状态和称呼同步状态,未知项留空;无可信账号前只保留在当前对话的私有上下文,不跨员工复用。称呼作为展示资料与账号关联,不把用户名或稳定账号ID写入公开报告正文。
-
-持久同步按当前服务合同和真实回执判断。现有 `employee-name` 是企微发送者作用域的称呼接口,不能给fmode账号伪造botId/senderId使用,也不新增其输入字段。网页端没有对应受控保存入口时,说明称呼仅在当前对话使用、待同步至看板;没有可信身份时说明账号归属待核对。本地缓存或聊天记忆不等于服务端绑定,只有实际保存成功并回读同一账号对应的展示称呼后,才确认同步完成。缺少宿主登录上下文或适用接口时报告相应缺项,不自行修改平台或业务服务。
+## 网站账号与称呼
+
+首次使用工作坊且没有已核验绑定时,先询问称呼和已开通的工作坊账号。已有信息只请本人确认;不询问密码、验证码、Token或无关个人资料。不从中文姓名猜拼音,不代建平台账号。账号不存在、企业不符或已有绑定冲突时,说明具体问题并请学员核对,不新建替代成员。独立研究可继续,成果暂不提交到看板。
+
+学员自报账号只用于查找;受控名册只能证明账号存在,不能证明说话者就是本人。优先用当前消息宿主提供并经服务端验证的登录绑定;没有适用可信桥接时,使用服务合同声明的 `ksfWorkshopAccount` 首次确认链路:
+
+1. 复用当前员工的本地 profileKey;尚无档案时按已提供账号登记待核对档案,不创建业务会话或空报告。
+2. 先执行 `account-status`。已绑定则复用返回的 memberKey,当前自报账号冲突时停止受影响写入;未绑定才执行 `account-prepare`,传本人提供的账号和称呼。
+3. 把服务返回的 confirmationUrl 发给学员。学员在该页面登录本人平台账号并明确确认;页面直接与平台校验,密码与Token不进聊天或报告。仅回复“已绑定”不算成功。
+4. 再执行 `account-status`,必须读到 status=bound、正确账号/企业和同一 memberKey,才说绑定完成。随后用原 profileKey 执行 workshop-start;核其 accountBinding.status=bound、memberKey 与上述一致。
+5. 每次保存后精确回读报告和公开看板,核会话、报告都映射至同一 memberKey。首次账号确认本身不产出报告。
+
+工具命令沿既有受控凭据入口(仅在服务合同已声明支持时使用):
+
+`node <Skill根目录>/scripts/ksf-secure.mjs account-prepare --input <私有绝对路径JSON> --request-id <本次请求ID> --agent-profile <自身完整Agent档案键>`
+
+prepare JSON为 `{"participant":{"profileKey":"当前员工完整档案键"},"username":"本人确认的账号","displayName":"本人提供的称呼"}`;status改用 `account-status`,JSON只保留participant。不要替学员调用confirm;服务身份不能冒充本人登录。链接过期可为同一profileKey重新prepare,不换员工键。
+
+fmode平台公开App ID为 `ncloudmaster`,企业ID为 `FKieRbIoGt`,康师傅业务App ID为 `FKieRbIoGt_main`。平台稳定用户ID不能填进业务 `participant.userId`。已取得真实平台ID时放 `account.accountId`;未取得时不把用户名冒称用户ID。既有旧档案可由服务端已核验别名继续引用,不改旧档案/参与者键以“消除重复”。本地模块的accountAuthenticated=false仍表示它不执行平台认证;认证事实以服务端绑定回执为准。
+
+同一平台用户ID+企业只对应一个 `platform-account:<摘要>` 注册成员。课题、会话、Agent、昵称变化可以增加会话或账号别名,不增加看板成员。多会话/旧参与者通过服务端显式memberKey关联;不按姓名或模型自报账号合并。已有报告保留原ID、正文、版本、来源及原始提交快照,仅补账号关联。公开页面不暴露平台ID、私有绑定凭据或会话原始标识。
+
+没有适用的身份接口或可信宿主上下文时,报告“账号绑定待完成”,不能把聊天记忆、本地档案、网页登录成功或成员名册当作服务端绑定完成;不得伪造企微bot/sender来使用employee-name。既有企微发送者的登记仍按后续章节执行;若需与网站账号统一,必须取得受控账号关联,不能只凭同名合并。
 
 ## 取得真实身份字段
 

+ 4 - 4
skills/ksf-workshop-runtime/references/workshop-analysis.md

@@ -85,7 +85,7 @@
 
 按 [战报验收细则](workshop-research-acceptance.md) 核任务回应、原件/对象/资格/分母和实际覆盖,明确可用集合及用途限制,再按 [VOC聚类细则](workshop-voc-clustering.md) 形成四层关系、主题成员、痛点库、KANO表与人群×场景矩阵;不能跳过待核原因后把预聚类整体升级为已核需求。
 
-需求库结合实际任务影响、替代/取舍、人群差异与证据给研究先后建议,频次和KANO只作相应依据;重要性未知不当低重要,不要求在此提前作机会S/A/B。下一段使用需求键和该建议开展供需比较,已核编码/成员优先复用。
+需求库结合实际任务影响、替代/取舍、人群差异与证据给研究先后建议,频次和KANO只作相应依据;重要性未知不当低重要,不在此提前作D2-05的机会三维排序。下一段使用需求键和该建议开展供需比较,已核编码/成员优先复用。
 
 先核对象和上下文,再归人群、场景、痛点/期待和JTBD;原文明示与研究推断分开,未知日期/人群保留未知。社媒与电商、平台评分体系、主评与追评分别处理,多标签不当互斥人群。
 
@@ -109,7 +109,7 @@
 
 ## S3 候选机会与推演
 
-先按 [风味趋势与机会发现](workshop-opportunity-discovery.md) 形成产品机会及独立指标初表,再按 [三源交叉](workshop-three-source-opportunities.md) 推演S×U×C、核真实来源共用关系和五力约束,逐卡保存并形成V1.0。趋势、指标和候选的证据状态分别说明,三维/五力不代独立证据或机会优先级。
+先按 [风味趋势与机会发现](workshop-opportunity-discovery.md) 形成产品机会及独立指标初表,再按 [三源交叉](workshop-three-source-opportunities.md) 用S×U×C定位候选,核商品事实、用户原声、工艺条件三类证据,逐卡保存并形成V1.0。趋势、指标和候选的证据状态分别说明,五力只补适用约束,不代三源证据或机会优先级。
 
 关联赛道、用户和场景材料,列现有替代、我方产品关系、差异与企业条件。三维共用同一材料时说明,不作为独立三源证明。波特五力用于有依据地检查约束,缺项列待核。
 
@@ -117,9 +117,9 @@
 
 ## S4 验证、模型与可行性
 
-依次按 [证据与优先级细则](workshop-opportunity-validation.md)、[商业与供应链细则](workshop-commercial-feasibility.md) 处理V1全池。S/A/B、待评与补证顺序分别记录,V2保留每条候选去向;工厂联动使用真实反馈/授权交接,不把待对接写成已确认。
+依次按 [证据与优先级细则](workshop-opportunity-validation.md)、[商业与供应链细则](workshop-commercial-feasibility.md) 处理V1全池。v3逐维1–3分、依据、未知项和补证顺序分别记录;任一维1分不进前三,V2保留每条候选去向。工厂联动使用真实反馈/授权交接,不把待对接写成已确认。
 
-逐项说明模型、量表、权重、来源和条件,未知不填零。没有已确认模型时可提出清楚标为草案的评价方法,不能把草案结果当企业评审结论。双模型分工、实际输入/输出和分歧处理沿本题验证配置卡,真实结果分列,一致不替代原件核验。
+逐项说明量表、来源和条件,未知不填零;v3不私加总分公式或权重,不将课堂排序当企业评审结论。另有明确业务量表时注明适用范围。双模型仅沿本题真实约定及能力执行,实际输入/输出和分歧分列,一致不替代原件核验。
 
 按需求证据、差异、商业价值和执行条件作适用比较,优先级不是成功概率。把已验证、待验证、特定约束下不可行分开;成本估算不等于核价、零售价不等于成本、整盒重量不等于面饼净含量,买得到原料不等于产线可做。政策原文、页码/条款、适用日期和产品条件分别核,不把应用摘要当法规原话。
 

+ 3 - 1
skills/ksf-workshop-runtime/references/workshop-commercial-feasibility.md

@@ -1,6 +1,8 @@
 # 商业及供应链可行性回推
 
-D2-06、系统阶段S4。承接 [优先级机会清单](workshop-opportunity-validation.md),把产品设想回推到经济、原料、工艺、产线和法规条件,产出**可行性回推表、机会卡清单V2.0**。S/A/B是进入本节的研究初排,不作为成本、量产或合规已通过的证明。
+D2-06、系统阶段S4。承接 [优先级机会清单](workshop-opportunity-validation.md),把产品设想回推到经济、原料、工艺、产线和法规条件,产出**可行性回推表、机会卡清单V2.0**。当前v3沿三维评分及未知项承接,不作为成本、量产或合规已通过的证明。
+
+v3 的回推明确对比 B0 现状与 O1 目标方案,列收入、渠道费用和损耗条件;条件不同先说明差异,不能直接比总额。一次费用、资本投入、营运资金分开,机会卡增成本区间、目标价格带、两路对比和合规条件。课堂估算、本组经验、企业确认与待确认分列;手册样卡比例和参数须核原件及适用性,不自动成为企业成本或法规结论。
 
 ## 1. 建立可比较的产品与经营基准
 

+ 7 - 3
skills/ksf-workshop-runtime/references/workshop-concept-presentation.md

@@ -10,6 +10,8 @@ D2-08、系统阶段S5。承接 [价值主张及卖点清单](workshop-value-pro
 
 提案按下列逻辑呈现,章节可合并,但核心对应不能丢:
 
+当前 v3 同时组织一句话(不超过 40 字)、一页摘要与全案三层阅读;现场展演另按手册五页以内的要求,不把一句话或展演页替代完整归档内容。按结论→依据→风险→行动串联。决策圈/协同圈/生态圈的预期问题与实际质询分开,实际答不出的问题保留到 V3 和下一步。
+
 1. 研究问题与范围、目标人群/场景/JTBD及证言,为什么值得研究。
 2. 市场/竞品与现有解决、机会差异和三源推理,支持、反证与来源共用关系。
 3. 优先级及规则、商业/供应链/合规条件,哪些已核、哪些仍为假设。
@@ -53,11 +55,13 @@ V3逐项承接V2全池:稳定候选键、真实机会/报告/方案编号及
 
 代表案例从实际小组成果选取,说明选择依据,例如证据链清晰、推理有代表性、验证中发现关键反证或约束;不只选看似成功的方案,不设虚构的小组数。保留组别/必要归属、报告与卡号、原问题、研究路径、关键证据/变化、当前结论和可复用经验/限制。没有真实案例则列待形成,不复制示范当本届成果;跨组材料按实际授权和公开范围使用。
 
-## 5. 汇总七类成果与待验证问题
+## 5. 汇总 13 份环节成果与待验证问题
 
 集中保留会改变推荐、规格或可行性判断的待验证问题,逐项说明影响哪条结论、需取得什么证据、不同结果如何改变建议。它是提案的不确定性说明,不展开长期执行日历。49天行动计划属于课后另行任务,本节不生成、不附在提案中,不列入课堂验收;用户后续明确要求时再沿真实条件处理,不能自动安排人员、日程或后台执行。
 
-用七类导航汇总实际成果:市场报告、社媒场景报告、用户/竞品证言池、三方机会卡、产品论证机会清单、场景买点方案、产品概念提案。每项列标题、真实ID/版本、实际页面、完成范围和缺项;一份报告承载多项时注明相应章节,多个分册则列全导航。不把应交清单或原课件历史数字写成已交成果。
+按 [v3 的 13 份产出物](workshop-v3-outputs.md) 逐环节列实际标题、真实 ID/版本、报告/HTML 页面、所在章节、用途、完成范围与缺项。配置卡、任务卡、验收记录、指标初表均独立定位;不因归入方法分类而略去。另可保留七类内容索引,但不能用七类已齐代替 13 环节交付。一份报告承载多项时精确到章节,多个分册则列全部真实编号;本地路径不当公开入口。不把应交清单或样卡数字写成已交成果。
+
+成果导航第一行保留本题真实质询中最影响判断的未答问题,说明结营后第一周先用哪份现有成果补哪项证据;不因此自动建课后项目或安排人员日程。V3 未经历实际质询则标待反馈,不编造质询发生。
 
 ## 6. 分别保存、回读与验收
 
@@ -67,4 +71,4 @@ V3逐项承接V2全池:稳定候选键、真实机会/报告/方案编号及
 
 课程项目只有在真实S5、存在关联本项目的S5成果和currentConceptRef且任务已授权结项时,才用project-progress记录completed并回读事件;有关键缺口时保留在研/待验证或按原合同blocked,不因课程结束自动结项。项目完成不等于企业审批、技术定型或正式报告提交;正式报告依旧preview→真人确认→submit,不自动代为确认。
 
-验收:提案论证与前序可回查;实际/预期质询分开;V2→V3全池有去向;代表案例真实且有依据;方案若保存有真实连续版本及项目/材料/工艺关联;待验证问题对应实际判断,未擅自扩展课后任务;七类成果导航和缺项真实;保存/回读/看板/项目完成分别报告。内容完成但独立方案、反馈或展示仍缺时分项反馈,不报全部已完成。
+验收:三层提案论证与前序可回查;实际/预期质询分开;V2→V3全池有去向;代表案例真实且有依据;方案若保存有真实连续版本及项目/材料/工艺关联;未答问题对应实际判断,未擅自扩展课后任务;13 份环节成果导航和缺项真实;保存/回读/看板/项目完成分别报告。内容完成但独立方案、反馈或展示仍缺时分项反馈,不报全部已完成。

+ 8 - 6
skills/ksf-workshop-runtime/references/workshop-course-flow.md

@@ -6,6 +6,8 @@
 
 原课表导入样板课D1-00归授课PPT与现场演示,不列入Skill的独立执行环节,不为“范式共识”建后台报告。以下13个正式研究环节保持课表先后次序,第一节为D1-01。
 
+当前课程的应交形态、三源定义、评分与交接以 [v3 的 13 份环节产出](workshop-v3-outputs.md) 为准。13 个环节逐项定位到真实报告/章节/文件;旧七类内容索引及看板 11 类报告不能代替环节清单。三份大课只教方法,不另列成果。
+
 ## 任务定位与共用处理链
 
 先核本题的研究对象、真实限制、已有成果和当前项目状态,再定位用户要求的一个环节、一段课程或整条研究链。前序已有可复用成果时直接核编号与依据,不为补齐课表痕迹重做研究。用户只问查询或解释时按只读范围处理;已要求执行并同步的研究任务,核对归属并沿用已有称呼完成保存,不额外发起个人资料开场。
@@ -148,7 +150,7 @@ moduleId仅是本地业务跟踪信息,不是API新字段。stageCode仍只用
 
 - **执行细则**:先读 [三源交叉机会推理](workshop-three-source-opportunities.md),建立三维/来源对应,逐卡推演并核波特五力。
 - **输入**:D2-03机会线索及实际编号、需求/证言/场景、赛道/供给/替代与我方条件、配置/来源版本及缺口。
-- **处理**:按有依据的S×U×C关系组合,列支持/反对、差异、共用来源和待验证关系;五力各列事实/解释/影响及未知。逐候选保存独立机会卡及报告,核真实编号关联,再汇总V1.0和暂缓/失败去向。
+- **处理**:用S×U×C定位候选,再按商品事实、用户原声、工艺条件核三源;研发侧工艺注释真实记录,AI不代签。按结论/三源/反例/未知/下一验证/工艺注释六字段交卡。五力仅补实际相关约束。逐卡保存独立机会及报告,回读后汇总V1.0与暂缓/失败去向。
 - **判断**:三个维度不等于三个独立来源,设想不当已观察行为;五力不代需求证据或默认求分。候选不套固定抱怨数/竞品家数/我方空白门槛,不代最终选择或旧排序。
 - **核心产出**:候选机会卡清单V1.0。独立卡用`workshop-save`的opportunity及`opportunity_card`报告,清单用`assessment_report`,保存后回读报告/卡片并核看板;空候选不凑卡,部分失败不伪造编号,完整池交下一段先比较后选项目。
 
@@ -158,8 +160,8 @@ moduleId仅是本地业务跟踪信息,不是API新字段。stageCode仍只用
 
 - **执行细则**:先读 [机会验证与优先级排序](workshop-opportunity-validation.md),从完整候选池回查证据再作可解释初排。
 - **输入**:完整候选清单V1.0、证言/市场证据和验证配置;已有明确选择或项目时一并引用。
-- **处理**:核痛点/场景→现有解决→差异→统计/关键主张的闭环,回原件与计算,保留反证/共用关系及核查覆盖。真实双模型在同版输入上独立审查再比对,缺入口标待执行。按适用模型或已公开草案规则产生S/A/B,逐维列理由、条件与验证先后;全池保留去向,不先建项目。
-- **判断**:优先级是验证先后,不是成功概率;未知/未评估与B级分开。同档无依据强分时并列,补证顺序与机会等级分列;双模型缺项不报全部验收通过,模型一致不代事实。不擅改既有活动排序。
+- **处理**:核痛点/场景→现有解决→差异→统计/关键主张的闭环,回原件与计算,保留反证/共用关系及核查覆盖。实际模型复核如实记录,缺入口不冒称已执行。当前v3按证据强度/可做性/商业价值各1–3分,逐分列依据;任一维1分不进前三,未知项单列,全池保留去向,不先建项目。
+- **判断**:优先级不是成功概率;未知不能填成低分,商业价值须本组复核。无明确公式不私加权重强排;证据不足以区分时并列或给条件顺序。补证先后与机会排序分列,模型一致不代事实,不擅改既有活动排序。
 - **核心产出**:证据闭环核验表、验证模型/适用规则、优先级机会清单。未建项目时按当前合同以S4保存不带projectId的`assessment_report`;已有项目的单项验证报告按项目当前阶段保存。实际选定方向进入项目验证时再完成下述S3项目衔接,不为保存清单而创建虚假项目。评分与说明写报告支持的结构,不向opportunity添加合同不支持的字段。
 
 ### D2-06 商业及供应链可行性回推
@@ -182,9 +184,9 @@ moduleId仅是本地业务跟踪信息,不是API新字段。stageCode仍只用
 
 - **执行细则**:先读 [概念提案路演与分享](workshop-concept-presentation.md),把真实成果、方案、质询与清单演进分别保存核对。
 - **输入**:前序市场、社媒、证言、机会、验证、买点成果及真实反馈。
-- **处理**:组织结论、证据、产品设定/条件和下一步,按真实项目/材料/工艺与连续版本另存需要的独立方案,核项目当前方案及pendingQuestions。实际质询与预期问题分列,V3承接V2全池并留变化依据;代表案例从实际成果选择,附七类成果导航,集中列明影响建议的待验证问题。
+- **处理**:组织结论→依据→风险→行动的一句话/一页/全案三层提案,按真实项目/材料/工艺与连续版本另存需要的独立方案,核项目当前方案及pendingQuestions。实际质询与预期问题分列,V3承接V2全池并留变化依据;代表案例从实际成果选择,附13份环节成果导航,集中列明影响建议的待验证问题。
 - **判断**:明确建议继续验证、补证或暂缓的条件,区分课堂完成、企业决策和正式发布。课程分享不生成虚构领导点评或真人确认事件。
-- **核心产出**:《产品概念提案》(路演版本,`concept`报告及独立方案)、机会卡清单V3.0(`assessment_report`)、小组代表案例与七类成果导航,列决定性待验证项及其对建议的影响。课堂完成按合同核当前成果与方案后记录;正式报告仍走真人确认流程。
+- **核心产出**:《产品概念提案》(路演版本,`concept`报告及按需独立方案)、机会卡清单V3.0(`assessment_report`)、13份环节成果导航,列决定性待验证项及其对建议的影响。课堂完成按合同核当前成果与方案后记录;正式报告仍走真人确认流程。
 
 ## 核心成果的最终汇总
 
@@ -198,7 +200,7 @@ moduleId仅是本地业务跟踪信息,不是API新字段。stageCode仍只用
 | 场景化用户买点方案 | D2-07 | 需求与买点映射、产品验证及待测试表达 |
 | 产品概念提案(路演版本) | D2-08 | 独立方案版本、前序成果导航、质询与下一步 |
 
-结营报告按上述七类建立成果导航,链接实际标题、编号、版本、页面与缺项;缺件如实列出,不把“应交付”写成“已生成”。本次三个半天到概念提案及评审汇总结束。49天行动计划为课后另行任务,不附在本次提案中,也不作为课堂完成条件;后续仅在用户明确要求时开展,不自动延长课表或安排任务。
+结营报告以[v3的13份环节交付](workshop-v3-outputs.md)为主导航,上表七类作为兼容内容索引;链接实际标题、编号、版本、页面与缺项。缺件如实列出,不把“应交付”写成“已生成”。本次三个半天到概念提案及评审汇总结束。49天行动计划为课后另行任务,不附在本次提案中,也不作为课堂完成条件;后续仅在用户明确要求时开展,不自动延长课表或安排任务。
 
 清单演进逐项可回查:V1保留候选与三源依据;优先级清单补证据核验、评分/等级及理由;V2补商业、生产、合规条件及保留/修改/暂缓/排除的原因;V3补买点、概念、实际质询与最终建议。沿稳定机会键和真实编号对应前后变化,每次列新增、修改、暂缓和排除及依据,不以覆盖旧表或只换版本名替代验证过程。
 

+ 9 - 7
skills/ksf-workshop-runtime/references/workshop-deliverable-contracts.md

@@ -2,6 +2,8 @@
 
 用于课表13类产出。手册负责发起当前任务,本Skill负责选材、分析、反证和成报。不存在固定案例答案,也不要求学员反复填研究表。
 
+当前 v3 的 13 份逐环节交付、三源定义、三维 1–3 分排序、最终导航及交接要求见 [v3 产出与交接](workshop-v3-outputs.md);本页用于内容分析的深入检查,不以历史分档或额外资产要求替代 v3 核心成果。
+
 ## 先确定分析单位,再检索
 
 每节先在工作底表写一行:决策问题→待判断主张→分析单位→所需数据/字段→来源与范围→支持/反证→何时足以判断。员工不必手填底表;Agent负责完成,并在报告方法附录保留实际查询和选材理由。
@@ -69,11 +71,11 @@
 
 选材:先回读本题图谱、源记录和实际接口contract,盘点可用字段和模型入口;抽查跨商品、跨平台或跨时间的高风险主张。
 
-分析:将证据类型、对象身份、时间、去重、分母、引用、冲突处置和复核责任落实为验证配置卡。输出可复用的检索、编码、反证审查、修订四类提示词资产,带本题输入和应回传结构。双模型须冻结同版材料分别独立执行;无第二入口时保留待执行状态,继续原件和计算核查。将发现的错误修回图谱。
+分析:将证据类型、对象身份、时间、去重、分母、引用、冲突处置和复核责任落实为验证配置卡,明确检索、编码、反证审查、修订的方法和回传依据。员工复制提示词属于手册,不要求在本节另交提示词资产包。实际使用双模型时冻结同版材料独立执行;无第二入口如实标未执行,继续原件和计算核查。将发现的错误修回图谱。
 
-应交付:验证配置卡:主张/所需证据/核法/判定/责任与版本;提示词资产包:检索、编码、反证审查、修订;可复制直接使用;前序实质修订及双模型实际执行/分歧记录。
+应交付:验证配置卡:资料资格/统计与引文口径/分工/分歧处理/版本;回查记录及前序实质修订;模型实际执行和未执行状态分别记。
 
-验收:四类资产有可执行输入与回传要求,不只是名称。;同一助手改角色不算双模型,未执行不能报通过。;规则发现错误后实际修改结论。
+验收:规则可执行、回查有原件与实际结果;同一助手改角色不算双模型,未执行不能报通过;规则发现错误后实际修改结论。
 
 不合格示例:只有“认真核验、不要幻觉”口号,或同一模型自问自答后写交叉验证通过。
 
@@ -169,7 +171,7 @@
 
 分析:从矩阵推演可比较方案;每卡给目标任务、现有替代、具体产品变化、收益机制、需要保留的体验、代价、支持/反证、五力约束与最脆弱假设。若只差实施细节就合并,避免一条观察任务拆成三卡。探索性概念允许提出新组合,但拟议设定与已核产品事实分列;候选不足不凑数。保留完整V1及暂缓线索。
 
-应交付:能独立阅读的三源候选机会卡:S/U/C、差异、机制、代价与反证;V1全池:稳定键、机会/研究任务区分、关键依赖与去向;针对候选的五力与替代约束分析。
+应交付:能独立阅读的六字段机会卡:结论、商品事实/用户原声/工艺条件三源、反例、未知、下一验证、研发侧工艺注释;S/U/C仅作定位坐标。V1全池保留稳定键、机会/研究线索区分、真实卡号和去向;竞争分析补实际相关的约束。
 
 验收:能说清产品拟怎样改变,观察任务不能冒充产品。;多个候选在任务或价值机制上确有差异。;供给存在不妨碍改良,但必须解释增量。
 
@@ -181,11 +183,11 @@
 
 选材:回查全池关键主张及反证,冻结同版资料;补能改变排序的对象、替代和约束。真实第二模型独立复核;方法依据不代本题数据。
 
-分析:沿Skill研究草案规则,逐候选比较需求依据、增量差异、关键反证、商业/工程依赖及下一验证价值。给可解释S/A/B初排,或说明具体为何不能分档;不能因财务未知就把所有探索候选一律待评,也不强凑S级。将机会等级、补证顺序和立项状态分开。重点实验写基准/变量/招募与条件/观察项/决策规则;保留第二模型真实结果和分歧,未执行单列。
+分析:当前v3按证据强度、可做性、商业价值各1–3分,逐分说明课堂证据/本组经验依据,商业价值须本组复核;任一维1分不进前三,未知单列而不填低分,不凑前三。比较时解释证据、差异与约束,未指定总分公式不私加权重。将机会排序、补证顺序和立项状态分开;重点验证写基准/变量/条件/观察项/决策规则。模型复核有真实结果才记执行。
 
-应交付:证据闭环表与全池S/A/B探索初排;逐卡等级理由、升降级条件及验证先后;重点比较实验与实际双模型/分歧记录。
+应交付:证据闭环表、三维分值/逐分依据/排序理由、未知项表与全池去向;下一验证及其决策条件;模型真实执行/分歧或未执行状态。
 
-验收:能解释某项为什么排前;无依据的小数评分不用。;机会等级不是成功概率,也不等于立项批准。;第二模型未执行时不能报本节全部通过。
+验收:能解释某项为什么排前;逐维1–3分有依据,任一维1分不进前三;未知与低分分开;机会排序不是成功概率或立项批准。第二模型未执行不能报双模型通过,但不以未约定的第二模型阻断本节交付。
 
 不合格示例:全池“待评、继续研究”,或按模型凭空给8.7分与成功率。
 

+ 3 - 1
skills/ksf-workshop-runtime/references/workshop-delivery.md

@@ -51,7 +51,7 @@ D2下午沿“V1全池→证据核验/等级及待评→回推条件与V2→价
 
 ## 3. 保存一份可读的小节报告
 
-实质章节与七类课堂产出的对应按 [七类产出与成果导航](workshop-output-navigation.md) 处理;配置卡、任务包等保留实际用途,不为导航凑齐空报告。
+本节内容和下一环交接按 [v3 的 13 份环节产出](workshop-v3-outputs.md) 逐项核;实质章节的七类内容索引按 [成果导航](workshop-output-navigation.md) 处理。配置卡、任务包等均有自己的环节位置,不为数量凑空报告,不以七类索引或11类分类数代环节完成数。
 
 报告标题写课题与当前业务问题/成果,例如“拌面准备过程:器具、排水与口感的取舍”;归属和小组由现有session注入。面向员工的标题与主文不以课表编号、安装、运行日志作叙事;内部环节对应保留在既有任务记录或必要的关联说明,不改stageCode和taskKey。不要把真实账号、整段私人聊天或凭据写入公开报告。
 
@@ -108,6 +108,8 @@ concept-save的pendingQuestions存于项目meta,须由project-status的project
 
 ## 5. 每个环节的结果反馈
 
+当前课程结束一节时,完成实质业务回答及真实成果链接后,以【本轮产出】【还缺什么】【下一步】三行交接:指出实际产出位置、影响下一环的具体字段缺口,以及一个确实需要员工回答的关键问题。已有答案沿用,不为格式重复询问;没有待选事项可说明已具备的接续输入。按用户约定逐轮等待,不因写了“下一步”自动执行后续节。
+
 回复与报告按 [产品反馈与产出标准](workshop-feedback.md) 组织:先给本节产品认识、必要依据和取舍,再附实际成果及简短状态。简单回应不套固定模板,复杂比较给足可讨论内容;覆盖限制跟随具体结论,技术明细后置。员工不用先下载附件或读操作日志也应看懂结果。读取失败等影响结果的阻断仍直接说明。
 
 按用途控制交付数量:简短查数、解释和澄清直接回复;有实质报告内容时默认生成美观、独立可读的HTML,正文与rawText/report同源,按 [文件合同](workshop-report-parity.md#保存及实际文件) 关联同一报告版本。其他图片、图表或文件按 [下节](#6-必要的图片图表与文件) 判断。不要用ZIP、原始JSON、哈希清单及同内容多格式导出代替正文。有实质阶段成果且已授权同步时,给HTML预览/文件、后台报告链接和简短核对状态,指出当前判断与需员工核对的业务点并接收真实反馈;未到报告交付点不为制造附件建空报告。用户要求案例留档、导出、排障或交接原件时,可将所需材料集中为一个ZIP,避免散发多个重复文件;必要的研究追溯记录仍须保留。

+ 24 - 0
skills/ksf-workshop-runtime/references/workshop-evidence-counting.md

@@ -23,3 +23,27 @@
 ## 案例和示例
 
 复用历史材料时核原来源、取得时间、适用对象和查询范围,不借用旧批次数字替代本次计算。纯教学示例须明确标sample,不作为真实消费者证言,也不混入真实研究分母。案例只帮助解释方法,不预设本题结论或产品方向。
+
+## 结论依据与全体相关资料总结
+
+报告沿“结论→全体相关材料的统计与对照→代表原话/原件→解释、反例与适用范围”组织。关键资料精选展示,全体相关资料仍须纳入统计或说明去向;不能先选结论,再只挑支持它的记录。技术可行性、性能和因果结论需各自适用证据,不能用评论多数代替实验或工程证明。
+
+1. **先交代本题材料全貌。** 按本轮查询/采集条件固定相关记录集合,注明来源、时间、对象及已有库/新增资料关系。逐层列候选、重复/不相关等排除、待核、纳入和实际已完成分析的数量;互斥去向在相同单位与去重口径下可核总和。未取得的正文不计已读;跨平台的评价、帖子、评论、商品、资料篇数和互动量分层,不强行求和为独立消费者。
+2. **全部相关资料有去向。** 对固定范围内已取得的相关材料逐条或分批编码,保留完整成员ID、纳入/排除原因、主题/场景和判定结果。对决定结论的支持、反对、混合、未知及不同场景分布分别汇总;一条记录可多标签,同主题内只计一次,不把主题之和当分母。未完成部分列实际分析n/应分析N,不据精选引文或关键词命中声称全量。
+3. **主文展示统计总结。** 本题有可统计的多条相关材料时,至少有能支撑关键判断的主题/维度汇总,给有效n、适用N、百分比、单位、时间/对象/来源、去重与多标签规则、解释和产品含义;相关的正向/负向、支持/反对及差异一并比较。不把完整成员名单铺满正文,也不把完整口径全部藏到附件,让员工看不到分母。
+4. **代表材料解释数字。** 每项关键结论连接对应统计/产品对照及有解释力的真实原话,保留最有影响的反例。原话卡是示例证据,卡片条数不是统计分子,后台引文数不是支持强度。互动赞数与评价条数各按原单位记录,单条高赞不能当数十万名同意者;未提及不能直接称反对或无需求。
+5. **不足时如实交代。** 无可靠分母时给已核数量、具体定性比较及未知,不填百分比;N=0时写无有效样本,不算0%需求率;只分析部分/样本就按其范围总结,明确全量尚未完成。结论的措辞和推广范围随证据收窄,不为图卡好看编数字、任意设强/中/弱刻度,亦不把定性资料强量化。
+
+图中的占比条只能表达真实n/N;“信号强/弱”若采用须解释比较范围、方法与判断条件,不能直接由引文数、热度或随意进度条推导。价格感知按真实比较对象、规格、购买条件和原话分层;不能把不同价格参照的原句拼为总体支付意愿。
+
+## 统计总结的现有报告表达
+
+仍用已有`table`与`findings`,不增加API顶层字段或section.kind。材料范围与处理去向用普通表,保留实质正文;关键统计可用语义ID为`statistics-summary`的table,下列列名和顺序固定:
+
+```json
+{"id":"statistics-summary","kind":"table","title":"本题相关材料的关键统计与含义","data":{"cols":["维度/主题","提及数 n","有效样本 N","统计口径与范围","数据解释与限制","产品含义","证据"],"rows":[]}}
+```
+
+上面仅为结构说明,空rows不是已完成统计。每行依次填主题、已核整数n、适用整数N、具体口径、对数字的解释与限制、对产品判断的含义、现有`report.evidence`键(没有适用引文时空字符串)。未知计数填null,不能填0;0只用于已确认零条,分子不能大于分母。HTML和看板从同一n/N计算一位小数占比,提供摘要卡及原表;未核分母不画占比条。`findings`连接相同证据键,逐字原话及原件定位依既有来源合同保存。
+
+`scripts/report-statistics.mjs`只校验表的结构、数字范围和引用键,并计算占比;不替代真实成员编码、统计复算或研究质量判断。统计表、资料覆盖/去向、成员索引及关键原话都应能随报告版本回查。发送前核同一结论在聊天、rawText、report、HTML中的统计口径一致;只核页面显示不能证明数字来源真实。

+ 4 - 2
skills/ksf-workshop-runtime/references/workshop-feedback.md

@@ -52,8 +52,8 @@
 | D2-01 战报验收 | 哪些材料可用于哪一种判断,什么误差会改变结论 | 可用集合、排除/待核原因及修复事项;保留不受影响的分析,不把验收变成全盘重做 |
 | D2-02 VOC聚类 | 谁在何种情境下要完成什么任务,现有办法哪里不够 | 四层编码、需求主题/反例、痛点库、KANO状态、人群×场景及研究先后理由 |
 | D2-03 风味×矩阵 | 哪些需求与供给之间有值得研究的不匹配或改良空间 | 有成员依据的指标初表、矩阵及机会线索;结构/趋势、未见/未覆盖分开 |
-| D2-04 三源机会 | 每个候选为什么值得研究,关键关系缺哪一环 | 实际候选卡和V1全池;S×U×C、来源共用、替代/五力约束与可证伪主张 |
-| D2-05 优先级 | 为什么先验证此项,出现什么结果应升降或停止 | 证据闭环、S/A/B或待评及依据,机会等级和补证先后分开;保留全池 |
+| D2-04 三源机会 | 每个候选为什么值得研究,关键关系缺哪一环 | V1全池与六字段卡;三源为商品事实/用户原声/工艺条件,S×U×C作定位;来源共用、替代约束与可证伪主张 |
+| D2-05 优先级 | 为什么先验证此项,出现什么结果应升降或停止 | 三维1–3分及逐分依据、任一维1分不进前三、未知项单列;补证先后与机会排序分开,保留全池 |
 | D2-06 可行性 | 在收入、成本、产线和合规约束下怎样改才值得继续 | 可重算情景及小改/大改的实际取舍、决定性条件、V1→V2逐项去向 |
 | D2-07 价值与卖点 | 某项产品变化给谁带来什么收益,凭什么相信 | 需求→要素→收益→表达对应;有内容的价值主张和待测文案,不把需求证据当性能证明 |
 | D2-08 提案与分享 | 现在建议推进什么、保留什么,后续谁需验证哪项 | V3全池、概念提案、实际质询/待反馈、成果导航和决定性待验证问题;不编企业批准 |
@@ -97,6 +97,8 @@
 
 报告摘要先给产品认识、比较或取舍;每章围绕一个实际问题安排正文/表格,方法、覆盖和修订记录后置。图谱保留实际层级与关系,机会卡说明任务、现有办法、拟改要素、收益假设和最关键的不确定性。下一环节直接引用稳定键、实际编号/版本和适用范围,避免每节重抄原材料。
 
+“只反馈关键资料”不表示只统计几条精选样本。重要结论同时有对应材料/对照与本题全体相关资料的统计总结:先简明交代纳入、排除、待核及实际分析覆盖,再给关键主题/支持/反对/场景分布的n/N、解释、代表原话和反例。聊天可摘最重要统计,HTML及入库正文保留完整实质汇总;详细成员索引后置。部分分析不能称全量,无法合理量化的技术/定性资料给具体对照和边界,不为了完成统计卡编比例。
+
 有实质报告内容时默认生成HTML并发员工核对,先按本节细则审内容,不能只把聊天摘要排版;与后台同版正文和证言一致,沿 [文件合同](workshop-report-parity.md) 关联、回读。其他图片按解释用途制作;统计图使用确定性数据绘制,商品图用真实已取得素材,概念图标设想。标题、单位、图例、来源索引可读,390px下可分区或容器内滚动,不能靠整页缩小让小字“无溢出”。后台仍用当前已支持的para/longpara、table等结构保存对应内容,不自造HTML渲染字段。员工确认针对明确报告版本,不把阅读、普通“继续”或保存回执当确认。
 
 发送前从使用者角度检查:市场同事能否判断信号及应关注的变化,研发同事能否看懂目标体验、改动与验证,负责人能否理解条件和取舍;只检查当前任务实际面对的角色,不为每个角色另写一份重复报告。再核数字、引用、修改意图与保存范围;版式检查不能替代研究内容检查。只写“已完成、见附件、建议继续调研”不能算有效交付。

+ 19 - 5
skills/ksf-workshop-runtime/references/workshop-opportunity-validation.md

@@ -22,13 +22,27 @@ D2-05、系统阶段S4。接续 [三源交叉候选清单V1.0](workshop-three-so
 
 原件回查和计算重算只处理当前授权内可取得材料;用户已给定的资料范围和采集限制仍有效。缺外部材料时先完成其余核查,保留具体阻断项;请求结果未知时先核原请求及已有原件,不盲目重发,也不为补齐证据扩大采集范围。
 
-## 3. 执行真实双模型交叉审查
+## 3. 按实际能力执行模型复核
+
+v3 不额外要求员工开通第二模型才可交本节成果。原件、计算和三维评分照实际材料执行;本题任务或验证配置已约定双模型时,再按下列独立复核要求处理,不将模型互评代替本组研发/商业判断。
 
 沿验证配置卡核两个真实、已授权模型入口,冻结同版候选、原件索引、规则与待审判断,分别独立完成复核;后者先不看前者结论。保留实际模型标识、输入/输出定位、执行状态及适用版本,再逐项比对事实、推理、反证和等级建议。只有一次模型调用或同一模型扮演两角色,不能记作已完成双模型。
 
-模型一致仍回到原件和计算;模型分歧按争议点核查,不投票决定事实,不无限重跑求一致。分歧未解时保留两种解释、影响和待验证办法。第二模型未接入、不可用或未授权时,如实列“待执行”,其余可用核查与初步排序继续;产出可用草案,但不能报双模型步骤或本节全部验收通过。
+模型一致仍回到原件和计算;模型分歧按争议点核查,不投票决定事实,不无限重跑求一致。分歧未解时保留两种解释、影响和待验证办法。第二模型未接入、不可用或未授权时,如实列“未执行”,不能报双模型步骤通过;环节成果另按v3的评分、依据、未知项和交付内容验收,不把未约定的额外模型当入场条件。
+
+## 4. 当前 v3:三维 1–3 分与未知项单列
+
+本工作坊默认使用 v3 量表:证据强度、可做性、商业价值各 1–3 分。每个分数逐项给实际依据,标明课堂证据/本组经验;商业价值须本组复核。先说明本题量表各档的可观察含义,缺依据不打分,不让 Agent 用模型常识代成本、产线或供应商确认。
+
+任一维为 1 分的候选不得进前三;候选不足不补足前三。未知单列成表,写缺什么、怎样取得、本次能否取得及影响,不能当 1 分/0 分或据此淘汰。对可比较候选结合三维实际依据解释顺序;手册未指定总分公式或权重,不私加乘法/平均数或虚构权重强排。同分且证据不足时并列或给条件顺序。
+
+报告展示三维得分、依据、规则、可比较范围、优先级及未知项全池去向。可另排补证优先级,但不把“值得先补证”伪装成机会已进前三。后续 V2/V3 保留本轮量表、分值依据及变化原因。
+
+按[v3保存约定](workshop-v3-outputs.md#入库与看板怎样对应)使用`course-priority`表承载机会、三维、依据及排序;HTML和看板从同一表生成课程评分卡。没有评分的维度保持未知,不用多人点评均分、历史S/A/B或推算总分替代。
+
+## 非 v3 任务的其他量表
 
-## 4. 按可解释规则产生S/A/B初排
+仅在业务方明确使用其他评价模型的任务中保留下述 S/A/B 草案;不以它覆盖当前 v3 三维规则,也不未经说明将两套标签相互换算。
 
 优先使用本题已有且适用的评价模型,记录量表、维度方向、权重、聚合、分档/并列规则和实际输入。企业给定的门槛与研究者建议分开;改变规则须保留版本和对排序的影响。没有已确认模型时,可使用下述**研究草案规则**,先公开规则再评,不把它称企业标准。
 
@@ -48,10 +62,10 @@ D2-05、系统阶段S4。接续 [三源交叉候选清单V1.0](workshop-three-so
 
 ## 5. 保存优先级清单并交接
 
-报告至少包含:V1全池及实际卡号索引、证据闭环表、双模型实际执行/分歧状态、评价规则与版本、逐维依据、S/A/B或待评及相对顺序、反证/条件、下一步验证与其余未评估项。用现有table和para/longpara,真实引文仍绑定业务sourceIds,不新增priority、score、modelA等API顶层字段。
+报告至少包含:V1全池及实际卡号索引、证据闭环表、模型实际执行/分歧状态、评价规则与版本、逐维得分和依据、优先级及未知项单列、反证/条件、下一步验证与其余未评估项。v3 用本页三维规则,其他明确量表按其适用范围说明。用现有table和para/longpara,真实引文仍绑定业务sourceIds,不新增priority、score、modelA等API顶层字段。
 
 以`workshop-save`保存`assessment_report`,顺序新任务stageCode=S4,建议taskKey=`<topicKey>:D2-05:priority-list`。无项目省略projectId;已有项目的单项报告遵守当前阶段,不为比较全池先建项目。按 [交付规则](workshop-delivery.md) 精确回读artifactId/版本和公开数据/页面,各自保留状态;结果未知先查原请求,不重建整池卡片。
 
 验收:V1候选去向齐全;关键主张可回查且核查覆盖明确;双模型执行与缺项如实;规则足以解释等级和顺序;未知/待评与低等级分开;有真实保存/回读及展示状态。本地草稿只算内容完成,不算后台已同步。
 
-交给 [商业及供应链回推](workshop-commercial-feasibility.md) 全池、等级/待评与理由、实际报告/卡号及版本、证据和反证、待核成本/工艺/合规条件及验证先后;不能只交S级并丢掉其余候选。
+交给 [商业及供应链回推](workshop-commercial-feasibility.md) 全池、三维评分/未知项与理由、实际报告/卡号及版本、证据和反证、待核成本/工艺/合规条件及验证先后;不能只交前三并丢掉其余候选。

+ 4 - 2
skills/ksf-workshop-runtime/references/workshop-output-navigation.md

@@ -1,4 +1,6 @@
-# 七类产出与成果导航
+# 内容索引与 13 份环节成果导航
+
+当前工作坊按 [v3 的 13 份环节交付](workshop-v3-outputs.md) 逐项验收;本页七类仅是跨报告的内容索引,既不是 13 份中的七份,也不代表只需交七份。配置卡、任务卡、验收记录和指标初表均须在对应环节导航中有真实位置。
 
 在形成或修改阶段报告时使用;保存接口沿用原入口,新增的report内交付标记与文件关联按 [个人报告交付与展示合同](workshop-report-parity.md) 核实际服务能力。手册定义当前问题与应交成果,分析方法和依据沿对应环节细则。各组比较轴来自真实任务、条件和材料,组号不决定研究方向。
 
@@ -26,7 +28,7 @@
 
 一份报告可承载多项,导航精确到现有报告和章节;一项也可跨多份报告。社媒材料未取得时不建空 `social-needs` 章节,说明缺项及影响;不能拿电商评论冒充社媒。原始证言较多时报告保留覆盖、必要原句和真实索引,完整数据沿研究库查回。独立机会卡仍按现有保存合同建立自己的编号,报告章节不替代对应业务对象。
 
-配置卡、任务包、调研验收和供需矩阵仍为实际课表成果,不强行塞入上述七类。它们保留原章节与真实任务系列,并在最终导航中按“方法、研究过程与补充材料”列出;不把待定位当未保存或删除依据。
+配置卡、任务包、调研验收和供需矩阵仍为实际课表成果,不强行塞入上述七类。它们保留原章节与真实任务系列,在最终 13 份环节导航中独立定位;“方法与过程材料”只是报告分类,不能降低其交付地位。不把待定位当未保存或删除依据。
 
 ## 任务、版本与展示
 

+ 2 - 0
skills/ksf-workshop-runtime/references/workshop-report-design.md

@@ -66,6 +66,8 @@
 
 正文先给关键解释,证据卡展示已保存引文;点击证据链再查完整引用关系。引文数量、关联成果数量及人数不是证据强度评分;来源登记日期也不是原帖发布日期。旧报告未保存原句时明确缺失,不从标题、摘要或模型记忆生成“原话”。独立HTML使用相同判断与证据编号,提供完整出处链接/脚注、可读引文和必要对照;两种载体的结论强度一致。
 
+关键结论不能只靠精选原话支撑。有可统计材料时,按 [全体相关资料总结](workshop-evidence-counting.md#结论依据与全体相关资料总结) 同时展示相关集合的覆盖/纳排/待核、主题或支持/反对的n/N、场景差异及解释,关键原话就近说明数字背后的事件。统计覆盖本题全部相关且实际完成分析的材料,不能把选出的原话卡当总体;未完成全量如实列覆盖,不能写“已总结全部”。可用既有table的`statistics-summary`生成同源统计卡,百分比条只表达样本内提及占比;强弱判断需要方法和条件,不画任意“信号强度”。
+
 ## 页面与图表怎样帮助阅读
 
 采用清楚的标题层级、留白和少量强调色。长报告给可用目录或页内导航,正文可连续阅读;汇报时可另有提要,不让整份内容依赖翻页动画、横向滚轮、全屏或外部脚本才能出现。HTML初始文本就应可读,未知指标显示未知,不用动画从0开始冒充真实数值。

+ 3 - 1
skills/ksf-workshop-runtime/references/workshop-report-parity.md

@@ -2,6 +2,8 @@
 
 报告分类、保存及附件能力以当前服务合同和实际回读为准;本地存在脚本不代表服务端支持相应能力。
 
+课程完整性按 [v3 的 13 份环节产出](workshop-v3-outputs.md) 检查;下述七类 outputs 是兼容的内容索引,11 类报告是阅读分类,两者均不等于课程产出份数。每个环节写真实 moduleId,并在报告中保留本节卡/表/清单的实质内容与下游用途。看板“已有正文”不自动代表内容齐全、HTML/证据已关联或员工确认。
+
 ## 归属与分类
 
 报告作者为可信当前员工,由已有 sessionId 继承。小组只组织个人,不建立共同作者报告。恢复任务沿各人的 workshopKey、taskKey、version;同名、同智能体或同课题不能合并员工身份。看板按“小组 → 组员 → 个人报告”,保留报告分类及点击阅读。
@@ -31,7 +33,7 @@
 ## 保存及实际文件
 
 1. 先读workshop-contract,核 `workshop.delivery.schema` 与附件能力。本合同未上线时保留完整本地内容,说明能力未就绪;需要继续沿旧服务保存时遵守原合同,不能称新分类和文件已同步。
-2. 对本题成品按相应细则完成内容自检。核心正文同时存rawText和report;引用真实sourceIds,证言逐字可查。每份报告默认生成独立HTML,由相同report数据渲染,不再独立编写另一套数字或结论。新helper不替代研究质量评审。
+2. 对本题成品按相应细则完成内容自检。核心正文同时存rawText和report;引用真实sourceIds,证言逐字可查。关键判断同时保留支持材料、全部相关资料的实际统计覆盖与纳排/待核去向、主题/反证分布及产品含义;统计只在聊天中出现不算报告已交。每份报告默认生成独立HTML,由相同report数据渲染,不再独立编写另一套数字或结论。语义统计表仍沿原有table保存,回读须核对应行的n/N、范围、解释和引用键。新helper不替代研究质量评审。
 3. 用既有加密入口保存。可运行下面的helper,它只调用冻结入口,不自行读取/输出令牌;写入只发一次,结果不明保留原请求号,先查回。
 4. 逐项核确切artifactId、个人会话/课题、任务系列、版本、正文、来源、公开投影。关联文件再核字节与SHA256。只有这些通过才说“已保存并在公开数据中核到”;浏览器实际打开正文后再说“页面已核”。
 

+ 6 - 0
skills/ksf-workshop-runtime/references/workshop-tasks.md

@@ -1,5 +1,11 @@
 # 工作坊任务输入
 
+## 首次账号关联(account-prepare / account-status)
+
+仅在workshop-contract已声明`workshop.accountBinding.enabled=true`时使用。首次询问称呼与已开通的账号,按[身份细则](identity.md#网站账号与称呼)完成本人登录确认;已有绑定先查再复用。同一账号只有一个注册成员,课题和会话不是新成员。未绑定时暂缓workshop-start/保存,不生成空报告。
+
+两命令均沿`ksf-secure.mjs`传`--input`私有绝对路径、`--request-id`和自身`--agent-profile`。prepare输入为`{"participant":{"profileKey":"当前员工档案键"},"username":"本人账号","displayName":"本人称呼"}`;status只保留participant。prepare返回的confirmationUrl交本人打开并确认;数字人只能查询status,不能冒充本人调用confirm。回读status=bound及正确memberKey之后再开工。学员说“已绑定”只触发回读,不直接当认证回执。
+
 ## 内置研究资料模块
 
 研究底料使用既有只读Python入口 `/opt/data/skills/ksf-voc-library/scripts/query_voc.py`,**不是ksf-secure的新子命令**。操作规则已纳入本Skill的 [研究资料操作](research-library/operations.md),先执行研究contract验实际代际,再按问题选search/facets/aggregate/get/source;未装不得声称可用。比如找份量反馈可用 `{"entities":["reviews"],"filters":{"brand":"康师傅"},"text":{"concepts":["portion_size"]},"limit":20}`,只限定问题实际给出的字段,不要求补齐平台/品牌/品类。商品ID、正文、规格/价格区间、时间、原文与条款、覆盖和来源都按目录选择路径;明确约束AND、同义组内OR,先精确关联再核上下文。同文评价按条数/去重文本/商品数分别统计,不当独立消费者。旧query三维模板保留兼容,不作为通用查询方式。

+ 4 - 0
skills/ksf-workshop-runtime/references/workshop-three-source-opportunities.md

@@ -4,6 +4,8 @@ D2-04、系统阶段S3。将 [产品机会初表](workshop-opportunity-discovery
 
 ## 1. 建立三维与来源对应
 
+当前 v3 的“三源证据”明确为:**商品事实、用户原声、工艺条件**。以下 S×U×C 是定位坐标,不能当作三类证据已齐。逐候选列商品链接/事实、用户原话/ID/态度、研发侧实际提供的工艺条件及来源;研发尚未提供时标“待工艺确认”,AI 不代写可行或冒称研发已签认。三源齐全为候选、两源为候选(弱)、一源为线索;评级说明证据成熟度,不代替下一节排序或企业立项。
+
 回读真实成果编号/版本、稳定线索/需求键、验收集合、矩阵/指标、验证配置及适用时间/范围。按本题问题组织以下对应,缺项保留待补,不用“资料来自三个平台”代交叉推理。
 
 | 维度 | 要回答的问题与证据 |
@@ -44,6 +46,8 @@ D2-04、系统阶段S3。将 [产品机会初表](workshop-opportunity-discovery
 
 每卡完整报告至少包含S/U/C定义与已观察/设想关系、用户任务/痛点、产品方向和差异、三源及共用索引、支持/反对、五力、关键约束和下一步验证。用现有table及para/longpara,原句按真实业务sourceIds/report.evidence逐字绑定;研究ID不冒充KfSource。
 
+对员工展示时按 v3 六个业务字段组织:可证伪的一句话结论、三源证据、反例、还缺什么及影响、下一步验证、研发侧工艺注释。通常收敛为 2–3 张有依据的卡,材料不足不凑数。此处六字段是报告内容,不替换下面 API 的六个短字段,也不把长证据塞进短字段。
+
 对每个实际候选调用workshop-save:stageCode=S3、artifactType=opportunity_card,建议taskKey=`<topicKey>:D2-04:card:<candidateKey>`;附opportunity只用既有六字段key、title、demandSummary、targetAudience、usageScenario、fusionDefinition,各为非空且不超200字符的简述,详细证据放报告。未知人群/条件可在简述中如实标待核,不为必填字段虚构画像。
 
 opportunity.key为该候选持久系列键,与本地线索键/需求键建立对应;不是显示序号。每卡API version沿自身系列递增,报告taskKey和opportunity.key各自稳定。没有真实项目省略projectId,不为建候选卡调用project-create;已有项目补核遵守当前阶段,不倒退或新造项目。

+ 52 - 0
skills/ksf-workshop-runtime/references/workshop-v3-outputs.md

@@ -0,0 +1,52 @@
+# v3:13 份环节产出与交接
+
+《学员手册 v3》就是当前操作手册;课程业务顺序、复制提示词及应交产出沿该手册,配套《总览图》用于讲解和样卡参考(2026-11-12 核对):
+
+- 总览:https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/overview/index.html
+- 手册:https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/manual-v3/index.html
+
+本文件是流程、方法和验收要求;员工复制提示词留在手册。原七类内容导航保留为跨报告索引,不能代替以下 13 份环节交付;看板 11 个分类也不是交付份数。与旧细则的默认分档、三源含义或最终导航不同时,当前课程沿本文件执行;原授权、真实身份、引用、项目阶段、正式确认和保存接口继续适用。
+
+## 怎样数 13 份
+
+13 是 D1-01~D1-04、D1-N、D2-01~D2-08 共 13 个环节的交付单元。一个单元可以包含卡、表、正文、HTML 和多个真实报告编号:例如 D2-02 的四张表合计一份环节产出,D2-04 的多张机会卡与候选清单合计一份。不是强制恰好 13 个 HTML/数据库行,也不把附件、来源记录、历史版本或同报告的多个章节重复计数。三份大课不另造报告。
+
+以下表只列各节核心内容。保存实质正文、统计、原件索引、同版 HTML、回读及看板核对仍按 [交付合同](workshop-report-parity.md) 与 [逐环节保存](workshop-delivery.md);不能仅写名称或把内容藏在聊天里。每位员工的成果保留各自归属,同组研究可以共享已授权资料。
+
+| 环节 / 阶段 | 环节产出物 | 最少包含什么 | 下一环怎么用 |
+|---|---|---|---|
+| D1-01 / S1 | 品类全景图谱 | 供给树(形态/工艺/价格带/地域风味)、需求树(人群/场景/需求)、供需缺口三栏;计数、来源及覆盖 | D1-02 换口径回查;D1-03 找同格竞品;D2-03 查空白 |
+| D1-02 / S1 | 本题验证配置卡 | 资料资格、统计/引文口径、AI 与人工分工、分歧处理;回查图谱中易被反驳的主张并记录实际修订 | D1-03 起每节沿同版规则,V1→V3 都检查 |
+| D1-03 / S1 | 竞品图谱 + 待验证痛点假设 | 同格 SKU/规格/价格条件/卖点组合;宣称/回应/推断分开;正反原话;H1–H3 可证伪假设 | D1-04 定任务;D1-N 验证;D2-04 留反例 |
+| D1-04 / S1 | 增强 AI 自驱任务卡 | 假设键、原假设、现有支持、支持路径、反证路径、可判定停止条件、数据来源与权限;最多 3 条主线,其余备查 | D1-N 按卡执行,D2-01 按卡验收 |
+| D1-N / S2 | 调研战报 + 缺口清单 | 逐假设回应/支持/反证;原件覆盖;VOC 预聚类与提及率口径;没查到/没权限/确实不存在分列,记录实际停止条件 | D2-01 先验收,合格资料给 D2-02 |
+| D2-01 / S2 | 战报验收记录 | 假设回应率、原件覆盖、分母口径三项检查;词典词回读及推断边界;可用资料集合和不合格项 | 仅已通过的材料进入 D2-02;未通过项继续标缺口 |
+| D2-02 / S2 | 聚类表 + 痛点库 + KANO 表 + 人群×场景矩阵 | 人群→场景→JTBD→痛点四层编码;逐句 ID、正/负/读不出;频次/分母;KANO 标频次先验 | D2-03 需求矩阵;D2-04 用户原声;D2-07 用户语言 |
+| D2-03 / S3 | 产品机会及指标初表 | 空白格/类别/供给证据/需求证据/待验证指标;结构、变化、未覆盖分开;未覆盖先查同格竞品 | D2-04 选待认证格;D2-05 排序指标;D2-06 成本指标 |
+| D2-04 / S3 | 候选机会清单 V1.0 | 通常 2–3 张六字段机会卡:可证伪结论、三源证据、反例、未知与影响、下一步验证、研发侧工艺注释;不足不凑数 | D2-05 排序,之后沿同一候选键更新 V2/V3 |
+| D2-05 / S4 | 优先级机会清单 + 未知项单列 | 证据强度/可做性/商业价值各 1–3 分、每分依据及来源;任一维 1 分不进前三;未知单列 | D2-06 主攻机会及全池去向;D2-08 说明为什么选 |
+| D2-06 / S4 | 回推表 + 候选机会清单 V2.0 | B0/O1 条件及差异;一次费用/资本投入/营运资金分开;成本区间/目标价格带/两路对比/工艺与合规条件 | D2-07 卖点匹配价格带;D2-08 风险与资源 |
+| D2-07 / S5 | 价值主张卡 + 卖点清单 | 一句主张、三条收益及证据;价格带×人群×场景的主推/备选表达;删除版本与不能说的话 | D2-08 提案首句、展演复述 |
+| D2-08 / S5 | 概念提案 + 候选清单 V3.0 + 成果导航 | 一句话/一页/全案三层;实际质询、矛盾与未答问题;V3 修改理由;逐项 13 份真实位置、用途和缺项 | 结营展演;第一周先补一个实际未答问题 |
+
+## 与旧实现相比必须校准的判断
+
+1. **三源是商品事实、用户原声、工艺条件。** 赛道×用户×场景仍是定位坐标,不是三个证据来源。工艺注释由研发侧真实提供,AI 可列待确认参数/条件和公开依据,不能代签可行。三源齐全为候选、两源为候选(弱)、一源为线索;同帖多引不增独立来源。
+2. **排序沿 v3 的三个维度和 1–3 分规则。** 任一维为 1 分不进前三,未知不填 1 分或 0 分,商业价值标需本组复核;不继续用默认 S/A/B 替代本课评分。企业另有明确量表时并列说明其适用范围,不静默换算。
+3. **方法与验收成果是正式的环节交付。** 配置卡、任务卡、战报验收记录、机会指标初表有各自位置,不再只归入补充材料后被最终交付清单漏掉。它们仍可沿现有“方法与过程材料”分类存储;不必各造一个报告分类。
+4. **KANO 是有来源的频次先验。** 评论文本无法代成对问卷;不将打标频次直接排名,不删态度读不出的原话。不存在合格数据时保留可读的不足记录,不虚填四张表的结果。
+5. **样卡数字只属于样卡快照。** 手册中的 400/125/71 条、20 篇/品牌、成本比例、供应商比例及标准参数须核其原件与本题适用性;不能作为当前库计数、企业标准、法定通用门槛或采样上限照抄。实际当前统计据本次合格集合计算,标准以有效原文为准。
+6. **V1→V2→V3 是同一候选池的成熟过程。** V2 增商业/工艺条件,V3 增实际质询修订;不是三套无关机会,也不以业务版名代 API version。没有质询则标待质询,不伪造 V3 已经评审。
+7. **每节以三行交接。** 完成业务回答并交实际链接后,末尾用【本轮产出】【还缺什么】【下一步】交接具体成果、影响下一环的字段缺口及一个确实改变路线的问题。已有答案直接沿用;无须业务选择时写明可接下一环,不为套格式制造问题。逐轮任务仍等待员工真实回应,不自动跑后续小节。
+
+## 入库与看板怎样对应
+
+使用现有 `report.delivery.moduleId`(D1-01~D2-08)及稳定 `taskKey/reportSeriesKey`,不新增 API 顶层字段。11 类报告是读者分类,13 个环节是进度维度,S1–S5 是系统阶段;三者可同时筛查,不互相替代。现有七类 `delivery.outputs` 保留兼容,用于内容索引,不冒称覆盖全部课表交付。
+
+看板环节导航取 [共享目录](../scripts/course-deliverables.mjs),按员工、课题、资料模式、各系列最新版本列 13 项并链接所有对应报告。只认明确 moduleId 或 taskKey 中的环节标识,不按相似标题猜;标记冲突待定位。一个报告有正文,只能记“已有正文”,不能自动判所有表已齐、HTML/原件已上传、报告质量通过或员工已确认。草稿、仅原文、缺正文和未保存分别显示;样例不补足真实研究。
+
+每份内容验收再按上表逐项检查实际章节/表行/引文/来源及用途;阶段和环节结束仍保留具体缺项。归属、正文、同版 HTML、证据桥接、统计覆盖、公开看板和员工确认各自留真实结果。上一节未合格的数据不因有报告编号而取得下一节证据资格。
+
+课程评分用既有`table`保存,建议section.id=`course-priority`,列依次为“机会、证据强度、可做性、商业价值、依据一句话、排序”。机会列保留稳定候选键及名称;三维为1/2/3,未知用null或“待确认”,依据分别说明每维理由与来源,商业价值标需本组复核。未知项另表列缺什么、怎么补及本次能否补;一维1分或尚缺评分时不写进入前三。共享脚本`scripts/course-assessment.mjs`供HTML和看板一致展示,不求总分、不自动排名。旧0–100多人点评及S/A/B历史等级不换算成课程分数,也不据此覆盖课程排序。
+
+手册v3正文与复制提示词规定任一维1分不进前三;总览图样卡中可做性1分却排第3的展示与此冲突,执行以手册规则为准,不照抄该示例排名。其余示例只按真实来源和本题适用性使用,手册文本不自动证明当前库计数、企业条件或实际工艺已确认。

+ 1 - 1
skills/ksf-workshop-runtime/references/workshop-voc-clustering.md

@@ -51,7 +51,7 @@ KANO表和矩阵是报告可查看的中间产出,不新增业务表或课堂
 
 影响强弱须有原话或实际观察,例如任务被中断、需另配工具/食物或放弃使用;语气强烈、低星或高频本身不证明后果严重。明确的少数场景需求也可先研究;高频但已有合适解决方式可说明后置理由。重要性未知与证据成熟度分开,缺证不打0,必要时只排补证先后或并列。KANO实测/建议是参考,不直接决定研究顺序。
 
-逐需求留“研究先后建议、任务影响/替代与证据、决定性未知、什么结果会改变判断”,下一节据此比较供给和差异。这里是需求层的研究安排,D2-05才对完整机会候选按S/A/B初排,不混成同一张评分表。已有业务取舍一并记录,Agent建议不写成企业已批准。
+逐需求留“研究先后建议、任务影响/替代与证据、决定性未知、什么结果会改变判断”,下一节据此比较供给和差异。这里是需求层的研究安排,D2-05才对完整机会候选按证据强度、可做性、商业价值各1–3分排序,未知单列,不混成同一张评分表。已有业务取舍一并记录,Agent建议不写成企业已批准。
 
 ## 5. 成报、保存与本节验收
 

+ 35 - 0
skills/ksf-workshop-runtime/scripts/course-assessment.mjs

@@ -0,0 +1,35 @@
+/** v3 course scores live in an existing report table, separately from 0–100 peer reviews. */
+export const COURSE_ASSESSMENT_ID = 'course-priority';
+export const COURSE_ASSESSMENT_COLUMNS = Object.freeze(['机会', '证据强度', '可做性', '商业价值', '依据一句话', '排序']);
+const invalid = () => { throw Object.assign(Error('COURSE_ASSESSMENT_INVALID'), { code: 'COURSE_ASSESSMENT_INVALID' }); };
+const key = value => typeof value === 'string' ? value.replace(/\s/gu, '') : '';
+const text = value => typeof value === 'string' && Boolean(value.trim());
+const score = value => {
+  if (value === null || value === '' || ['待确认', '未知', '未评分', '—'].includes(value)) return null;
+  if (typeof value === 'string' && /^[123]$/.test(value.trim())) value = Number(value.trim());
+  if (!Number.isInteger(value) || value < 1 || value > 3) invalid();
+  return value;
+};
+
+export function courseAssessmentRows(section) {
+  if (section?.id !== COURSE_ASSESSMENT_ID) return null;
+  if (section.kind !== 'table' || !Array.isArray(section.data?.cols)
+    || section.data.cols.length !== COURSE_ASSESSMENT_COLUMNS.length
+    || section.data.cols.some((column, i) => key(column) !== key(COURSE_ASSESSMENT_COLUMNS[i]))
+    || !Array.isArray(section.data.rows) || !section.data.rows.length) invalid();
+  return section.data.rows.map(row => {
+    if (!Array.isArray(row) || row.length !== 6) invalid();
+    const [candidate, evidence, feasibility, business, basis, order] = row;
+    if (!text(candidate) || !text(basis) || typeof order !== 'string') invalid();
+    const scores = [evidence, feasibility, business].map(score);
+    const unknown = scores.some(value => value === null);
+    const low = scores.includes(1);
+    if ((unknown || low) && /^(?:第\s*)?[123一二三]\s*(?:名|位)?$/.test(order.trim())) invalid();
+    return { candidate, scores, basis, order, unknown, low,
+      status: low ? '不进入前三' : unknown ? '未知项待补' : '可参与排序' };
+  });
+}
+
+export function validateCourseAssessment(report) {
+  for (const chapter of report?.chapters || []) for (const section of chapter.sections || []) courseAssessmentRows(section);
+}

+ 44 - 0
skills/ksf-workshop-runtime/scripts/course-deliverables.mjs

@@ -0,0 +1,44 @@
+/** v3 course outputs. Course modules, report categories and stored files are separate counts. */
+import { validateReportDelivery } from './report-contract.mjs';
+export const COURSE_DELIVERABLES = Object.freeze([
+  ['D1-01', '品类全景图谱', 'S1', '三栏图谱', ['供给树', '需求树', '供需缺口与来源覆盖']],
+  ['D1-02', '本题验证配置卡', 'S1', '配置卡与回查记录', ['资料资格', '统计与引文口径', '模型/人工分工与分歧处理', '图谱回查记录']],
+  ['D1-03', '竞品图谱 + 待验证痛点假设', 'S1', '矩阵与假设清单', ['同格竞品与卖点组合', '宣称/回应/推断', '正反原话与可证伪假设']],
+  ['D1-04', '增强 AI 自驱任务卡', 'S1', '任务卡', ['稳定假设键', '支持路径与反证路径', '可判定停止条件', '数据来源与权限']],
+  ['D1-N', '调研战报 + 缺口清单', 'S2', '战报、缺口表与预聚类', ['逐假设回应', '没查到/没权限/确实不存在', '原件覆盖与 VOC 预聚类']],
+  ['D2-01', '战报验收记录', 'S2', '验收记录与可用资料索引', ['假设回应率', '原件覆盖', '分母口径', '可用资料集合']],
+  ['D2-02', '聚类表 + 痛点库 + KANO 表 + 人群 × 场景矩阵', 'S2', '四张表', ['四层聚类', '痛点库', 'KANO 频次先验', '人群 × 场景矩阵']],
+  ['D2-03', '产品机会及指标初表', 'S3', '机会与指标表', ['结构/变化/未覆盖分列', '同格竞品核查', '供给与需求证据', '待验证指标']],
+  ['D2-04', '候选机会清单 V1.0', 'S3', '清单与六字段机会卡', ['商品事实/用户原声/工艺条件', '结论与反例', '未知与下一步验证', '研发侧工艺注释']],
+  ['D2-05', '优先级机会清单 + 未知项单列', 'S4', '排序表与未知项表', ['证据强度/可做性/商业价值各 1–3 分', '逐分依据', '任一维 1 分不进前三', '未知不代填低分']],
+  ['D2-06', '回推表 + 候选机会清单 V2.0', 'S4', '回推表与更新机会卡', ['B0/O1 可比条件', '一次费用/资本投入/营运资金', '成本与目标价格带', '工艺与合规条件']],
+  ['D2-07', '价值主张卡 + 卖点清单', 'S5', '价值卡与卖点表', ['一句主张与三条收益', '逐句证据', '主推/备选/不能说的话', '证据与合规边界']],
+  ['D2-08', '概念提案 + 候选清单 V3.0 + 成果导航', 'S5', '三层提案与成果导航', ['一句话/一页/全案', '实际质询与未答问题', 'V3.0 变化理由', '13 份产出物位置与用途']],
+].map(([moduleId, name, stageCode, form, checks]) => Object.freeze({ moduleId, name, stageCode, form, checks: Object.freeze(checks) })));
+
+/** Match only explicit metadata/task identifiers. Never infer a module from a title. */
+export function courseModuleOf(artifact) {
+  const marked = artifact?.report?.delivery?.moduleId;
+  const known = value => COURSE_DELIVERABLES.some(output => output.moduleId === value);
+  const task = String(artifact?.reportSeriesKey || '').match(/(?:^|[:/])(D1-(?:0[1-4]|N)|D2-0[1-8])(?=[:/]|$)/)?.[1];
+  if (marked !== undefined) {
+    try { validateReportDelivery(artifact.report, artifact.type || artifact.artifactType); }
+    catch { return ''; }
+    if (!known(marked) || task && task !== marked) return '';
+    return marked;
+  }
+  return known(task) ? task : '';
+}
+
+/** A saved body is a location check; it does not certify research quality or employee approval. */
+export function courseOutputLedger(rows, hasContent) {
+  return COURSE_DELIVERABLES.map(output => {
+    const reports = rows.filter(row => courseModuleOf(row.artifact) === output.moduleId);
+    const body = reports.filter(row => Array.isArray(row.artifact.report?.chapters) && row.artifact.report.chapters.some(hasContent));
+    const submitted = body.filter(row => row.artifact.report?.delivery?.contentStatus !== 'draft');
+    const state = submitted.length ? 'has-body' : body.length ? 'draft'
+      : reports.some(row => String(row.artifact.rawText || '').trim()) ? 'text-only'
+      : reports.length ? 'missing-body' : 'missing';
+    return { ...output, state, reports };
+  });
+}

+ 30 - 0
skills/ksf-workshop-runtime/scripts/ksf-account.mjs

@@ -0,0 +1,30 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import crypto from 'node:crypto';
+import { fileURLToPath } from 'node:url';
+import { readAgentProfileByKey, readParticipantProfile } from './ksf-identity.mjs';
+import { createWorkshopCaller } from './ksf-workshop.mjs';
+const self=fileURLToPath(import.meta.url),sha=x=>crypto.createHash('sha256').update(x).digest('hex');
+const fail=code=>{throw Object.assign(Error(code),{code});};
+export async function runAccountBinding(command,task,{requestId,agentProfile,participantProfile,call}={}){
+ if(!['account-prepare','account-status'].includes(command)||!task||typeof task!=='object'||Array.isArray(task)||Object.keys(task).some(k=>!['participant','username','displayName'].includes(k)))fail('INVALID_INPUT');
+ if(!requestId||agentProfile?.role!=='workshop'||!participantProfile||task.participant?.profileKey!==participantProfile.key||Object.keys(task.participant).some(k=>k!=='profileKey'))fail('PARTICIPANT_PROFILE_REQUIRED');
+ if(participantProfile.account?.platform!=='fmode')fail('ACCOUNT_PLATFORM_MISMATCH');
+ const preparing=command==='account-prepare';
+ if(!preparing&&(Object.hasOwn(task,'username')||Object.hasOwn(task,'displayName')))fail('INVALID_INPUT');
+ if(preparing&&(task.username!==participantProfile.account.accountName||typeof task.displayName!=='string'||!task.displayName.trim()))fail('ACCOUNT_BINDING_CONFLICT');
+ return call('ksfWorkshopAccount',{requestId,action:preparing?'prepare':'status',participantProfileKey:participantProfile.key,...(preparing?{username:task.username,displayName:task.displayName}:{})});
+}
+if(process.argv[1]&&path.resolve(process.argv[1])===self){
+ const [command,...argv]=process.argv.slice(2),flags={};
+ const base={skill:'ksf-workshop-runtime',command,entry:self,entrySha256:sha(fs.readFileSync(self)),invocationId:crypto.randomUUID(),at:new Date().toISOString()};
+ try{
+  for(let i=0;i<argv.length;i+=2){if(!['--input','--agent-profile','--request-id'].includes(argv[i])||!argv[i+1]||flags[argv[i]])fail('USAGE');flags[argv[i]]=argv[i+1];}
+  if(!path.isAbsolute(flags['--input']||''))fail('INPUT_PATH_MUST_BE_ABSOLUTE');
+  const task=JSON.parse(fs.readFileSync(flags['--input'],'utf8'));
+  const result=await runAccountBinding(command,task,{requestId:flags['--request-id'],agentProfile:readAgentProfileByKey(flags['--agent-profile']),participantProfile:readParticipantProfile(task.participant?.profileKey),call:createWorkshopCaller({token:process.env.KSF_SERVICE_TOKEN})});
+  const output=JSON.stringify({...base,requestId:flags['--request-id'],ok:true,readOnly:command==='account-status',result});
+  if(process.env.KSF_SERVICE_TOKEN&&output.includes(process.env.KSF_SERVICE_TOKEN))fail('OUTPUT_CONTAINS_SECRET');
+  console.log(output);
+ }catch(e){console.error(JSON.stringify({...base,requestId:flags['--request-id'],ok:false,error:{code:/^[A-Z][A-Z0-9_]+$/.test(e.code||'')?e.code:'ACCOUNT_BINDING_FAILED',message:'账号绑定未完成;保留原档案,未输出凭据。'}}));process.exitCode=1;}
+}

+ 1 - 1
skills/ksf-workshop-runtime/scripts/ksf-identity.mjs

@@ -68,7 +68,7 @@ export function adoptLegacyAgentProfile(file,{profileDir=PROFILE_DIR}={}){const
 export function bindOwnAgent(task,profile){if(!profile)fail('AGENT_PROFILE_REQUIRED');if(profile.role!=='workshop')fail('AGENT_ROLE_MISMATCH');const agent={key:profile.key,name:profile.name,identityBasis:profile.identityBasis,account:normalizeAgentAccount(profile.account),role:profile.role,runtimePlatform:profile.runtimePlatform??null,channel:profile.channel??null,collectedAt:profile.collectedAt??profile.registeredAt};if(task.agent!==undefined){exact(task.agent,['key','name','identityBasis','account','role','runtimePlatform','channel','collectedAt']);for(const key of ['key','name','identityBasis','role','runtimePlatform','channel','collectedAt'])if(task.agent[key]!==undefined&&task.agent[key]!==agent[key])fail('AGENT_IDENTITY_MISMATCH');if(task.agent.account!==undefined&&canonical(normalizeAgentAccount(task.agent.account))!==canonical(agent.account))fail('AGENT_IDENTITY_MISMATCH');}return{...task,agent};}
 export function bindRegisteredParticipant(input,profile){if(!profile)fail('PARTICIPANT_PROFILE_REQUIRED');if(!object(input)||Object.keys(input).some(k=>!['profileKey','name'].includes(k)))fail('INVALID_IDENTITY_FIELDS');if(input.profileKey!==profile.key||input.name&&input.name!==profile.name)fail('PARTICIPANT_PROFILE_CONFLICT');return{key:profile.key,name:profile.name,identityBasis:profile.identityBasis,...(profile.userId?{userId:profile.userId}:{}),account:normalizeParticipantAccount(profile.account)};}
 export function assertOwnSession(row,profile){if(!profile)fail('AGENT_PROFILE_REQUIRED');if(profile.role!=='workshop')fail('AGENT_ROLE_MISMATCH');const a=row?.meta?.attribution;if(a?.agentKey!==profile.key||a?.agentName!==profile.name||a?.agentRuntimePlatform!==(profile.runtimePlatform??null)||a?.agentChannel!==(profile.channel??null))fail('AGENT_SESSION_MISMATCH');}
-export function redactIdentity(value){if(Array.isArray(value))return value.map(redactIdentity);if(!object(value))return value;const hidden=new Set(['participantAccount','agentAccount','conversationKey','ownerId','userRef','accountId','tenantId','runtimeAgentId','wecomAppAgentId','employeeNumber','scopeId','botId','senderId']);return Object.fromEntries(Object.entries(value).filter(([k,v])=>!hidden.has(k)&&v!==undefined).map(([k,v])=>[k,k==='producer'&&object(v)?redactIdentity({...v,...(v.agent?{agent:{key:v.agent.key,name:v.agent.name,identityBasis:v.agent.identityBasis}}:{})}):redactIdentity(v)]));}
+export function redactIdentity(value){if(Array.isArray(value))return value.map(redactIdentity);if(!object(value))return value;const hidden=new Set(['accountBinding','accountProfileKey','platformUserId','participantAccount','agentAccount','conversationKey','ownerId','userRef','accountId','tenantId','runtimeAgentId','wecomAppAgentId','employeeNumber','scopeId','botId','senderId']);return Object.fromEntries(Object.entries(value).filter(([k,v])=>!hidden.has(k)&&v!==undefined).map(([k,v])=>[k,k==='producer'&&object(v)?redactIdentity({...v,...(v.agent?{agent:{key:v.agent.key,name:v.agent.name,identityBasis:v.agent.identityBasis}}:{})}):redactIdentity(v)]));}
 export function executeIdentity(argv,options={}){
  const[command,...args]=argv;let result;
  if(command==='status'&&args.length===0)result={...listIdentityProfiles(options)};

+ 8 - 4
skills/ksf-workshop-runtime/scripts/ksf-secure.mjs

@@ -10,8 +10,10 @@ const sha256 = bytes => crypto.createHash('sha256').update(bytes).digest('hex');
 const ENTRY_HASH = '7ef128f7d022bfbc15c0ec813bfd87995c6297c6efe407a563c840f014aba477';
 const LOCK_HASH = '2605cbe8fd7be43b5969a4991f978dc0768dee5b4d65d18f7af15f75e9004a79';
 const WORKSHOP_ENTRY_HASH = '7a04eb22d3429cdced23513717f36594f639539738994d45712a8bea738100a1';
-const IDENTITY_MODULE_HASH = '9224ef89a96425890d54961fda1f4fcae3403aa7c753fe1d70ac62082f2ff77e';
-const WORKSHOP_COMMANDS = ['workshop-start','workshop-save','project-create','project-progress','concept-save','project-status','workshop-import','workshop-dedup','workshop-search','workshop-read','workshop-contract','workshop-schema','employee-read','employee-name'];
+const ACCOUNT_ENTRY_HASH = '9bfda45c53192d70fefb31b378851aeb19e075b6f5adcd8217ba4838cc133f7d';
+const ACCOUNT_COMMANDS = ['account-prepare','account-status'];
+const IDENTITY_MODULE_HASH = 'ab6838afd140e4b84ef39a255fcbdd80ece9b0b7c245f65cd8ba81d892036513';
+const WORKSHOP_COMMANDS = [...ACCOUNT_COMMANDS,'workshop-start','workshop-save','project-create','project-progress','concept-save','project-status','workshop-import','workshop-dedup','workshop-search','workshop-read','workshop-contract','workshop-schema','employee-read','employee-name'];
 const fail = code => { throw Object.assign(new Error(code), { code }); };
 const requireThat = (value, code) => { if (!value) fail(code); };
 
@@ -49,8 +51,10 @@ export async function executeSecure(argv, dependencies = {}) {
   const readBytes = dependencies.readBytes || (file => fs.readFileSync(file));
   const spawn = dependencies.spawn || spawnSync;
   const workshop = WORKSHOP_COMMANDS.includes(args.command);
-  const entry = path.join(skillDir, 'scripts', workshop ? 'ksf-workshop.mjs' : 'ksf.mjs');
-  const expectedEntryHash = workshop ? WORKSHOP_ENTRY_HASH : ENTRY_HASH;
+  const account = ACCOUNT_COMMANDS.includes(args.command);
+  const entry = path.join(skillDir, 'scripts', account ? 'ksf-account.mjs' : workshop ? 'ksf-workshop.mjs' : 'ksf.mjs');
+  const expectedEntryHash = account ? ACCOUNT_ENTRY_HASH : workshop ? WORKSHOP_ENTRY_HASH : ENTRY_HASH;
+  if(account)requireThat(sha256(readBytes(path.join(skillDir,'scripts/ksf-workshop.mjs'))) === WORKSHOP_ENTRY_HASH, 'ENTRY_HASH_MISMATCH');
   requireThat(sha256(readBytes(entry)) === expectedEntryHash, 'ENTRY_HASH_MISMATCH');
   if(workshop)requireThat(sha256(readBytes(path.join(skillDir,'scripts','ksf-identity.mjs'))) === IDENTITY_MODULE_HASH, 'IDENTITY_MODULE_HASH_MISMATCH');
   requireThat(sha256(readBytes(path.join(skillDir, 'runtime-lock.json'))) === LOCK_HASH, 'RUNTIME_LOCK_HASH_MISMATCH');

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 17 - 1
skills/ksf-workshop-runtime/scripts/render-report-html.mjs


+ 32 - 0
skills/ksf-workshop-runtime/scripts/report-statistics.mjs

@@ -0,0 +1,32 @@
+/** A semantic table within the existing report schema; no new section.kind or API fields. */
+export const STATISTICS_SECTION_ID = 'statistics-summary';
+export const STATISTICS_COLUMNS = Object.freeze(['维度/主题', '提及数 n', '有效样本 N', '统计口径与范围', '数据解释与限制', '产品含义', '证据']);
+const invalid = () => { throw Object.assign(new Error('REPORT_STATISTICS_INVALID'), { code: 'REPORT_STATISTICS_INVALID' }); };
+const hasText = value => typeof value === 'string' && Boolean(value.trim());
+const count = value => value === null || Number.isSafeInteger(value) && value >= 0;
+// The board's CJK typography pass may replace ASCII spaces with thin spaces.
+const columnKey = value => typeof value === 'string' ? value.replace(/\s/gu, '') : null;
+
+export function statisticsRows(section) {
+  if (section?.id !== STATISTICS_SECTION_ID) return null;
+  if (section.kind !== 'table' || !Array.isArray(section.data?.cols) || section.data.cols.length !== STATISTICS_COLUMNS.length
+    || section.data.cols.some((column, index) => columnKey(column) !== columnKey(STATISTICS_COLUMNS[index]))
+    || !Array.isArray(section.data?.rows) || !section.data.rows.length) invalid();
+  return section.data.rows.map(row => {
+    if (!Array.isArray(row) || row.length !== 7) invalid();
+    const [label, numerator, denominator, scope, interpretation, implication, evidenceId] = row;
+    if (![label, scope, interpretation, implication].every(hasText) || typeof evidenceId !== 'string'
+      || !count(numerator) || !count(denominator)
+      || numerator !== null && denominator !== null && numerator > denominator) invalid();
+    const ratio = numerator !== null && denominator !== null && denominator > 0 ? numerator / denominator : null;
+    return { label, numerator, denominator, scope, interpretation, implication, evidenceId,
+      ratio, percent: ratio === null ? null : (ratio * 100).toFixed(1) + '%' };
+  });
+}
+
+export function validateReportStatistics(report) {
+  for (const chapter of report?.chapters || []) for (const section of chapter.sections || []) {
+    const rows = statisticsRows(section);
+    if (rows?.some(row => row.evidenceId && !Object.hasOwn(report.evidence || {}, row.evidenceId))) invalid();
+  }
+}

+ 4 - 0
skills/ksf-workshop-runtime/scripts/save-report.mjs

@@ -6,6 +6,8 @@ import { spawnSync } from 'node:child_process';
 import { fileURLToPath } from 'node:url';
 import { DELIVERY_SCHEMA, validateReportDelivery, REPORT_ATTACHMENT_TYPES, REPORT_ATTACHMENT_LIMITS } from './report-contract.mjs';
 import { renderReportHtml } from './render-report-html.mjs';
+import { validateReportStatistics } from './report-statistics.mjs';
+import { validateCourseAssessment } from './course-assessment.mjs';
 const reportSaveSelf = fileURLToPath(import.meta.url);
 const reportSaveHash = x => crypto.createHash('sha256').update(x).digest('hex');
 const reportSaveCanonical = x => x && typeof x === 'object' ? Array.isArray(x) ? '[' + x.map(reportSaveCanonical).join(',') + ']'
@@ -54,6 +56,8 @@ export function prepareHtmlReport(task, { directory, localFiles = [], dataMode }
 export async function saveAndVerifyReport(task, { requestId, invoke, publicRead, readAttachment }) {
   if (!requestId || task.requestId && task.requestId !== requestId) reportSaveFail('BAD_REQUEST_ID');
   if (validateReportDelivery(task.report, task.artifactType)?.schema !== DELIVERY_SCHEMA) reportSaveFail('REPORT_DELIVERY_REQUIRED');
+  validateReportStatistics(task.report);
+  validateCourseAssessment(task.report);
   const contract = await invoke('workshop-contract', {}, requestId + ':contract');
   if (contract.workshop?.delivery?.schema !== DELIVERY_SCHEMA
     || task.report.attachments?.length && !contract.workshop.delivery.attachments?.enabled) reportSaveFail('REPORT_DELIVERY_CAPABILITY_UNAVAILABLE');

+ 29 - 0
test/workshop-account.test.js

@@ -0,0 +1,29 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import path from 'node:path';
+import {runAccountBinding} from '../skills/ksf-workshop-runtime/scripts/ksf-account.mjs';
+import {parseArgs} from '../skills/ksf-workshop-runtime/scripts/ksf-secure.mjs';
+import {redactIdentity} from '../skills/ksf-workshop-runtime/scripts/ksf-identity.mjs';
+const profile={key:'participant-registration:1ab680ff-4ad4-4377-9333-3b2f23e26bb7',account:{platform:'fmode',accountName:'guopeng',accountId:null}};
+const task={participant:{profileKey:profile.key},username:'guopeng',displayName:'果鹏'};
+const opts={requestId:'first-link',agentProfile:{role:'workshop'},participantProfile:profile};
+test('首次绑定命令只传当前档案和自报称呼账号,不收密码或冒充平台确认',async()=>{
+ let called=0;const call=async(name,p)=>{called++;assert.equal(name,'ksfWorkshopAccount');assert.equal(p.action,'prepare');assert.equal(p.participantProfileKey,profile.key);assert.ok(!('password'in p));return{status:'awaiting_account_confirmation'};};
+ const r=await runAccountBinding('account-prepare',task,{...opts,call});assert.equal(r.status,'awaiting_account_confirmation');assert.equal(called,1);
+ await assert.rejects(()=>runAccountBinding('account-confirm',task,{...opts,call}),{code:'INVALID_INPUT'});assert.equal(called,1);
+});
+test('档案不匹配、冒用其他账号或通道字段写入前拒绝',async()=>{
+ const call=()=>{assert.fail('must stop before network');};
+ for(const t of [{...task,username:'liuna'},{...task,participant:{profileKey:'another'}},{...task,password:'forbidden'}])await assert.rejects(()=>runAccountBinding('account-prepare',t,{...opts,call}));
+ const status=await runAccountBinding('account-status',{participant:task.participant},{...opts,call:async()=>({status:'bound',memberKey:'verified-key'})});assert.equal(status.memberKey,'verified-key');
+});
+test('新增受控命令沿用加密凭据入口,要求Agent及请求编号',()=>{
+ const flags=['--input',path.resolve('work/task.json'),'--request-id','link-test','--agent-profile','agent-account:'+'a'.repeat(64)];
+ assert.equal(parseArgs(['account-prepare',...flags]).command,'account-prepare');
+ assert.equal(parseArgs(['account-status',...flags]).command,'account-status');
+ assert.throws(()=>parseArgs(['account-prepare','--input',path.resolve('work/task.json'),'--request-id','link-test']),{code:'AGENT_PROFILE_REQUIRED'});
+});
+test('报告回读移除新增私有绑定快照和平台编号,只保留公开memberKey',()=>{
+ const result=redactIdentity({memberKey:'public-member',meta:{attribution:{participantKey:'old-participant',accountBinding:{platformUserId:'private-user'},accountProfileKey:'private-profile',platformUserId:'private-user'}}});
+ assert.deepEqual(result,{memberKey:'public-member',meta:{attribution:{participantKey:'old-participant'}}});
+});

+ 60 - 0
test/workshop-v3-assessment.test.js

@@ -0,0 +1,60 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'node:fs';
+import { COURSE_ASSESSMENT_COLUMNS, courseAssessmentRows } from '../skills/ksf-workshop-runtime/scripts/course-assessment.mjs';
+import { renderReportHtml } from '../skills/ksf-workshop-runtime/scripts/render-report-html.mjs';
+import { saveAndVerifyReport } from '../skills/ksf-workshop-runtime/scripts/save-report.mjs';
+import { DELIVERY_SCHEMA } from '../skills/ksf-workshop-runtime/scripts/report-contract.mjs';
+
+const section = rows => ({ id: 'course-priority', kind: 'table', data: { cols: [...COURSE_ASSESSMENT_COLUMNS], rows } });
+const valid = () => section([
+  ['测试候选A', 3, 2, 2, '证据为隔离样例;工艺条件仅测试;商业价值需本组复核', '第1'],
+  ['测试候选B', 2, 1, 2, '测试可做性1分,保持不进入前三', '不进入前三'],
+  ['测试候选C', 2, null, 2, '工艺资料缺失,列未知项;不是低分', '先补证'],
+]);
+const task = table => ({ artifactType: 'assessment_report', stageCode: 'S4', version: 1, title: '隔离样例:课程排序',
+  report: { delivery: { schema: DELIVERY_SCHEMA, moduleId: 'D2-05', kind: 'validation', contentStatus: 'ready', outputs: ['validation'] },
+    chapters: [{ id: 'opportunity-validation', title: '三维评分', sections: [table] }] } });
+
+test('课程三维分别为1–3,未知保持未知,资格不是自动前三或总分', () => {
+  const rows = courseAssessmentRows(valid());
+  assert.deepEqual(rows.map(row => row.status), ['可参与排序', '不进入前三', '未知项待补']);
+  assert.deepEqual(rows[2].scores, [2, null, 2]);
+  assert.equal(Object.hasOwn(rows[0], 'total'), false);
+  const displayTable = valid(); displayTable.data.cols[0] = '机\u2009会';
+  assert.equal(courseAssessmentRows(displayTable).length, 3);
+});
+
+test('一维1分或未知时不能按样卡进入前三,越界分值和缺依据不通过', () => {
+  for (const scores of [[2, 1, 2], [2, null, 2], [0, 2, 2], [4, 2, 2], [2.5, 2, 2]]) {
+    assert.throws(() => courseAssessmentRows(section([['测试', ...scores, '测试依据', '第3']])), { code: 'COURSE_ASSESSMENT_INVALID' });
+  }
+  assert.throws(() => courseAssessmentRows(section([['测试', 2, 2, 2, '', '第1']])), { code: 'COURSE_ASSESSMENT_INVALID' });
+  assert.equal(courseAssessmentRows({ kind: 'table', data: { rows: [['旧表']] } }), null);
+});
+
+test('独立HTML从同一评分表展示三维、未知及说明,不生成百分制总分', () => {
+  const html = renderReportHtml(task(valid()));
+  assert.match(html, /data-course-assessment/);assert.match(html, /待确认/);assert.match(html, /不进入前三/);
+  assert.match(html, /商业价值需本组复核/);assert.doesNotMatch(html, /总分<\/th>/);
+  const escaped = valid(); escaped.data.rows[0][0] = '<img src=x onerror=alert(1)>';
+  assert.doesNotMatch(renderReportHtml(task(escaped)), /<img src=x/);
+});
+
+test('课程非法排序在任何远程调用前停止保存', async () => {
+  let calls = 0;
+  const bad = task(section([['测试', 2, 1, 2, '可做性为1', '第3']]));
+  await assert.rejects(saveAndVerifyReport(bad, { requestId: 'invalid-course', invoke: () => { calls++; } }), { code: 'COURSE_ASSESSMENT_INVALID' });
+  assert.equal(calls, 0);
+});
+
+test('final操作手册采用v3全文,13段提示词原样,页内锚点不被远程base改写', () => {
+  const source = fs.readFileSync(new URL('../docs/workshop-v3-alignment-20261112/source-manual-v3.html', import.meta.url), 'utf8');
+  const final = fs.readFileSync(new URL('../docs/workshop-quality-r13-20261110/final-康师傅工作坊操作手册.html', import.meta.url), 'utf8');
+  assert.equal(final.replace(/<script id="ksf-v3-responsive-tables">[\s\S]*?<\/script>\n/, '')
+    .replaceAll('href="https://s3.fmode.cn/user/K0xKEZANOG/kangshifu/overview/index.html"', 'href="../overview/index.html"'), source);
+  assert.doesNotMatch(final, /<base\s/i);
+  const saved = JSON.parse(fs.readFileSync(new URL('../docs/workshop-quality-r13-20261110/manual/workshop-dialogue-prompts.json', import.meta.url)));
+  const original = JSON.parse(fs.readFileSync(new URL('../docs/workshop-v3-alignment-20261112/source-prompts-v3.json', import.meta.url)));
+  assert.deepEqual(saved.prompts, original.prompts);assert.equal(Object.keys(saved.prompts).length, 13);
+});

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است