mancode 0.5.3 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  assertActivationRollbackManifestTransition,
9
9
  assertClaimTransition,
10
10
  assertConfigPolicyConsistency,
11
+ assertExecutableImplementationScope,
11
12
  assertHandoffTransition,
12
13
  assertKnownKeys,
13
14
  assertOperationJournalTransition,
@@ -17,6 +18,7 @@ import {
17
18
  assertRecord,
18
19
  assertRepairUsesOriginalAuthorization,
19
20
  assertRequirementsLedgerTransition,
21
+ assertRequirementsScopeConsistent,
20
22
  assertReviewLedgerAgainstContext,
21
23
  assertReviewLedgerTransition,
22
24
  assertSafeSharedRelativePath,
@@ -49,6 +51,7 @@ import {
49
51
  formatTaskRef,
50
52
  gitRefWorkflowRepairJournalPath,
51
53
  handoffDirectory,
54
+ implementationScopeIsExecutable,
52
55
  isUlid,
53
56
  listGitRefWorkflowRepairJournalSummaries,
54
57
  listUnfinishedGitRefWorkflowRepairs,
@@ -111,13 +114,15 @@ import {
111
114
  workflowMetadataDigest,
112
115
  writeOperationReservation,
113
116
  writeProjectFacts
114
- } from "./chunk-VHZI2WKD.js";
117
+ } from "./chunk-YWHFHZ4A.js";
115
118
  import {
116
119
  DEFAULT_MANCODE_END_MARKER,
117
120
  DEFAULT_MANCODE_START_MARKER,
121
+ INTERFACE_EMOJI_ICON_GUIDANCE,
118
122
  V3_ADAPTER_FILE_TARGETS,
119
123
  V3_ADAPTER_PLATFORMS,
120
124
  V3_ADAPTER_VERSION,
125
+ VISUAL_DIRECTION_SELECTION_GUIDANCE,
121
126
  adapterManagedContentDigest,
122
127
  applyV3AdapterFilePlan,
123
128
  assertV3AdapterInstallable,
@@ -134,7 +139,7 @@ import {
134
139
  stageV3AdapterUpgradeFiles,
135
140
  v3AdapterTargetPath,
136
141
  v3AdapterVersionsFromStatuses
137
- } from "./chunk-2JOKDC3X.js";
142
+ } from "./chunk-AWOIP2LC.js";
138
143
 
139
144
  // src/cli.ts
140
145
  import { Option, program } from "commander";
@@ -1152,6 +1157,11 @@ var OPERATION_DEFINITIONS = {
1152
1157
  expectedRevisionPrefixes: ["claim:"],
1153
1158
  requiredLockPrefixes: ["claim:"]
1154
1159
  }),
1160
+ write(
1161
+ "mark-review-verification-stale",
1162
+ ["review:", "verification:", "task:"],
1163
+ ["task:"]
1164
+ ),
1155
1165
  write("update-metadata-scope", ["task:"], ["task:"]),
1156
1166
  write("activate-successor-claims", ["task:"], ["task:"], {
1157
1167
  expectedRevisionPrefixes: ["claim:"],
@@ -5692,11 +5702,13 @@ function parseRequirementsLedger2(raw, options = {}) {
5692
5702
  "requirements need at least one required acceptance criterion"
5693
5703
  );
5694
5704
  }
5705
+ const confirmedScope = normalizeStrings(value.confirmedScope);
5706
+ const excludedScope = normalizeStrings(value.excludedScope);
5695
5707
  return {
5696
5708
  version: 1,
5697
5709
  goal: value.goal.trim(),
5698
- confirmedScope: normalizeStrings(value.confirmedScope),
5699
- excludedScope: normalizeStrings(value.excludedScope),
5710
+ confirmedScope,
5711
+ excludedScope,
5700
5712
  technicalDecisions: normalizeStrings(value.technicalDecisions),
5701
5713
  defaults: normalizeStrings(value.defaults),
5702
5714
  blockingUnknowns: normalizeStrings(value.blockingUnknowns),
@@ -5704,6 +5716,12 @@ function parseRequirementsLedger2(raw, options = {}) {
5704
5716
  acceptanceCriteria
5705
5717
  };
5706
5718
  }
5719
+ function assertRequirementsScopeConsistent2(ledger) {
5720
+ const confirmed = new Set(ledger.confirmedScope);
5721
+ if (ledger.excludedScope.some((item) => confirmed.has(item))) {
5722
+ throw new Error("requirements scope cannot be both confirmed and excluded");
5723
+ }
5724
+ }
5707
5725
  function requirementsAreReady2(ledger) {
5708
5726
  return ledger.blockingUnknowns.length === 0;
5709
5727
  }
@@ -9620,7 +9638,7 @@ async function activateLegacyMigration(input) {
9620
9638
  if (session === null || session.status !== "active") {
9621
9639
  throw new Error("MANCODE_SESSION_NOT_FOUND");
9622
9640
  }
9623
- const store = new (await import("./store-EEWJJANB.js")).V3ContextStore(root);
9641
+ const store = new (await import("./store-DREAZNIX.js")).V3ContextStore(root);
9624
9642
  const project = await store.readProjectSnapshot();
9625
9643
  const stage = await readMigrationStage(root, input.stageId);
9626
9644
  if (stage.state !== "staged" || stage.revision !== input.expectedStageRevision) {
@@ -9883,7 +9901,7 @@ async function activateLegacyMigration(input) {
9883
9901
  for (const action of payload.actions.filter(
9884
9902
  (action2) => action2.kind === "v3_adapter_file"
9885
9903
  )) {
9886
- const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-DBVEX5H5.js");
9904
+ const { applyV3AdapterFilePlan: applyV3AdapterFilePlan2 } = await import("./v3-adapter-TCEFETAG.js");
9887
9905
  await applyV3AdapterFilePlan2(root, action);
9888
9906
  }
9889
9907
  journal = await completeActivationStep(
@@ -13739,7 +13757,7 @@ async function upgradeV3Adapters(input) {
13739
13757
  if (unfinished.length > 0) {
13740
13758
  throw new Error("MANCODE_ADAPTER_UPGRADE_OPERATION_PENDING");
13741
13759
  }
13742
- const actualVersions = await import("./v3-adapter-DBVEX5H5.js").then(
13760
+ const actualVersions = await import("./v3-adapter-TCEFETAG.js").then(
13743
13761
  ({ inspectV3AdapterVersions: inspectV3AdapterVersions2 }) => inspectV3AdapterVersions2(
13744
13762
  root,
13745
13763
  managedAdapterNames(project.manifest.managedAdapters)
@@ -14330,7 +14348,7 @@ import path26 from "path";
14330
14348
  var SCOUT_AGENT = {
14331
14349
  name: "scout",
14332
14350
  description: "Investigates the codebase for mancode /man workflows. Finds similar implementations, reusable modules, files to change, and risks. Does not write code.",
14333
- tools: ["Read", "Grep", "Glob", "Bash"],
14351
+ tools: ["Read", "Grep", "Glob"],
14334
14352
  body: `\u4F60\u662F mancode \u6559\u7EC3\u7EC4\u7684 Scout\uFF08\u7403\u63A2\uFF09\u3002
14335
14353
 
14336
14354
  \u4F60\u7684\u804C\u8D23\uFF1A\u8C03\u7814\u4EE3\u7801\u5E93\uFF0C\u4E3A Head Coach \u51C6\u5907\u6218\u672F\u4FE1\u606F\u3002
@@ -14341,6 +14359,8 @@ var SCOUT_AGENT = {
14341
14359
  - \u53EA\u5217\u5BF9\u5B9E\u65BD\u6709\u7528\u7684\u4FE1\u606F
14342
14360
  - \u627E\u5230\u98CE\u9669\u70B9\u8981\u6807\u6CE8\uFF08\u26A0\uFE0F\uFF09
14343
14361
  - \u4E0D\u786E\u5B9A\u7684\u8981\u660E\u8BF4\uFF0C\u4E0D\u731C
14362
+ - \u4E3B\u52A8\u6838\u9A8C\u7528\u6237\u524D\u63D0\uFF0C\u5E76\u4ECE\u7AEF\u5230\u7AEF\u7528\u6237\u76EE\u6807\u3001\u5E38\u89C1\u9886\u57DF\u5931\u8D25\u8DEF\u5F84\u548C\u8FB9\u754C\u6761\u4EF6\u5BFB\u627E\u4F1A\u6539\u53D8\u65B9\u6848\u7684\u76F2\u70B9\uFF1B\u6700\u591A\u4FDD\u7559 3 \u4E2A\u6700\u9AD8\u5F71\u54CD\u9879\u3002\u4ED3\u5E93\u4E8B\u5B9E\u5FC5\u987B\u6709\u8BC1\u636E\uFF1B\u65E0\u6CD5\u5728\u4ED3\u5E93\u6838\u9A8C\u7684\u884C\u4E1A\u5224\u65AD\u5FC5\u987B\u6807\u4E3A domain_hypothesis\uFF0C\u53EA\u80FD\u5F62\u6210\u805A\u7126\u95EE\u9898\uFF0C\u4E0D\u80FD\u5199\u6210\u4E8B\u5B9E
14363
+ - \u53D1\u73B0\u53EA\u63D0\u4F9B\u8BC1\u636E\u548C\u5EFA\u8BAE\u6743\uFF0C\u4E0D\u4EA7\u751F\u4FEE\u6539\u6743\uFF1B\u4E0D\u628A\u5EFA\u8BAE\u5199\u6210\u5DF2\u786E\u8BA4\u8303\u56F4\u6216\u6280\u672F\u51B3\u7B56
14344
14364
  - \u5B58\u5728 \`.mancode/shared/context/glossary.json\` \u65F6\uFF0C\u62A5\u544A\u4F18\u5148\u4F7F\u7528\u5176\u4E2D\u672F\u8BED\uFF1B\u53D1\u73B0\u65B0\u7684\u9AD8\u9891\u9886\u57DF\u8BCD\u53EF\u5728\u62A5\u544A\u4E2D\u5217\u4E3A\u5EFA\u8BAE\u8BCD\u6761\uFF08\u4EC5\u5EFA\u8BAE\uFF0C\u4E0D\u5199\u5165\u672F\u8BED\u8868\uFF09
14345
14365
  - \u5F15\u7528\u6587\u4EF6\u7528 \`path:line\` \u683C\u5F0F\uFF0C\u8BA9 Head Coach \u4E00\u79D2\u8DF3\u8FC7\u53BB
14346
14366
 
@@ -14406,6 +14426,16 @@ var SCOUT_AGENT = {
14406
14426
  - Transport/platform: <\u5F71\u54CD\u6216 no change>
14407
14427
  - Migration/rollback: <\u9700\u8981\u7684\u8BC1\u636E\u6216 no change>
14408
14428
 
14429
+ ## Decision-impact Findings
14430
+ - Finding ID: F-1\uFF08\u540E\u7EED\u4F9D\u6B21 F-2\u3001F-3\uFF1B\u6700\u591A\u4E09\u9879\uFF09
14431
+ - Type: premise | scope | technical | risk | acceptance
14432
+ - Status: repository_fact | domain_hypothesis
14433
+ - Finding: <\u4E0E\u7528\u6237\u524D\u63D0\u51B2\u7A81\u7684\u4E8B\u5B9E\u3001\u5173\u952E\u76F2\u70B9\u6216\u53EF\u884C\u7684\u8303\u56F4\u5EFA\u8BAE\uFF1B\u6CA1\u6709\u5219\u5199 none>
14434
+ - Evidence/Basis: \`<repository test/file:line/caller-provided output\uFF0C\u6216\u660E\u786E\u6807\u6CE8\u7684\u9886\u57DF\u63A8\u7406\u4F9D\u636E>\`
14435
+ - Class: blocking | recommendable | defaultable
14436
+ - Impact: <\u4F1A\u6539\u53D8\u7684\u76EE\u6807\u3001\u8303\u56F4\u3001\u884C\u4E3A\u3001\u9A8C\u6536\u3001\u67B6\u6784\u3001\u6570\u636E\u3001\u517C\u5BB9\u6027\u3001\u5B89\u5168\u6216 owner>
14437
+ - Recommendation: <\u4E00\u4E2A\u6700\u5C0F\u3001\u76F4\u63A5\u7684\u5EFA\u8BAE\uFF1B\u4E0D\u66FF\u7528\u6237\u786E\u8BA4>
14438
+
14409
14439
  ## \u76F8\u4F3C\u5B9E\u73B0
14410
14440
  - \`<detected-source-root>/<relevant-file>:<line>\` \u2014 \u7B80\u8FF0\u53EF\u590D\u7528\u7684\u903B\u8F91
14411
14441
 
@@ -14441,8 +14471,8 @@ trigger: <\u88AB\u65B0\u8BC1\u636E\u63A8\u7FFB\u6216\u8D85\u51FA\u5F53\u524D req
14441
14471
 
14442
14472
  - \u7528 Grep / Glob \u627E\u4EE3\u7801\uFF0C\u4E0D\u8981 cat \u6574\u4E2A\u6587\u4EF6
14443
14473
  - \u7528 Read \u770B file:line \u9644\u8FD1\u7684\u4E0A\u4E0B\u6587
14444
- - \u7528 Bash \u8DD1 \`git log --oneline -5\` \u4E86\u89E3\u6700\u8FD1\u6539\u52A8
14445
- - **\u4E0D\u8981** Edit / Write \u2014 \u90A3\u662F Head Coach \u7684\u6D3B
14474
+ - \u53EA\u5F15\u7528\u5F53\u524D\u53EA\u8BFB\u5DE5\u5177\u80FD\u591F\u6838\u9A8C\u7684\u8BC1\u636E\uFF1B\u9700\u8981\u8FD0\u884C\u547D\u4EE4\u65F6\uFF0C\u628A\u547D\u4EE4\u5217\u4E3A\u4EA4\u7ED9\u8C03\u7528\u65B9\u7684\u9A8C\u8BC1\u5EFA\u8BAE\uFF0C\u4E0D\u81EA\u884C\u6267\u884C
14475
+ - **\u4E0D\u8981** Edit / Write / Bash \u2014 \u90A3\u662F\u6267\u884C\u9636\u6BB5\u7684\u6D3B
14446
14476
 
14447
14477
  \u6536\u5230\u4EFB\u52A1\u540E\u7ACB\u5373\u5F00\u59CB\u8C03\u7814\u3002\u62A5\u544A\u5B8C\u6574\u5373\u53EF\uFF0C\u4E0D\u9700\u8981\u7B49\u7528\u6237\u786E\u8BA4\u3002`
14448
14478
  };
@@ -14466,7 +14496,11 @@ var PLAN_COACH_AGENT = {
14466
14496
 
14467
14497
  ## \u8F93\u5165\u5C31\u7EEA\u68C0\u67E5
14468
14498
 
14469
- \u5148\u8BFB\u53D6 \`requirements.json\`\uFF0C\u4EE5\u5176\u4E2D\u7684 confirmedScope\u3001excludedScope\u3001technicalDecisions\u3001defaults\u3001blockingUnknowns\u3001coverage \u548C acceptanceCriteria \u4E3A\u6743\u5A01\u8F93\u5165\uFF1B\`requirements.md\` \u53EA\u7528\u4E8E\u9605\u8BFB\u3002\u9010\u9879\u68C0\u67E5 platform\u3001core_scope\u3001technical_stack\u3001data_and_persistence\u3001performance\u3001compatibility\u3001security \u7684\u72B6\u6001\u548C\u7406\u7531\u662F\u5426\u4E0E\u4E8B\u5B9E\u4E00\u81F4\u3002\u68C0\u67E5\u9700\u6C42\u662F\u5426\u8986\u76D6\u4EFB\u52A1\u5B9E\u9645\u9002\u7528\u7684\u7528\u6237\u76EE\u6807\u3001\u6838\u5FC3\u6D41\u7A0B\u3001\u9996\u671F\u8303\u56F4\u3001\u6392\u9664\u9879\u3001\u6280\u672F\u4E0E\u8FD0\u884C\u7EA6\u675F\u3001\u6570\u636E/\u72B6\u6001/\u96C6\u6210\u3001\u5173\u952E\u6027\u80FD/\u517C\u5BB9\u6027/\u5B89\u5168\u8981\u6C42\u548C\u9A8C\u6536\u6807\u51C6\u3002blockingUnknowns \u975E\u7A7A\u3001coverage \u7528\u65E0\u6839\u636E\u7684 not_applicable \u63A9\u76D6\u51B3\u7B56\u3001\u6838\u5FC3\u884C\u4E3A\u7F3A\u5C11\u9A8C\u6536 ID\uFF0C\u6216\u6587\u6863\u4E0E\u7ED3\u6784\u5316\u8F93\u5165\u77DB\u76FE\u65F6\u5FC5\u987B\u8FD4\u56DE NEEDS_CLARIFICATION\u3002
14499
+ \u5148\u8BFB\u53D6 \`requirements.json\`\u3002V3 \u4EE5 \`functionalScope.inScope\`\u3001\`functionalScope.outOfScope\`\u3001\`technicalDecisions\`\u3001\`defaults\`\u3001\`blockingUnknowns\`\u3001\`coverage\` \u548C \`acceptanceCriteria\` \u4E3A\u6743\u5A01\u8F93\u5165\uFF1Blegacy \u8F93\u5165\u4E2D\u7684\u8BED\u4E49\u5BF9\u5E94\u5B57\u6BB5\u662F \`confirmedScope\` \u4E0E \`excludedScope\`\uFF1B\`requirements.md\` \u53EA\u7528\u4E8E\u9605\u8BFB\u3002\u9010\u9879\u68C0\u67E5 platform\u3001core_scope\u3001technical_stack\u3001data_and_persistence\u3001performance\u3001compatibility\u3001security \u7684\u72B6\u6001\u548C\u7406\u7531\u662F\u5426\u4E0E\u4E8B\u5B9E\u4E00\u81F4\u3002\u68C0\u67E5\u9700\u6C42\u662F\u5426\u8986\u76D6\u4EFB\u52A1\u5B9E\u9645\u9002\u7528\u7684\u7528\u6237\u76EE\u6807\u3001\u6838\u5FC3\u6D41\u7A0B\u3001\u9996\u671F\u8303\u56F4\u3001\u6392\u9664\u9879\u3001\u6280\u672F\u4E0E\u8FD0\u884C\u7EA6\u675F\u3001\u6570\u636E/\u72B6\u6001/\u96C6\u6210\u3001\u5173\u952E\u6027\u80FD/\u517C\u5BB9\u6027/\u5B89\u5168\u8981\u6C42\u548C\u9A8C\u6536\u6807\u51C6\u3002blockingUnknowns \u975E\u7A7A\u3001coverage \u7528\u65E0\u6839\u636E\u7684 not_applicable \u63A9\u76D6\u51B3\u7B56\u3001\u6838\u5FC3\u884C\u4E3A\u7F3A\u5C11\u9A8C\u6536 ID\uFF0C\u6216\u6587\u6863\u4E0E\u7ED3\u6784\u5316\u8F93\u5165\u77DB\u76FE\u65F6\u5FC5\u987B\u8FD4\u56DE NEEDS_CLARIFICATION\u3002
14500
+
14501
+ \u9010\u9879\u6838\u5BF9 Scout \u7684 F-1\u2026F-3 \u662F\u5426\u5DF2\u6709\u6309\u7C7B\u578B\u5904\u7F6E\uFF1A\`repository_fact\` \u53EF\u4EE5\u7EA0\u6B63\u9519\u8BEF\u524D\u63D0\uFF1B\`domain_hypothesis\` \u5FC5\u987B\u5148\u8F6C\u6210\u805A\u7126\u95EE\u9898\uFF0C\u4E0D\u80FD\u5F53\u6210\u5DF2\u786E\u8BA4\u4E8B\u5B9E\u3002blocking \u5199\u5165 \`blockingUnknowns\`\uFF1B\u7528\u6237\u63A5\u53D7\u7684\u8303\u56F4\u6216\u884C\u4E3A finding \u5199\u5165 \`confirmedScope\`\uFF08V3 \u4E3A \`functionalScope.inScope\`\uFF09\u5E76\u8865\u4E0A\u5339\u914D\u7684\u9A8C\u6536 \`acceptanceCriteria\`\uFF1B\u7528\u6237\u63A5\u53D7\u7684\u6280\u672F\u9009\u62E9\u5199\u5165 \`technicalDecisions\`\uFF1B\u4F4E\u5F71\u54CD\u3001\u53EF\u9006\u7684\u5B9E\u73B0\u7EC6\u8282\u624D\u5199\u5165 \`defaults\`\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u6392\u9664\u7684\u884C\u4E3A\u5199\u5165 \`excludedScope\`\uFF08V3 \u4E3A \`functionalScope.outOfScope\`\uFF09\u3002\u672A\u63A5\u53D7\u7684\u5EFA\u8BAE\u4ECD\u7136\u6CA1\u6709\u6267\u884C\u6743\uFF0C\u4F46\u4E0D\u5F97\u81EA\u52A8\u585E\u5165 excludedScope\uFF0C\u66F4\u4E0D\u80FD\u590D\u5236\u8FDB\u6240\u6709\u5B57\u6BB5\u3002\u9519\u8BEF\u524D\u63D0\u6216\u98CE\u9669\u82E5\u4F1A\u6539\u53D8\u8BA1\u5212\uFF0C\u5FC5\u987B\u5148\u4F5C\u4E3A blocking \u6F84\u6E05\uFF0C\u518D\u6309\u6700\u7EC8\u8BED\u4E49\u843D\u5165\u4E0A\u8FF0\u552F\u4E00\u5408\u9002\u4F4D\u7F6E\u3002\u53D1\u73B0\u53EA\u4EA7\u751F\u5EFA\u8BAE\u6743\uFF0Cconfirmed requirements \u624D\u4EA7\u751F\u884C\u4E3A\u6388\u6743\u3002
14502
+
14503
+ \u8BA1\u5212\u8FD8\u5FC5\u987B\u8BFB\u53D6\u6216\u63D0\u51FA\u4E00\u4EFD\u7528\u6237\u53EF\u89C1\u7684 \`implementationScope\`\uFF08repo-relative \`include\`\u3001\`exclude\`\u3001\`modules\`\uFF09\uFF0C\u4F5C\u4E3A\u6587\u4EF6\u6539\u52A8\u4E0A\u9650\u3002\u5B83\u4E0D\u80FD\u7531 Scout \u5EFA\u8BAE\u81EA\u52A8\u751F\u6210\u6388\u6743\uFF0C\u4E5F\u4E0D\u80FD\u7528\u6A21\u5757\u6807\u7B7E\u4EE3\u66FF\u975E\u7A7A include\uFF1B\u5B83\u4E0E\u884C\u4E3A\u9700\u6C42\u5171\u540C\u7EA6\u675F\u6267\u884C\u3002
14470
14504
 
14471
14505
  \u540C\u65F6\u6267\u884C\u65B9\u6848\u5B8C\u6574\u6027\u68C0\u67E5\uFF1A
14472
14506
 
@@ -14474,6 +14508,7 @@ var PLAN_COACH_AGENT = {
14474
14508
  2. \u6BCF\u4E2A\u65B9\u6848\u5FC5\u987B\u8BF4\u660E\u590D\u6742\u5EA6\u7531\u8C01\u627F\u62C5\u4EE5\u53CA\u53EF\u89C2\u5BDF\u6210\u672C\uFF0C\u627F\u62C5\u8005\u53EF\u4EE5\u662F\u5B9E\u73B0\u4EE3\u7801\u3001\u8FC1\u79FB\u3001\u8FD0\u884C\u7EF4\u62A4\u3001\u7528\u6237\u64CD\u4F5C\u3001\u517C\u5BB9\u5C42\u6216\u6D4B\u8BD5\uFF1B\u4E0D\u80FD\u53EA\u5199\u201C\u66F4\u7B80\u5355\u201D\u3002
14475
14509
  3. \u5FC5\u987B\u7ED9\u51FA\u552F\u4E00 recommendation\uFF0C\u5E76\u8BF4\u660E\u62D2\u7EDD\u5176\u4ED6\u65B9\u5411\u7684\u4E3B\u8981\u7406\u7531\uFF1B\u4E0D\u80FD\u628A\u591A\u4E2A\u672A\u51B3\u65B9\u5411\u539F\u6837\u4EA4\u7ED9\u7528\u6237\u3002
14476
14510
  4. \u7B80\u5355\u4EFB\u52A1\u6CA1\u6709\u771F\u5B9E\u66FF\u4EE3\u65B9\u6848\u65F6\u53EA\u5217\u4E00\u4E2A\u660E\u663E\u53EF\u884C\u65B9\u5411\uFF0C\u5E76\u89E3\u91CA\u4E3A\u4EC0\u4E48\u4E0D\u5B58\u5728\u771F\u5B9E\u66FF\u4EE3\uFF1B\u4E0D\u5F97\u5236\u9020\u4F2A\u9009\u9879\u3002\u8FD9\u4E2A\u5355\u4E00\u65B9\u5411\u4ECD\u5FC5\u987B\u6210\u4E3A recommendation \u5E76\u6709 stop conditions\u3002
14511
+ 5. \u6BCF\u4E2A\u5B9E\u65BD\u6B65\u9AA4\u5FC5\u987B\u6620\u5C04\u5230\u5DF2\u786E\u8BA4\u8303\u56F4\u6216\u9A8C\u6536 ID\u3002\u4F18\u5148\u590D\u7528\u73B0\u6709\u5B9E\u73B0\u548C\u4F9D\u8D56\uFF0C\u9009\u62E9\u80FD\u6EE1\u8DB3\u9A8C\u6536\u7684\u6700\u5C0F\u76F4\u63A5\u65B9\u6848\uFF1B\u4E0D\u4E3A\u5355\u6B21\u7528\u9014\u589E\u52A0\u62BD\u8C61\u3001\u53EF\u914D\u7F6E\u6027\u3001\u76F8\u90BB\u6E05\u7406\u6216\u63A8\u6D4B\u6027\u9632\u5FA1\u3002
14477
14512
 
14478
14513
  Scout \u82E5\u7ED9\u51FA\u4E24\u4E2A\u540C\u7B49\u5019\u9009 semantic owner\u3001\u65E0\u6CD5\u786E\u5B9A authority/writer\uFF0C\u6216 evidence \u4E0E confirmed requirements \u51B2\u7A81\uFF0C\u4E0D\u80FD\u81EA\u884C\u9009\u4E00\u4E2A\u7EE7\u7EED\u3002
14479
14514
 
@@ -14507,6 +14542,10 @@ stop_conditions: <conditions that invalidate this plan>
14507
14542
  ## \u6A21\u5757\u7D22\u5F15
14508
14543
  ## \u6280\u672F\u4E0E\u4EA4\u4ED8\u7EA6\u675F\uFF08\u4EC5\u65B0\u9879\u76EE\u6216\u6280\u672F\u9009\u62E9\u672A\u5B9A\u65F6\uFF09
14509
14544
  - \u5DF2\u786E\u8BA4\u65B9\u6848\u3001\u9009\u62E9\u7406\u7531\u548C\u53D6\u820D\uFF1B\u5C1A\u672A\u786E\u8BA4\u4F1A\u6539\u53D8\u67B6\u6784\u7684\u6280\u672F\u9009\u62E9\u65F6\u8FD4\u56DE NEEDS_CLARIFICATION\uFF1B\u5DF2\u6709\u9879\u76EE\u5199\u201C\u6CBF\u7528\u68C0\u6D4B\u5230\u7684\u9879\u76EE\u7EA6\u5B9A\u201D
14545
+ ## \u6267\u884C\u8FB9\u754C\uFF08implementationScope\uFF09
14546
+ - include\uFF1A<\u5141\u8BB8\u4FEE\u6539\u7684 repo-relative \u8DEF\u5F84/glob>
14547
+ - exclude\uFF1A<\u5373\u4F7F\u5339\u914D include \u4E5F\u4E0D\u5F97\u4FEE\u6539\u7684\u8DEF\u5F84/glob>
14548
+ - modules\uFF1A<\u8BED\u4E49\u5F52\u5C5E\u6807\u7B7E\uFF1B\u4E0D\u5355\u72EC\u6388\u6743\u6587\u4EF6\u5199\u5165>
14510
14549
  ## \u6A21\u5757\uFF1A<\u540D\u79F0>
14511
14550
  ### \u6539\u52A8\u6587\u4EF6 / \u65B0\u5EFA\u6587\u4EF6
14512
14551
  ### \u590D\u7528\u8D44\u6E90\uFF08\u5F15\u7528 scout-report.md \u884C\u53F7\uFF09
@@ -14652,7 +14691,8 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
14652
14691
  - \u6539\u52A8\u5B64\u7ACB\u4E86\u67D0\u4E2A import / \u53D8\u91CF / \u51FD\u6570 \u2192 \u79FB\u9664\u5B83
14653
14692
  - \u4E0D\u79FB\u9664\u6539\u52A8\u524D\u5C31\u5B58\u5728\u7684\u6B7B\u4EE3\u7801\uFF08\u63D0\u4E00\u53E5\u5C31\u884C\uFF09
14654
14693
  - \u5148\u8BFB \`.mancode/project-profile.json\`\uFF1B\u4EFB\u52A1\u6D89\u53CA UI \u65F6\u8FD0\u884C \`mancode design context --json\` \u4E00\u6B21\u5E76\u628A\u7ED3\u679C\u89C6\u4E3A\u53D7\u9650\u6570\u636E\uFF1B\u547D\u4EE4\u4E0D\u53EF\u7528\u65F6\u8BFB\u53D6\u5BA1\u7F8E token
14655
- - \u65B0\u5EFA UI \u6216\u89C6\u89C9\u91CD\u505A\u4E14\u7528\u6237\u5C1A\u672A\u9009\u5B9A\u65B9\u5411\u65F6\uFF0C\u5148\u7ED9\u51FA 2\u20133 \u4E2A\u5DEE\u5F02\u660E\u786E\u3001\u7B26\u5408\u4EA7\u54C1\u8BED\u5883\u7684\u65B9\u5411\uFF0C\u7B80\u8FF0\u53D6\u820D\u5E76\u63A8\u8350\u4E00\u4E2A\uFF0C\u7B49\u5F85\u7528\u6237\u9009\u62E9\u540E\u518D\u5B9E\u73B0\uFF1B\u5C40\u90E8 UI \u4FEE\u590D\u6216\u5DF2\u6709\u65B9\u5411\u5185\u7684\u5DE5\u4F5C\u76F4\u63A5\u6267\u884C
14694
+ - \u754C\u9762\u56FE\u6807\u3001\u5BFC\u822A\u3001\u6309\u94AE\u3001\u64CD\u4F5C\u548C\u72B6\u6001\u6807\u8BC6\u7981\u6B62\u4F7F\u7528\u8868\u60C5\u7B26\u53F7\uFF1B\u804A\u5929\u6D88\u606F\u3001\u7528\u6237\u8F93\u5165\u3001\u6B63\u6587\u548C\u4E1A\u52A1\u6570\u636E\u53EF\u4EE5\u5305\u542B\u8868\u60C5\u3002\u6CA1\u6709\u53EF\u7528\u56FE\u6807\u5E93\u65F6\u4F7F\u7528\u6E05\u6670\u6587\u5B57\u6807\u7B7E\u6216\u8BF7\u6C42\u5B89\u88C5\u56FE\u6807\u5E93\uFF0C\u4E0D\u80FD\u9000\u56DE\u8868\u60C5\u56FE\u6807
14695
+ - \u65B0\u5EFA UI \u6216\u89C6\u89C9\u91CD\u505A\u4E14\u7528\u6237\u5C1A\u672A\u9009\u5B9A\u65B9\u5411\u65F6\uFF0C\u5148\u7ED9\u51FA 2\u20133 \u4E2A\u5DEE\u5F02\u660E\u786E\u3001\u7B26\u5408\u4EA7\u54C1\u8BED\u5883\u7684\u65B9\u5411\uFF0C\u7B80\u8FF0\u53D6\u820D\u5E76\u63A8\u8350\u4E00\u4E2A\uFF0C\u7B49\u5F85\u7528\u6237\u9009\u62E9\u540E\u518D\u5B9E\u73B0\uFF1B\u201C\u4F01\u4E1A\u7EA7\u201D\u201C\u7B80\u6D01\u201D\u201C\u73B0\u4EE3\u201D\u201C\u9AD8\u7EA7\u201D\u201C\u4E0D\u82B1\u54E8\u201D\u7B49\u5BBD\u6CDB\u5F62\u5BB9\u8BCD\u53EA\u662F\u7EA6\u675F\uFF0C\u4E0D\u7B97\u5DF2\u7ECF\u9009\u5B9A\u89C6\u89C9\u65B9\u5411\uFF1B\u5C40\u90E8 UI \u4FEE\u590D\u6216\u5DF2\u6709\u65B9\u5411\u5185\u7684\u5DE5\u4F5C\u76F4\u63A5\u6267\u884C
14656
14696
 
14657
14697
  ---
14658
14698
 
@@ -14761,6 +14801,7 @@ var FILM_ANALYST_OFFENSE_AGENT = {
14761
14801
  - \u6700\u540E\u7ED9\u8BC4\u5206\uFF081-10\uFF09+ \u901A\u8FC7 / \u4E0D\u901A\u8FC7
14762
14802
  - \u53EA\u5BA1\u67E5\u672C\u6B21 diff\u3001\u7528\u6237\u9700\u6C42\u548C\u76F4\u63A5\u53D7\u5F71\u54CD\u8DEF\u5F84\uFF1B\u6700\u591A 3 \u4E2A\u65B0\u95EE\u9898
14763
14803
  - \u6BCF\u4E2A\u95EE\u9898\u5FC5\u987B\u5305\u542B\u6539\u52A8\u884C\u3001\u53EF\u6838\u67E5\u8BC1\u636E\u548C\u7528\u6237\u5F71\u54CD\u3002\u6CA1\u6709\u8BC1\u636E\u7684 checklist \u9879\u4E0D\u8F93\u51FA
14804
+ - \u5148\u505A\u6388\u6743\u4E00\u81F4\u6027\u5BA1\u67E5\uFF1AV3 \u5BF9\u7167 requirements \u7684 \`functionalScope.inScope\` / \`functionalScope.outOfScope\`\u3001\`technicalDecisions\`\u3001\`defaults\` \u548C \`acceptanceCriteria\`\uFF1Blegacy \u5BF9\u7167\u8BED\u4E49\u7B49\u4EF7\u7684 \`confirmedScope\` / \`excludedScope\`\u3002\u540C\u65F6\u8BFB\u53D6 Context Pack \u7684 \`activeTask.implementationScope\`\uFF0C\u9010\u4E2A\u68C0\u67E5\u5B9E\u9645\u6539\u52A8\u8DEF\u5F84\u662F\u5426\u843D\u5728 include \u4E14\u4E0D\u5339\u914D exclude\uFF1Bmodules \u53EA\u662F\u5F52\u5C5E\u6807\u7B7E\uFF0C\u4E0D\u5355\u72EC\u6388\u6743\u6587\u4EF6\u5199\u5165\u3002\u4EFB\u4F55\u672A\u7ECF\u6388\u6743\u3001\u89E6\u78B0\u884C\u4E3A\u6392\u9664\u9879\u3001\u8D85\u51FA\u6587\u4EF6\u8FB9\u754C\u6216\u65E0\u6CD5\u8FFD\u6EAF\u5230\u9A8C\u6536\u7684\u6539\u52A8\u4E00\u5F8B\u8BB0\u4E3A \u{1F534} scope blocker
14764
14805
 
14765
14806
  ## \u4F60\u4E0D\u5199\u4EE3\u7801
14766
14807
 
@@ -14770,6 +14811,7 @@ var FILM_ANALYST_OFFENSE_AGENT = {
14770
14811
 
14771
14812
  | \u7EF4\u5EA6 | \u68C0\u67E5\u4EC0\u4E48 |
14772
14813
  |---|---|
14814
+ | **\u6388\u6743\u4E00\u81F4\u6027** | \u6BCF\u4E00\u5904\u6539\u52A8\u80FD\u5426\u540C\u65F6\u8FFD\u6EAF\u5230\u5DF2\u786E\u8BA4\u884C\u4E3A/\u9A8C\u6536 ID\uFF0C\u5E76\u4F4D\u4E8E implementationScope \u6587\u4EF6\u8FB9\u754C\u5185\uFF1B\u662F\u5426\u5B9E\u73B0\u4E86\u88AB\u62D2\u7EDD\u3001\u5EF6\u671F\u6216\u672A\u8BA8\u8BBA\u7684\u5EFA\u8BAE |
14773
14815
  | **\u53EF\u8BFB\u6027** | \u547D\u540D\u6E05\u6670\u3001\u7ED3\u6784\u5408\u7406\u3001\u6CE8\u91CA\u6070\u5F53\uFF08\u53EA\u5728 WHY \u975E\u663E\u7136\u65F6\uFF09 |
14774
14816
  | **\u53EF\u7EF4\u62A4\u6027** | \u6A21\u5757\u8FB9\u754C\u3001\u8026\u5408\u5EA6\u3001\u6269\u5C55\u6027 |
14775
14817
  | **\u98CE\u683C\u4E00\u81F4\u6027** | \u662F\u5426\u5339\u914D\u9879\u76EE\u5DF2\u6709\u98CE\u683C\uFF08\u5373\u4F7F\u4F60\u4E0D\u8BA4\u540C\uFF09 |
@@ -15059,6 +15101,8 @@ const state = readJson(path.join(mancodeDir, 'state.json')) || {};
15059
15101
  const profile = readJson(path.join(mancodeDir, 'project-profile.json')) || {};
15060
15102
  const mode = typeof state.currentMode === 'string' ? state.currentMode : '';
15061
15103
  const output = [];
15104
+ const interfaceEmojiIconGuidance = ${JSON.stringify(INTERFACE_EMOJI_ICON_GUIDANCE)};
15105
+ const visualDirectionSelectionGuidance = ${JSON.stringify(VISUAL_DIRECTION_SELECTION_GUIDANCE)};
15062
15106
 
15063
15107
  if (mode === 'solo') {
15064
15108
  output.push(
@@ -15122,9 +15166,25 @@ if (
15122
15166
  );
15123
15167
  }
15124
15168
 
15125
- const uiPattern = /\b(?:button|component|page|style|ui|design|layout|css|color|font|theme|card|input|modal|dialog|header|footer|sidebar|dropdown|tooltip|toast|avatar|badge)\b|界面|页面|按钮|样式|颜色|字体|布局|组件|弹窗|导航|卡片|输入框|主题|美化|优化.*界面|调整.*样式/iu;
15169
+ const strongUiPattern = /\b(?:ui|ux|front-?end|html|web ?page|page|button|icon|lucide|layout|css|card|modal|dialog|header|footer|sidebar|navigation|navbar|menu|dropdown|tooltip|toast|avatar|badge|dashboard|status indicator)s?\b|界面|页面|网页|前端|按钮|图标|布局|弹窗|导航|菜单|卡片|状态标识|状态图标|美化|优化.*界面|调整.*样式/iu;
15170
+ const weakVisualPattern = /\b(?:component|style|design|color|font|theme|input|visual|aesthetic)s?\b|样式|颜色|字体|主题|组件|输入框|审美|视觉|美观|好看/iu;
15171
+ const hasStrongUiSignal = strongUiPattern.test(userPrompt);
15172
+ const hasWeakVisualSignal = weakVisualPattern.test(userPrompt);
15173
+ const isUiPrompt =
15174
+ hasStrongUiSignal ||
15175
+ (profile.uiAssets === 'detected' && hasWeakVisualSignal);
15176
+
15177
+ if (isUiPrompt) {
15178
+ output.push(
15179
+ '## mancode UI design baseline',
15180
+ '',
15181
+ interfaceEmojiIconGuidance,
15182
+ visualDirectionSelectionGuidance,
15183
+ '',
15184
+ );
15185
+ }
15126
15186
 
15127
- if (profile.uiAssets === 'detected' && uiPattern.test(userPrompt)) {
15187
+ if (profile.uiAssets === 'detected' && isUiPrompt) {
15128
15188
  appendAestheticSummary(
15129
15189
  output,
15130
15190
  readJson(path.join(mancodeDir, 'aesthetics', 'style-tokens.json')),
@@ -15266,11 +15326,13 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
15266
15326
  \u8FD9\u662F\u53EA\u8BFB\u8BCA\u65AD\u3002\u4FDD\u7559 requirements\u3001plan\u3001review/verification ledger\u3001claims\u3001handoff \u548C metadata\uFF1B\u4E0D\u8C03\u7528\u901A\u7528 \`workflow update\`\uFF0C\u4E0D\u5199 blocked/currentStep/planning\uFF0C\u4E0D\u5F52\u6863\u65E7\u6587\u4EF6\uFF0C\u4E0D\u91CA\u653E claim\uFF0C\u4E0D\u53D6\u6D88 handoff\uFF0C\u4E5F\u4E0D\u5BA3\u79F0\u5DF2\u56DE\u5230 Step 2\u3002
15267
15327
 
15268
15328
  ### UI \u4EFB\u52A1\uFF08\u6761\u4EF6\u6267\u884C\uFF09
15269
- \u4EC5\u5F53 project-profile \u786E\u8BA4\u6709 UI \u8D44\u4EA7\u4E14\u4EFB\u52A1\u786E\u5B9E\u6D89\u53CA\u754C\u9762\u65F6\uFF1A
15270
- 1. UserPromptSubmit hook \u4F1A\u6CE8\u5165\u9879\u76EE\u5BA1\u7F8E token\uFF08\u5982\u6709\uFF09
15271
- 2. \u4E25\u683C\u4F7F\u7528\u5DF2\u6709 token \u548C\u7EC4\u4EF6\uFF1B\u6CA1\u6709\u53EF\u9760 token \u65F6\u5148\u68C0\u67E5\u73B0\u6709\u754C\u9762\uFF0C\u518D\u63D0\u51FA\u6700\u5C0F\u4E00\u81F4\u65B9\u6848
15272
- 3. \u4E0D\u628A\u7279\u5B9A\u6846\u67B6\u3001\u7EC4\u4EF6\u540D\u3001\u8272\u677F\u6216\u4EA4\u4E92\u8303\u5F0F\u5F53\u4F5C\u9ED8\u8BA4
15273
- 4. \u4EE5\u9879\u76EE\u65E2\u6709\u7684\u65E0\u969C\u788D\u3001\u54CD\u5E94\u5F0F\u4E0E\u53CD\u9988\u65B9\u5F0F\u4E3A\u51C6
15329
+ \u4EFB\u52A1\u6D89\u53CA\u754C\u9762\u65F6\uFF1A
15330
+ - ${INTERFACE_EMOJI_ICON_GUIDANCE}
15331
+ - ${VISUAL_DIRECTION_SELECTION_GUIDANCE}
15332
+ - project-profile \u786E\u8BA4\u6709 UI \u8D44\u4EA7\u65F6\uFF0CUserPromptSubmit hook \u4F1A\u6CE8\u5165\u9879\u76EE\u5BA1\u7F8E token\uFF08\u5982\u6709\uFF09
15333
+ - \u4E25\u683C\u4F7F\u7528\u5DF2\u6709 token \u548C\u7EC4\u4EF6\uFF1B\u6CA1\u6709\u53EF\u9760 token \u65F6\u5148\u68C0\u67E5\u73B0\u6709\u754C\u9762\uFF0C\u518D\u63D0\u51FA\u6700\u5C0F\u4E00\u81F4\u65B9\u6848
15334
+ - \u4E0D\u628A\u7279\u5B9A\u6846\u67B6\u3001\u7EC4\u4EF6\u540D\u3001\u8272\u677F\u6216\u4EA4\u4E92\u8303\u5F0F\u5F53\u4F5C\u9ED8\u8BA4
15335
+ - \u4EE5\u9879\u76EE\u65E2\u6709\u7684\u65E0\u969C\u788D\u3001\u54CD\u5E94\u5F0F\u4E0E\u53CD\u9988\u65B9\u5F0F\u4E3A\u51C6
15274
15336
 
15275
15337
  ### \u754C\u9762\u8D28\u91CF\u68C0\u67E5\uFF08\u6761\u4EF6\u6267\u884C\uFF09
15276
15338
  \u53EA\u68C0\u67E5\u672C\u6B21 diff \u65B0\u589E\u6216\u6539\u53D8\u7684\u754C\u9762\u884C\u4E3A\uFF1A\u590D\u7528\u5DF2\u6709\u5C42\u7EA7\u3001token \u548C\u7EC4\u4EF6\uFF1B\u65B0\u589E\u5F02\u6B65\u6216\u4EA4\u4E92\u8DEF\u5F84\u65F6\u624D\u68C0\u67E5\u5BF9\u5E94\u7684\u52A0\u8F7D\u3001\u5931\u8D25\u548C\u53EF\u8FBE\u6027\u72B6\u6001\u3002\u4E0D\u8981\u501F UI \u81EA\u68C0\u5DE1\u67E5\u672A\u6539\u52A8\u9875\u9762\u6216\u8865\u9F50\u63A8\u6D4B\u6027\u72B6\u6001\u3002
@@ -15298,11 +15360,11 @@ trigger: <\u5177\u4F53\u4E8B\u5B9E>
15298
15360
  // src/templates/skills/principles.ts
15299
15361
  var CORE_CODING_PRINCIPLES = `## \u94C1\u5F8B\uFF08\u6C38\u4E0D\u8FDD\u53CD\uFF09
15300
15362
 
15301
- 1. **\u4E0D\u505A\u65E0\u5173\u4FEE\u6539** \u2014 \u53EA\u6539 plan \u8303\u56F4\u5185\u7684
15302
- 2. **\u5148\u9A8C\u8BC1\u518D\u58F0\u79F0\u5B8C\u6210** \u2014 build/lint/test \u5FC5\u987B\u5B9E\u9645\u8DD1
15363
+ 1. **\u4E0D\u505A\u65E0\u5173\u4FEE\u6539** \u2014 \u53EA\u6539\u7528\u6237\u5DF2\u786E\u8BA4\u7684 plan \u4E0E implementationScope\uFF1B\u6BCF\u4E00\u5904\u6539\u52A8\u90FD\u80FD\u8FFD\u6EAF\u5230\u8303\u56F4\u6216\u9A8C\u6536
15364
+ 2. **\u5148\u9A8C\u8BC1\u518D\u58F0\u79F0\u5B8C\u6210** \u2014 \u5F00\u5DE5\u524D\u5199\u660E\u5B9E\u8D28\u5047\u8BBE\u548C\u53EF\u9A8C\u8BC1\u6210\u529F\u6807\u51C6\uFF1Bbuild/lint/test \u5FC5\u987B\u5B9E\u9645\u8DD1
15303
15365
  3. **\u5931\u8D25\u4E24\u6B21\u5FC5\u987B\u505C\u4E0B** \u2014 \u4E0D\u76F2\u8BD5
15304
15366
  4. **\u4E0D\u53EF\u9006\u64CD\u4F5C\u5148\u95EE** \u2014 \u5220\u9664\u3001force push\u3001worktree \u5408\u5E76
15305
- 5. **\u53EA\u89E3\u51B3\u88AB\u95EE\u5230\u7684\u95EE\u9898** \u2014 \u4E0D\u52A0\u63A8\u6D4B\u6027\u529F\u80FD`;
15367
+ 5. **\u53EA\u89E3\u51B3\u88AB\u95EE\u5230\u7684\u95EE\u9898** \u2014 \u4F18\u5148\u590D\u7528\u73B0\u6709\u5B9E\u73B0\uFF0C\u9009\u62E9\u6EE1\u8DB3\u9A8C\u6536\u7684\u6700\u5C0F\u76F4\u63A5\u6539\u52A8\uFF1B\u4E0D\u52A0\u63A8\u6D4B\u6027\u529F\u80FD\u3001\u4E00\u6B21\u6027\u62BD\u8C61\u3001\u65E0\u5173\u6E05\u7406\u6216\u591A\u4F59\u914D\u7F6E`;
15306
15368
 
15307
15369
  // src/templates/skills/man.ts
15308
15370
  var MAN_SKILL = {
@@ -15322,7 +15384,7 @@ var MAN_SKILL = {
15322
15384
 
15323
15385
  ### Step 1: Scout \u8C03\u7814
15324
15386
 
15325
- \u5148\u8BFB \`.mancode/shared/context/glossary.json\`\uFF08\u82E5\u5B58\u5728\uFF09\uFF0C\u8C03\u7814\u3001\u62A5\u544A\u4E0E\u540E\u7EED\u6C9F\u901A\u4F18\u5148\u4F7F\u7528\u5176\u4E2D\u5DF2\u786E\u8BA4\u672F\u8BED\u3002\u8C03\u7528 \`scout\`\uFF0C\u5199 \`scout-report.md\`\u3002\u62A5\u544A\u5FC5\u987B\u5305\u542B\u201C**\u4E0D\u786E\u5B9A\u7684\u5730\u65B9**\u201D\uFF0C\u5E76\u6309\u53EF\u9A8C\u8BC1\u4E8B\u5B9E\u8865\u5145 Current Behavior Evidence\u3001Candidate Semantic Owner\u3001Source of Truth\u3001Historical / Compatibility Impact\uFF1B\u5B57\u6BB5\u4E0D\u76F8\u5173\u6216\u65E0\u6CD5\u9A8C\u8BC1\u65F6\u53EF\u4EE5\u7701\u7565\uFF0C\u4E0D\u80FD\u7F16\u9020\u3002Current Behavior Evidence \u81F3\u5C11\u6709\u4E00\u4E2A\u53EF\u590D\u73B0\u89C2\u5BDF\u548C\u4ED3\u5E93\u8DEF\u5F84\u3001\u6D4B\u8BD5\u6216\u547D\u4EE4\u8BC1\u636E\uFF1Bowner \u5199\u7F6E\u4FE1\u5EA6\u4E0E\u51B2\u7A81\uFF1Bsource of truth \u533A\u5206 authority \u548C derived copy\uFF1B\u517C\u5BB9\u5F71\u54CD\u8986\u76D6\u65E7 workflow\u3001legacy fixture\u3001transport\u3001\u8FC1\u79FB\u548C rollback\u3002\u8FD0\u884C \`mancode workflow update <taskId> --step 2\`\u3002
15387
+ \u5148\u8BFB \`.mancode/shared/context/glossary.json\`\uFF08\u82E5\u5B58\u5728\uFF09\uFF0C\u8C03\u7814\u3001\u62A5\u544A\u4E0E\u540E\u7EED\u6C9F\u901A\u4F18\u5148\u4F7F\u7528\u5176\u4E2D\u5DF2\u786E\u8BA4\u672F\u8BED\u3002\u8C03\u7528\u53EA\u8BFB \`scout\`\uFF0C\u5199 \`scout-report.md\`\u3002\u62A5\u544A\u5FC5\u987B\u5305\u542B\u201C**\u4E0D\u786E\u5B9A\u7684\u5730\u65B9**\u201D\u548C\u6700\u591A 3 \u4E2A\u4F1A\u6539\u53D8\u51B3\u7B56\u7684 Decision-impact Findings\uFF1B\u4F7F\u7528\u7A33\u5B9A ID F-1\u2026F-3\uFF0C\u6807\u6CE8 Type\uFF1Apremise / scope / technical / risk / acceptance\uFF0C\u5E76\u533A\u5206 repository_fact \u4E0E domain_hypothesis\u3002\u524D\u8005\u5FC5\u987B\u6709\u4ED3\u5E93\u8BC1\u636E\uFF1B\u540E\u8005\u53EA\u6839\u636E\u7AEF\u5230\u7AEF\u76EE\u6807\u548C\u5E38\u89C1\u9886\u57DF\u5931\u8D25/\u8FB9\u754C\u8DEF\u5F84\u63D0\u51FA\u805A\u7126\u95EE\u9898\uFF0C\u4E0D\u80FD\u5199\u6210\u4E8B\u5B9E\u3002\u6309\u53EF\u9A8C\u8BC1\u4E8B\u5B9E\u8865\u5145 Current Behavior Evidence\u3001Candidate Semantic Owner\u3001Source of Truth\u3001Historical / Compatibility Impact\uFF1B\u5B57\u6BB5\u4E0D\u76F8\u5173\u6216\u65E0\u6CD5\u9A8C\u8BC1\u65F6\u53EF\u4EE5\u7701\u7565\uFF0C\u4E0D\u80FD\u7F16\u9020\u3002Current Behavior Evidence \u81F3\u5C11\u6709\u4E00\u4E2A\u53EF\u590D\u73B0\u89C2\u5BDF\u548C\u4ED3\u5E93\u8DEF\u5F84\u3001\u6D4B\u8BD5\u6216\u8C03\u7528\u65B9\u63D0\u4F9B\u7684\u547D\u4EE4\u8BC1\u636E\uFF1Bowner \u5199\u7F6E\u4FE1\u5EA6\u4E0E\u51B2\u7A81\uFF1Bsource of truth \u533A\u5206 authority \u548C derived copy\uFF1B\u517C\u5BB9\u5F71\u54CD\u8986\u76D6\u65E7 workflow\u3001legacy fixture\u3001transport\u3001\u8FC1\u79FB\u548C rollback\u3002\u4E3B\u52A8\u6838\u9A8C\u7528\u6237\u524D\u63D0\u5E76\u6307\u51FA\u5173\u952E\u76F2\u70B9\uFF0C\u4F46\u53D1\u73B0\u53EA\u4EA7\u751F\u5EFA\u8BAE\u6743\uFF0C\u4E0D\u4EA7\u751F\u6267\u884C\u6743\u3002\u8FD0\u884C \`mancode workflow update <taskId> --step 2\`\u3002
15326
15388
 
15327
15389
  ### Step 2: \u9700\u6C42\u6F84\u6E05
15328
15390
 
@@ -15333,6 +15395,8 @@ var MAN_SKILL = {
15333
15395
  - **recommendable**\uFF1A\u6709\u5408\u9002\u65B9\u6848\u65F6\u76F4\u63A5\u7ED9 2\u20133 \u4E2A\u65B9\u6848\u3001\u4F18\u7F3A\u70B9\u548C\u660E\u786E\u63A8\u8350\uFF0C\u8BA9\u7528\u6237\u63A5\u53D7\u6216\u8C03\u6574\uFF1B\u4E0D\u8981\u53EA\u628A\u9009\u62E9\u9898\u629B\u7ED9\u7528\u6237\u3002
15334
15396
  - **defaultable**\uFF1A\u547D\u540D\u3001\u5FAE\u5C0F\u6837\u5F0F\u7B49\u4F4E\u5F71\u54CD\u7EC6\u8282\uFF0C\u53EF\u91C7\u7528\u9ED8\u8BA4\u503C\uFF0C\u4F46\u5199\u660E\u9ED8\u8BA4\u503C\u548C\u7406\u7531\u3002
15335
15397
 
15398
+ \u4E3A\u6BCF\u4E2A F-1\u2026F-3 \u660E\u786E\u4E14\u6309\u7C7B\u578B\u5904\u7F6E\uFF1Ablocking \u5199\u5165 \`blockingUnknowns\`\uFF1B\u7528\u6237\u63A5\u53D7\u7684\u8303\u56F4\u6216\u884C\u4E3A\u5199\u5165 \`confirmedScope\` \u5E76\u8865\u4E0A\u76F8\u5E94 \`acceptanceCriteria\`\uFF1B\u7528\u6237\u63A5\u53D7\u7684\u6280\u672F\u9009\u62E9\u5199\u5165 \`technicalDecisions\`\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u6392\u9664\u7684\u884C\u4E3A\u5199\u5165 \`excludedScope\`\uFF1B\`defaults\` \u53EA\u80FD\u63CF\u8FF0\u5DF2\u786E\u8BA4\u8303\u56F4\u5185\u4F4E\u5F71\u54CD\u3001\u53EF\u9006\u4E14\u7B26\u5408\u4ED3\u5E93\u7EA6\u5B9A\u7684\u5B9E\u73B0\u7EC6\u8282\uFF0C\u4E0D\u80FD\u6269\u5927\u8303\u56F4\u3002\u672A\u63A5\u53D7\u7684\u5EFA\u8BAE\u4ECD\u65E0\u6267\u884C\u6743\uFF0C\u4F46\u4E0D\u5F97\u81EA\u52A8\u585E\u5165 \`excludedScope\`\uFF0C\u4E5F\u4E0D\u5F97\u590D\u5236\u8FDB\u6240\u6709\u5B57\u6BB5\u3002
15399
+
15336
15400
  \u6309\u4EFB\u52A1\u5B9E\u9645\u9002\u7528\u8303\u56F4\u68C0\u67E5\uFF1A\u7528\u6237\u76EE\u6807\u4E0E\u5E73\u53F0\u3001\u6838\u5FC3\u6D41\u7A0B\u3001\u9996\u671F\u8303\u56F4\u3001\u6392\u9664\u9879\u3001\u6280\u672F\u4E0E\u8FD0\u884C\u7EA6\u675F\u3001\u6570\u636E/\u72B6\u6001/\u96C6\u6210\u3001\u6027\u80FD/\u517C\u5BB9\u6027/\u5B89\u5168\u3001\u53EF\u9A8C\u8BC1\u5B8C\u6210\u6807\u51C6\u3002\u8FDE\u7EED\u6F84\u6E05\u6CA1\u6709\u51CF\u5C11 blocking \u9879\u65F6\uFF0C\u4E0D\u6563\u95EE\uFF1B\u8BA9\u7528\u6237\u9009\u62E9\u7F29\u5C0F\u9996\u671F\u8303\u56F4\u3001\u63A5\u53D7\u5217\u660E\u7684\u63A8\u8350\u9ED8\u8BA4\u503C\u6216\u6682\u505C\u3002
15337
15401
 
15338
15402
  \u628A\u7ED3\u8BBA\u5199\u5165\u7ED3\u6784\u5316\u9700\u6C42\u8F93\u5165\uFF0C\u81F3\u5C11\u5305\u542B \`goal\`\u3001\u975E\u7A7A \`confirmedScope\`\u3001\`excludedScope\`\u3001\`technicalDecisions\`\u3001\`defaults\`\u3001\`blockingUnknowns\`\u3001\`coverage\` \u548C \`acceptanceCriteria\`\u3002coverage \u5FC5\u987B\u9010\u9879\u8BF4\u660E platform\u3001core_scope\u3001technical_stack\u3001data_and_persistence\u3001performance\u3001compatibility\u3001security \u662F \`confirmed\`\u3001\`defaulted\` \u6216\u5E26\u7406\u7531\u7684 \`not_applicable\`\uFF0C\u4E0D\u80FD\u7528\u7A7A\u6570\u7EC4\u5047\u88C5\u5DF2\u7ECF\u8003\u8651\u3002\u6BCF\u4E2A\u6838\u5FC3\u7528\u6237\u884C\u4E3A\u5FC5\u987B\u6709\u7A33\u5B9A\u9A8C\u6536 ID\uFF08\`AC-1\` \u7B49\uFF09\u3001\u63CF\u8FF0\u3001\`required\` \u548C\u9A8C\u8BC1\u65B9\u5F0F \`automated\` / \`manual\` / \`hybrid\`\uFF1B\u81F3\u5C11\u4E00\u4E2A\u9A8C\u6536\u9879\u5FC5\u9700\u3002\u8FD0\u884C \`mancode workflow requirements <taskId> finalize --file <requirements-input.json>\`\uFF0C\u7531 CLI \u6821\u9A8C\u5E76\u751F\u6210\u6743\u5A01 \`requirements.json\` \u4E0E \`requirements.md\`\uFF0C\u4E0D\u8981\u624B\u5DE5\u5236\u9020\u4E24\u4EFD\u53EF\u80FD\u51B2\u7A81\u7684\u7ED3\u8BBA\u3002\u65E0\u987B\u63D0\u95EE\u65F6\u53EF\u628A \`clarification\` \u8BB0\u5165\u7D2F\u8BA1 skippedSteps\uFF0C\u4F46\u4E0D\u80FD\u8DF3\u8FC7\u9700\u6C42\u6458\u8981\u4E0E\u5C31\u7EEA\u5224\u65AD\u3002\u4ECD\u6709 blocking \u9879\u65F6\u505C\u5728 Step 2\uFF1B\u53EA\u6709 CLI \u8FD4\u56DE ready \u624D\u8FD0\u884C \`mancode workflow update <taskId> --step 3\`\u3002
@@ -15343,7 +15407,7 @@ var MAN_SKILL = {
15343
15407
 
15344
15408
  Plan Coach \u5FC5\u987B\u8BC1\u660E\u6240\u6709\u9009\u9879\u89E3\u51B3\u540C\u4E00\u4E2A goal\u3001\u9A8C\u6536\u8FB9\u754C\u548C scope\uFF1B\u9010\u9879\u5199\u660E complexity bearer \u53CA\u53EF\u89C2\u5BDF\u6210\u672C\uFF1B\u7ED9\u51FA\u4E14\u53EA\u7ED9\u51FA\u4E00\u4E2A recommendation\u3001\u62D2\u7EDD\u5176\u4ED6\u65B9\u5411\u7684\u4E3B\u8981\u7406\u7531\u548C stop conditions\u3002\u7B80\u5355\u4EFB\u52A1\u6CA1\u6709\u771F\u5B9E\u66FF\u4EE3\u65F6\u53EA\u5217\u4E00\u4E2A\u65B9\u5411\u5E76\u8BF4\u660E\u539F\u56E0\uFF0C\u4E0D\u5236\u9020\u4F2A\u9009\u9879\u3002\u4E24\u4E2A\u540C\u7B49 owner \u5019\u9009\u6216 authority writer \u672A\u51B3\u65F6\u8FD4\u56DE \`NEEDS_CLARIFICATION\`\u3002
15345
15409
 
15346
- \u8BA1\u5212\u5FC5\u987B\u542B\u9700\u6C42\u6458\u8981\u3001\u4EFB\u52A1\u5206\u7EA7\u3001\u6280\u672F\u9009\u62E9\u53CA\u7406\u7531\u3001\u6A21\u5757\u7D22\u5F15\u3001\u590D\u7528\u8D44\u6E90\u4E0E scout \u884C\u53F7\u3001\u6838\u5FC3\u884C\u4E3A\u3001\u6700\u5C0F\u7B56\u7565\u3001\u4E0D\u505A\u4EC0\u4E48\u3001\u6B65\u9AA4\u3001\u98CE\u9669/\u56DE\u9000\u3001\u5B8C\u6210\u5B9A\u4E49\u3001\u771F\u5B9E\u9A8C\u8BC1\u4E0E smoke test\u3001\u9884\u4F30\u548C\u975E\u963B\u585E\u9ED8\u8BA4\u503C\u3002\u5165\u53E3/\u6D41\u7A0B\u8DE8\u5E73\u53F0\u4E0D\u4E00\u81F4\u3001owner/source of truth \u4E0D\u6E05\u3001\u72B6\u6001\u6216 contract \u8BED\u4E49\u53D8\u5316\u3001\u8DE8 workflow/child/team/transport\uFF0C\u6216\u8FC1\u79FB/\u517C\u5BB9\u5F71\u54CD\u8D85\u8FC7\u4E00\u4E2A\u7248\u672C\u65F6\uFF0C\u5728 \`plan.md\` \u5185\u52A0\u5165\u53EF\u9009 Domain Matrix\uFF0C\u5217\u51FA Domain\u3001\u5F53\u524D\u884C\u4E3A/\u8BC1\u636E\u3001\u5019\u9009 owner\u3001source of truth\u3001contract/state \u5F71\u54CD\u3001compatibility/history\u3001validation \u548C rollback/stop\uFF1B\u5B83\u4E0D\u662F\u65B0\u7684 authority\u3002\u9996\u6B21\u8BA1\u5212\u5199\u5165\u6210\u529F\u540E\u8FD0\u884C \`mancode workflow update <taskId> --step 4\`\uFF1B\u91CD\u5199\u8BA1\u5212\u65F6\u4FDD\u6301 Step 4\uFF0C\u8FD0\u884C \`--plan-version <\u5F53\u524D\u7248\u672C+1>\`\uFF0C\u4E0D\u5F97\u76F4\u63A5\u7F16\u8F91 planVersion\u3002
15410
+ \u8BA1\u5212\u5FC5\u987B\u542B\u9700\u6C42\u6458\u8981\u3001\u4EFB\u52A1\u5206\u7EA7\u3001\u6280\u672F\u9009\u62E9\u53CA\u7406\u7531\u3001\u6A21\u5757\u7D22\u5F15\u3001\u590D\u7528\u8D44\u6E90\u4E0E scout \u884C\u53F7\u3001\u6838\u5FC3\u884C\u4E3A\u3001\u6700\u5C0F\u7B56\u7565\u3001\u4E0D\u505A\u4EC0\u4E48\u3001\u6B65\u9AA4\u3001\u98CE\u9669/\u56DE\u9000\u3001\u5B8C\u6210\u5B9A\u4E49\u3001\u771F\u5B9E\u9A8C\u8BC1\u4E0E smoke test\u3001\u9884\u4F30\u548C\u975E\u963B\u585E\u9ED8\u8BA4\u503C\uFF0C\u8FD8\u8981\u6709\u7528\u6237\u53EF\u89C1\u7684 \`implementationScope\`\uFF1Arepo-relative \`include\`\u3001\`exclude\`\u3001\`modules\`\u3002include \u662F\u6587\u4EF6\u5199\u5165\u4E0A\u9650\u4E14\u5FC5\u987B\u975E\u7A7A\uFF0Cexclude \u4F18\u5148\uFF0Cmodules \u53EA\u63CF\u8FF0\u5F52\u5C5E\u3001\u4E0D\u5355\u72EC\u6388\u6743\u3002\u6BCF\u4E2A\u5B9E\u65BD\u6B65\u9AA4\u5FC5\u987B\u6620\u5C04\u5230\u5DF2\u786E\u8BA4\u8303\u56F4\u6216\u9A8C\u6536 ID\uFF1B\u4F18\u5148\u590D\u7528\u5DF2\u6709\u4EE3\u7801\u548C\u4F9D\u8D56\uFF0C\u9009\u62E9\u80FD\u6EE1\u8DB3\u9A8C\u6536\u7684\u6700\u5C0F\u3001\u76F4\u63A5\u3001\u53EF\u9A8C\u8BC1\u65B9\u6848\uFF0C\u4E0D\u4E3A\u5355\u6B21\u7528\u9014\u65B0\u589E\u62BD\u8C61\u3001\u53EF\u914D\u7F6E\u6027\u6216\u63A8\u6D4B\u6027\u9632\u5FA1\u3002\u5165\u53E3/\u6D41\u7A0B\u8DE8\u5E73\u53F0\u4E0D\u4E00\u81F4\u3001owner/source of truth \u4E0D\u6E05\u3001\u72B6\u6001\u6216 contract \u8BED\u4E49\u53D8\u5316\u3001\u8DE8 workflow/child/team/transport\uFF0C\u6216\u8FC1\u79FB/\u517C\u5BB9\u5F71\u54CD\u8D85\u8FC7\u4E00\u4E2A\u7248\u672C\u65F6\uFF0C\u5728 \`plan.md\` \u5185\u52A0\u5165\u53EF\u9009 Domain Matrix\uFF0C\u5217\u51FA Domain\u3001\u5F53\u524D\u884C\u4E3A/\u8BC1\u636E\u3001\u5019\u9009 owner\u3001source of truth\u3001contract/state \u5F71\u54CD\u3001compatibility/history\u3001validation \u548C rollback/stop\uFF1B\u5B83\u4E0D\u662F\u65B0\u7684 authority\u3002\u9996\u6B21\u8BA1\u5212\u4E0E\u8FB9\u754C\u901A\u8FC7 CLI \u4E00\u8D77\u5199\u5165\u540E\u8FD0\u884C \`mancode workflow update <taskId> --step 4\`\uFF1B\u517C\u5BB9\u65E7\u5165\u53E3\u91CD\u5199\u8BA1\u5212\u65F6\u4FDD\u6301 Step 4\uFF0C\u4F7F\u7528 \`--plan-version <\u5F53\u524D\u7248\u672C+1>\`\uFF0C\u5E76\u8BA9\u65E7\u5BA1\u67E5/\u9A8C\u8BC1\u5931\u6548\uFF0C\u4E0D\u5F97\u76F4\u63A5\u7F16\u8F91 planVersion\u3002
15347
15411
 
15348
15412
  ### Step 4: \u8BA1\u5212\u5173\u5361
15349
15413
 
@@ -15365,7 +15429,9 @@ Plan Coach \u5FC5\u987B\u8BC1\u660E\u6240\u6709\u9009\u9879\u89E3\u51B3\u540C\u4
15365
15429
 
15366
15430
  ### Step 5: \u5B9E\u65BD
15367
15431
 
15368
- \u8C03\u7528 \`head-coach\` \u6309\u786E\u8BA4\u8BA1\u5212\u5B9E\u65BD\u3002\u591A\u6587\u4EF6\u3001\u65B0\u6A21\u5757\u6216\u9AD8\u98CE\u9669\u4EFB\u52A1\u53EF\u5EFA\u8BAE worktree\uFF0C\u5FC5\u987B\u5148\u83B7\u7528\u6237\u540C\u610F\u3002\u5B9E\u65BD\u5B8C\u6210\u540E\u901A\u8FC7 CLI \u66F4\u65B0\u81F3 Step 6\u3002
15432
+ \u8C03\u7528 \`head-coach\` \u6309\u786E\u8BA4\u8BA1\u5212\u5B9E\u65BD\u3002\u5148\u660E\u786E\u4ECD\u5B58\u5728\u7684\u5B9E\u8D28\u5047\u8BBE\u548C\u53EF\u9A8C\u8BC1\u6210\u529F\u6807\u51C6\uFF1B\u6BCF\u4E00\u5904\u6539\u52A8\u90FD\u5FC5\u987B\u8FFD\u6EAF\u5230\u5DF2\u786E\u8BA4\u8303\u56F4\u3001\u6280\u672F\u51B3\u7B56\u6216\u9A8C\u6536 ID\u3002\u53EA\u6539\u4E3A\u6EE1\u8DB3\u8BA1\u5212\u6240\u5FC5\u9700\u7684\u6587\u4EF6\uFF0C\u4E0D\u987A\u624B\u91CD\u6784\u3001\u683C\u5F0F\u5316\u3001\u6E05\u7406\u76F8\u90BB\u4EE3\u7801\u6216\u589E\u52A0\u672A\u8BF7\u6C42\u529F\u80FD\u3002\u591A\u6587\u4EF6\u3001\u65B0\u6A21\u5757\u6216\u9AD8\u98CE\u9669\u4EFB\u52A1\u53EF\u5EFA\u8BAE worktree\uFF0C\u5FC5\u987B\u5148\u83B7\u7528\u6237\u540C\u610F\u3002\u5B9E\u65BD\u5B8C\u6210\u540E\u901A\u8FC7 CLI \u66F4\u65B0\u81F3 Step 6\u3002
15433
+
15434
+ \u82E5\u5347\u7EA7\u524D\u5DF2\u7ECF\u8FDB\u5165\u6267\u884C\u9636\u6BB5\u7684\u672C\u5730 Man \u4EFB\u52A1\u7F3A\u5C11\u53EF\u6267\u884C \`implementationScope\`\uFF0C\u5B8C\u6210\u95E8\u4ECD\u4F1A\u62D2\u7EDD\u3002\u5148\u5411\u7528\u6237\u5C55\u793A\u5B8C\u6574\u8FB9\u754C\u5E76\u7B49\u5F85\u660E\u786E\u786E\u8BA4\uFF0C\u518D\u4F7F\u7528\u5185\u5BB9\u5B8C\u5168\u4E0D\u53D8\u7684\u5F53\u524D plan \u548C \`--scope-file\` \u91CD\u65B0\u6267\u884C plan revise\u3002\u8FD9\u4E2A\u517C\u5BB9\u8865\u7ED1\u53EA\u5141\u8BB8\u9012\u589E plan authority \u5E76\u4F7F\u65E7 review/verification \u5931\u6548\uFF1B\u4E0D\u5F97\u4FEE\u6539 plan\u3001\u884C\u4E3A\u3001\u9A8C\u6536\u6216\u5DF2\u7ECF\u53EF\u6267\u884C\u7684\u8FB9\u754C\u3002
15369
15435
 
15370
15436
  ### Step 6: \u81EA\u6D4B\u3001\u8BCA\u65AD\u4E0E\u56DE\u5F52
15371
15437
 
@@ -15377,7 +15443,7 @@ Plan Coach \u5FC5\u987B\u8BC1\u660E\u6240\u6709\u9009\u9879\u89E3\u51B3\u540C\u4
15377
15443
 
15378
15444
  ### Step 7: Film #1 \u4EE3\u7801\u8D28\u91CF\u5BA1\u67E5\u4E0E\u4FEE\u590D
15379
15445
 
15380
- \u672A\u8DF3\u8FC7 review \u65F6\u8C03\u7528 \`film-analyst-offense\`\uFF0C\u53EA\u5BA1\u67E5\u672C\u6B21 diff \u7684\u884C\u4E3A\u6B63\u786E\u6027\u3001\u590D\u7528\u3001\u590D\u6742\u5EA6\u548C\u6D4B\u8BD5\uFF0C\u5199 \`film-report-1.md\`\u3002\u6BCF\u6761 finding \u5FC5\u987B\u5F15\u7528\u6539\u52A8\u884C\u3001\u7ED9\u51FA\u8BC1\u636E\u548C\u7528\u6237\u5F71\u54CD\uFF1B\u6700\u591A 3 \u4E2A\u65B0 finding\u3002\u7528\u7A33\u5B9A ID\uFF08\u5982 Q1\uFF09\u6807\u8BB0 \u{1F534} blocker\uFF0C\u5E76\u8FD0\u884C \`mancode workflow review <taskId> complete --review-domain quality --report film-report-1.md --blockers Q1,Q2\`\uFF1B\u6CA1\u6709 blocker \u65F6\u4F20\u7A7A\u5B57\u7B26\u4E32\u3002\u6B64\u65F6\u4E0D\u4FEE\u590D\uFF0C\u5148\u5B8C\u6210\u6240\u9700\u5BA1\u67E5\u9886\u57DF\uFF0C\u518D\u66F4\u65B0\u81F3 Step 8\u3002
15446
+ \u672A\u8DF3\u8FC7 review \u65F6\u8C03\u7528 \`film-analyst-offense\`\uFF0C\u5148\u628A\u5B9E\u9645 diff \u5BF9\u7167 \`confirmedScope\`\u3001\`excludedScope\`\u3001\`technicalDecisions\`\u3001\`acceptanceCriteria\` \u548C \`implementationScope\` \u505A\u6388\u6743\u4E00\u81F4\u6027\u5BA1\u67E5\uFF0C\u518D\u68C0\u67E5\u884C\u4E3A\u6B63\u786E\u6027\u3001\u590D\u7528\u3001\u590D\u6742\u5EA6\u548C\u6D4B\u8BD5\uFF0C\u5199 \`film-report-1.md\`\u3002\u5B9E\u73B0\u88AB\u62D2\u7EDD\u3001\u5EF6\u671F\u3001\u672A\u8BA8\u8BBA\u3001\u65E0\u6CD5\u8FFD\u6EAF\u5230\u5DF2\u786E\u8BA4\u884C\u4E3A\uFF0C\u6216\u6539\u52A8\u8DEF\u5F84\u843D\u5728 include \u5916 / \u5339\u914D exclude \u7684\u5185\u5BB9\u4E00\u5F8B\u4F5C\u4E3A \u{1F534} scope blocker\u3002\u6BCF\u6761 finding \u5FC5\u987B\u5F15\u7528\u6539\u52A8\u884C\u3001\u7ED9\u51FA\u8BC1\u636E\u548C\u7528\u6237\u5F71\u54CD\uFF1B\u6700\u591A 3 \u4E2A\u65B0 finding\u3002\u7528\u7A33\u5B9A ID\uFF08\u5982 Q1\uFF09\u6807\u8BB0 \u{1F534} blocker\uFF0C\u5E76\u8FD0\u884C \`mancode workflow review <taskId> complete --review-domain quality --report film-report-1.md --blockers Q1,Q2\`\uFF1B\u6CA1\u6709 blocker \u65F6\u4F20\u7A7A\u5B57\u7B26\u4E32\u3002\u6B64\u65F6\u4E0D\u4FEE\u590D\uFF0C\u5148\u5B8C\u6210\u6240\u9700\u5BA1\u67E5\u9886\u57DF\uFF0C\u518D\u66F4\u65B0\u81F3 Step 8\u3002
15381
15447
 
15382
15448
  ### Step 8: Film #2 \u5B89\u5168\u4E0E\u8FB9\u754C\u5BA1\u67E5
15383
15449
 
@@ -15711,16 +15777,18 @@ var MANTEAM_SKILL = {
15711
15777
 
15712
15778
  \u6309 \`/man\` \u7684 9 \u6B65\u6D41\u7A0B\u6267\u884C\uFF08\u542B\u6F84\u6E05\u3001\u8BA1\u5212\u5173\u5361\u548C\u589E\u5F3A\u6536\u5C3E\uFF09\uFF0C\u4F46\u6BCF\u4E00\u6B65\u589E\u52A0\u56E2\u961F\u7EA6\u675F\uFF1A
15713
15779
 
15714
- 1. Scout Report\uFF1A\u5FC5\u987B\u5217\u51FA\u5171\u4EAB\u6587\u4EF6\u3001\u8FD1\u671F\u76F8\u5173\u63D0\u4EA4\u3001\u6F5C\u5728\u51B2\u7A81\u6587\u4EF6\uFF0C\u5E76\u6309\u4E8B\u5B9E\u8865\u5145 Current Behavior Evidence\u3001Candidate Semantic Owner\u3001Source of Truth\u3001Historical / Compatibility Impact\uFF1Bauthority \u4E0E Markdown/adapter \u7B49 derived copy \u5FC5\u987B\u533A\u5206\u3002
15715
- 2. \u6F84\u6E05\uFF1A\u6CBF\u7528 /man \u7684\u9700\u6C42\u5C31\u7EEA\u95E8\u69DB\uFF0C\u4E0D\u8BBE\u56FA\u5B9A\u8F6E\u6570\u6216\u6BCF\u6279\u95EE\u9898\u6570\u91CF\uFF1B\u95EE\u51FA\u6240\u6709\u4F1A\u6539\u53D8\u51B3\u7B56\u4E14\u65E0\u6CD5\u4ECE\u9879\u76EE\u4E8B\u5B9E\u67E5\u6E05\u7684\u7591\u95EE\uFF0C\u4E0D\u91CD\u590D\u5DF2\u786E\u8BA4\u5185\u5BB9\u3002\u6709\u5408\u9002\u65B9\u6848\u65F6\u76F4\u63A5\u7ED9\u51FA\u9009\u9879\u3001\u4F18\u7F3A\u70B9\u548C\u660E\u786E\u63A8\u8350\u3002\u901A\u8FC7 \`workflow requirements ... finalize\` \u56FA\u5316\u4E03\u4E2A coverage \u7EF4\u5EA6\u3001\u7ED3\u6784\u5316\u9700\u6C42\u548C\u5E26\u9A8C\u8BC1\u65B9\u5F0F\u7684\u9A8C\u6536 ID\uFF0C\u53EA\u6709 CLI \u5224\u5B9A ready \u624D\u8FDB\u5165\u8BA1\u5212\u3002
15716
- 3. Game Plan\uFF1APlan Coach \u5148\u505A\u8F93\u5165\u5C31\u7EEA\u68C0\u67E5\uFF1B\u6240\u6709\u9009\u9879\u5FC5\u987B\u89E3\u51B3\u540C\u4E00\u76EE\u6807\u548C\u9A8C\u6536\u8FB9\u754C\uFF0C\u5199\u660E complexity bearer\uFF0C\u53EA\u4FDD\u7559\u4E00\u4E2A recommendation \u548C stop conditions\uFF1B\u7B80\u5355\u4EFB\u52A1\u53EF\u4EE5\u53EA\u6709\u4E00\u4E2A\u771F\u5B9E\u65B9\u5411\u3002\u8BA1\u5212\u91CC\u5FC5\u987B\u5305\u542B\u53D8\u66F4\u8FB9\u754C\u3001\u6280\u672F\u9009\u62E9\u7406\u7531\u3001\u517C\u5BB9\u6027\u98CE\u9669\u3001\u56DE\u6EDA\u65B9\u5F0F\uFF1B\u9AD8\u98CE\u9669\u6216\u8DE8 team/transport/owner/authority \u7684\u4EFB\u52A1\u5728 plan.md \u5185\u52A0\u5165\u975E\u6743\u5A01 Domain Matrix\u3002\u7981\u6B62\u63D0\u524D\u4FEE\u6539\u4E1A\u52A1\u6587\u4EF6\u6216\u56E2\u961F memory\u3002
15780
+ 1. Scout Report\uFF1A\u5FC5\u987B\u5217\u51FA\u5171\u4EAB\u6587\u4EF6\u3001\u8FD1\u671F\u76F8\u5173\u63D0\u4EA4\u3001\u6F5C\u5728\u51B2\u7A81\u6587\u4EF6\uFF0C\u5E76\u6309\u4E8B\u5B9E\u8865\u5145 Current Behavior Evidence\u3001Candidate Semantic Owner\u3001Source of Truth\u3001Historical / Compatibility Impact\uFF1Bauthority \u4E0E Markdown/adapter \u7B49 derived copy \u5FC5\u987B\u533A\u5206\u3002\u6700\u591A\u4FDD\u7559\u4E09\u4E2A\u4F1A\u6539\u53D8\u51B3\u7B56\u7684 finding\uFF0C\u4F7F\u7528\u7A33\u5B9A ID F-1\u2026F-3 \u548C Type\uFF1Apremise / scope / technical / risk / acceptance\u3002
15781
+ 2. \u6F84\u6E05\uFF1A\u6CBF\u7528 /man \u7684\u9700\u6C42\u5C31\u7EEA\u95E8\u69DB\uFF0C\u4E0D\u8BBE\u56FA\u5B9A\u8F6E\u6570\u6216\u6BCF\u6279\u95EE\u9898\u6570\u91CF\uFF1B\u95EE\u51FA\u6240\u6709\u4F1A\u6539\u53D8\u51B3\u7B56\u4E14\u65E0\u6CD5\u4ECE\u9879\u76EE\u4E8B\u5B9E\u67E5\u6E05\u7684\u7591\u95EE\uFF0C\u4E0D\u91CD\u590D\u5DF2\u786E\u8BA4\u5185\u5BB9\u3002\u6709\u5408\u9002\u65B9\u6848\u65F6\u76F4\u63A5\u7ED9\u51FA\u9009\u9879\u3001\u4F18\u7F3A\u70B9\u548C\u660E\u786E\u63A8\u8350\u3002\u53D1\u73B0\u53EA\u4EA7\u751F\u5EFA\u8BAE\u6743\uFF0C\u4E0D\u4EA7\u751F\u6267\u884C\u6743\uFF1A\u63A5\u53D7\u7684\u8303\u56F4\u6216\u884C\u4E3A\u8FDB\u5165 confirmedScope \u548C\u5339\u914D\u7684 acceptanceCriteria\uFF1B\u63A5\u53D7\u7684\u6280\u672F\u9009\u62E9\u8FDB\u5165 technicalDecisions\uFF1B\u53EA\u6709\u660E\u786E\u6392\u9664\u7684\u884C\u4E3A\u8FDB\u5165 excludedScope\uFF1B\u672A\u63A5\u53D7\u7684\u5EFA\u8BAE\u4ECD\u65E0\u6267\u884C\u6743\uFF0C\u4F46\u4E0D\u5F97\u81EA\u52A8\u585E\u5165 excludedScope\uFF1B\u4F4E\u5F71\u54CD\u53EF\u9006\u9ED8\u8BA4\u503C\u8FDB\u5165 defaults \u4E14\u4E0D\u5F97\u6269\u5F20\u8303\u56F4\u3002\u901A\u8FC7 \`workflow requirements ... finalize\` \u56FA\u5316\u4E03\u4E2A coverage \u7EF4\u5EA6\u3001\u7ED3\u6784\u5316\u9700\u6C42\u548C\u5E26\u9A8C\u8BC1\u65B9\u5F0F\u7684\u9A8C\u6536 ID\uFF0C\u53EA\u6709 CLI \u5224\u5B9A ready \u624D\u8FDB\u5165\u8BA1\u5212\u3002
15782
+ 3. Game Plan\uFF1APlan Coach \u5148\u505A\u8F93\u5165\u5C31\u7EEA\u68C0\u67E5\uFF1B\u6240\u6709\u9009\u9879\u5FC5\u987B\u89E3\u51B3\u540C\u4E00\u76EE\u6807\u548C\u9A8C\u6536\u8FB9\u754C\uFF0C\u5199\u660E complexity bearer\uFF0C\u53EA\u4FDD\u7559\u4E00\u4E2A recommendation \u548C stop conditions\uFF1B\u7B80\u5355\u4EFB\u52A1\u53EF\u4EE5\u53EA\u6709\u4E00\u4E2A\u771F\u5B9E\u65B9\u5411\u3002\u8BA1\u5212\u91CC\u5FC5\u987B\u5305\u542B\u7528\u6237\u53EF\u89C1\u7684 \`implementationScope\`\uFF08repo-relative include/exclude/modules\uFF09\u3001\u6280\u672F\u9009\u62E9\u7406\u7531\u3001\u517C\u5BB9\u6027\u98CE\u9669\u3001\u56DE\u6EDA\u65B9\u5F0F\uFF1Binclude \u662F\u6587\u4EF6\u5199\u5165\u4E0A\u9650\uFF0Cmodules \u4E0D\u5355\u72EC\u6388\u6743\u3002\u9AD8\u98CE\u9669\u6216\u8DE8 team/transport/owner/authority \u7684\u4EFB\u52A1\u5728 plan.md \u5185\u52A0\u5165\u975E\u6743\u5A01 Domain Matrix\u3002\u7981\u6B62\u63D0\u524D\u4FEE\u6539\u4E1A\u52A1\u6587\u4EF6\u6216\u56E2\u961F memory\u3002
15717
15783
  4. \u8BA1\u5212\u5173\u5361\uFF1A\u7528\u6237\u53EF\u53EA\u4FDD\u7559\u8BA1\u5212\u3001\u7EE7\u7EED\u5B8C\u6574\u56E2\u961F\u6267\u884C\u3001\u660E\u786E\u4EA4\u7ED9 solo \u8F7B\u91CF\u6267\u884C\u6216\u91CD\u5199\u8BA1\u5212\uFF1BActive Plans \u6309 taskId \u66F4\u65B0\u3002\u56E2\u961F\u5171\u4EAB\u6587\u4EF6\u6216\u4EA4\u63A5\u98CE\u9669\u5B58\u5728\u65F6\u63A8\u8350\u5B8C\u6574\u56E2\u961F\u6267\u884C\u3002
15718
15784
  5. \u5B9E\u65BD\uFF1A\u6539\u52A8\u524D\u518D\u6B21\u68C0\u67E5 \`git status --short\`\uFF0C\u907F\u514D\u8E29\u7528\u6237\u6216\u961F\u53CB\u6539\u52A8\u3002
15719
15785
  6. Self-test\uFF1A\u5728 Step 6 \u521D\u59CB\u5316 verification ledger\uFF0C\u628A\u6BCF\u4E2A required \u9A8C\u6536 ID \u7684\u81EA\u52A8\u3001\u4EBA\u5DE5\u6216 hybrid \u7ED3\u679C\u548C\u8BC1\u636E\u901A\u8FC7 CLI \u8BB0\u5F55\uFF1B\u81EA\u52A8\u7ED3\u679C\u5305\u542B\u547D\u4EE4\u4E0E\u9000\u51FA\u7801\uFF0C\u672A\u5168\u90E8\u901A\u8FC7\u4E0D\u5F97\u8FDB\u5165 review\u3002\u4F18\u5148\u8DD1\u9879\u76EE\u5DF2\u6709\u9A8C\u8BC1\u547D\u4EE4\uFF1B\u5931\u8D25\u4E24\u6B21\u505C\u4E0B\u8BCA\u65AD\u6839\u56E0\u3002\u9700\u8981\u4EBA\u5DE5\u9A8C\u8BC1\u65F6\u6807\u8BB0 require-manual \u5E76\u7B49\u5F85\u7528\u6237\u660E\u786E\u786E\u8BA4\uFF0C\u4E0D\u5F97\u81EA\u52A8\u6062\u590D\u3002remediation \u540E\u5728 Step 9 \u91CD\u65B0\u767B\u8BB0\u5168\u90E8\u9A8C\u6536\u3002
15720
- 7. Review scope + Film #1\uFF1A\u57FA\u4E8E\u5B9E\u9645 diff \u5199 \`review-scope.md\`\uFF0C\u7528 \`workflow review ... init\` \u9009\u62E9 targeted \u6216 full\uFF1B\u91CD\u70B9\u5BA1\u67E5\u884C\u4E3A\u3001\u53EF\u7EF4\u62A4\u6027\u3001\u56E2\u961F\u98CE\u683C\u4E0E\u6D4B\u8BD5\uFF0Cfinding \u5FC5\u987B\u6709\u8BC1\u636E\u548C\u7A33\u5B9A ID\u3002
15786
+ 7. Review scope + Film #1\uFF1A\u57FA\u4E8E\u5B9E\u9645 diff \u5199 \`review-scope.md\`\uFF0C\u7528 \`workflow review ... init\` \u9009\u62E9 targeted \u6216 full\uFF1B\u5148\u68C0\u67E5\u6BCF\u4E00\u5904\u6539\u52A8\u662F\u5426\u80FD\u8FFD\u6EAF\u5230\u5DF2\u786E\u8BA4\u8303\u56F4\u4E14\u540C\u65F6\u4F4D\u4E8E \`implementationScope\` include \u5185\u3001\u4E0D\u5339\u914D exclude\uFF0C\u672A\u7ECF\u6388\u6743\u7684\u6539\u52A8\u4F5C\u4E3A blocker\uFF0C\u518D\u5BA1\u67E5\u884C\u4E3A\u3001\u53EF\u7EF4\u62A4\u6027\u3001\u56E2\u961F\u98CE\u683C\u4E0E\u6D4B\u8BD5\uFF1Bfinding \u5FC5\u987B\u6709\u8BC1\u636E\u548C\u7A33\u5B9A ID\u3002
15721
15787
  8. Film #2\uFF1A\u4EC5 full \u6267\u884C\uFF0C\u5148\u8BFB Film #1 \u62A5\u544A\u5E76\u53BB\u91CD\uFF0C\u53EA\u5BA1\u67E5\u8FB9\u754C\u3001\u5B89\u5168\u3001\u6027\u80FD\u3001\u5E76\u53D1\u548C\u517C\u5BB9\u6027\u3002targeted \u7684\u7B2C\u4E8C\u5BA1\u662F\u4E0D\u9002\u7528\uFF0C\u4E0D\u80FD\u8BB0\u4E3A skipped\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8981\u6C42\u624D\u53EF\u8DF3\u8FC7\u5168\u90E8 review\uFF0C\u5E76\u5199\u5165 \`review\` \u548C\u6B8B\u4F59\u98CE\u9669\u3002
15722
15788
  9. Post-game\uFF1A\u6C47\u603B blocker\uFF0C\u53EA\u505A\u4E00\u8F6E\u4FEE\u590D\u5E76\u7528 \`workflow review ... remediate\` \u8BB0\u5F55\uFF1B\u590D\u9A8C\u540E\u5199 summary \u4E0E hand-off\u3002\u9A8C\u8BC1\u5931\u8D25\u3001\u5BA1\u67E5\u4E0D\u5B8C\u6574\u6216\u4ECD\u6709 blocker \u65F6\u6807\u8BB0 blocked\uFF0C\u4E0D\u5F97\u6807 completed\u3002
15723
15789
 
15790
+ \u5B9E\u65BD\u671F\u95F4\u82E5\u53EA\u9700\u8C03\u6574\u6587\u4EF6\u8FB9\u754C\u3001\u4E0D\u6539\u53D8\u5DF2\u786E\u8BA4\u884C\u4E3A\u6216\u9A8C\u6536\uFF0C\u5148\u5411\u7528\u6237\u5C55\u793A\u5B8C\u6574\u65B0\u8FB9\u754C\u5E76\u53D6\u5F97\u660E\u786E\u540C\u610F\uFF0C\u518D\u901A\u8FC7\u4E13\u7528 \`workflow scope change\` mutation \u66F4\u65B0\uFF1B\u5B83\u5FC5\u987B\u9012\u589E plan authority\u3001\u4F7F\u65E7 review/verification \u5931\u6548\u5E76\u91CD\u7B7E\u517C\u5BB9 claim\u3002\u884C\u4E3A\u6216\u9A8C\u6536\u53D8\u5316\u4ECD\u8D70 reframe\uFF0C\u4E0D\u80FD\u7528 scope change \u7ED5\u8FC7\u9700\u6C42\u786E\u8BA4\u3002
15791
+
15724
15792
  \u5B9E\u65BD\u4E2D\u65B0\u8BC1\u636E\u82E5\u63A8\u7FFB\u5DF2\u786E\u8BA4\u7684\u76EE\u6807\u3001owner\u3001source of truth \u6216\u9A8C\u6536\uFF0C\u5165\u53E3/\u6D41\u7A0B\u4F1A\u4EA7\u751F\u4E0D\u540C\u8BED\u4E49\uFF0Cstatus/contract/policy/transition \u542B\u4E49\u8981\u53D8\uFF0C\u53D1\u73B0 stale adapter\u3001writer \u4E0D\u517C\u5BB9\u3001\u672A\u5B8C\u6210 operation\u3001active child/open handoff/active solo assignment\uFF0C\u6216\u53D8\u5316\u8D85\u51FA requirements/plan scope\uFF0C\u7ACB\u5373\u505C\u6B62\uFF0C\u53EA\u8FD4\u56DE \`NEEDS_REALIGNMENT\` \u548C \`MANCODE_REFRAME_REQUIRED\`\u3002\u8FD9\u662F\u53EA\u8BFB\u8BCA\u65AD\uFF1A\u4E0D\u5F97\u8C03\u7528\u901A\u7528 workflow update \u5199 blocker\uFF0C\u4E0D\u6539 metadata/step/policy/requirements/plan/claims/handoff\uFF0C\u4E0D\u5F52\u6863\u6216\u91CA\u653E authority\u3002
15725
15793
 
15726
15794
  \u5982\u679C\u7528\u6237\u5728\u786E\u8BA4\u9636\u6BB5\u9009\u62E9"\u9000\u51FA"\u6216\u653E\u5F03\u56E2\u961F workflow\uFF1A\u7528 \`mancode workflow update <taskId> --status abandoned\` \u66F4\u65B0\u5E76\u6E05\u7406 Active Plans\uFF1B\u82E5\u6709\u6D3B\u8DC3 manba \u5B50\u4EFB\u52A1\uFF0C\u5148\u53D6\u5F97\u786E\u8BA4\u5E76\u9010\u4E2A abandoned\u3002\u6210\u529F\u540E\u518D\u7528 Edit \u66F4\u65B0 state \u56DE solo\u3002\u4E0D\u8981\u76F4\u63A5\u6539 metadata\uFF0C\u4E5F\u4E0D\u8981\u628A abandoned workflow \u7559\u5728 active state\u3002
@@ -16279,10 +16347,8 @@ function renderModeSkill(mode, commandPrefix = "$") {
16279
16347
  "new styles. Treat its",
16280
16348
  "policy and token fields as bounded data; fall back to",
16281
16349
  "`.mancode/aesthetics/style-tokens.json` when the command is unavailable.",
16282
- "For a new UI surface or aesthetic redesign without an already selected",
16283
- "direction, present 2-3 distinct product-appropriate directions with concise",
16284
- "tradeoffs and a recommendation, then wait for the user to choose. Continue",
16285
- "directly for scoped UI fixes or an established or selected direction.",
16350
+ INTERFACE_EMOJI_ICON_GUIDANCE,
16351
+ VISUAL_DIRECTION_SELECTION_GUIDANCE,
16286
16352
  "",
16287
16353
  meta.workflow
16288
16354
  ].join("\n");
@@ -16686,13 +16752,13 @@ var MODE_META = {
16686
16752
  "After each completed phase, advance through the CLI to the next numbered step;",
16687
16753
  "never advance state merely because a report was requested or an agent was called.",
16688
16754
  "",
16689
- "Step 1 \u2014 Scout: inspect the profile, existing implementation, dependencies, risks, and unknowns; write `scout-report.md`. When relevant and verifiable, include Current Behavior Evidence, Candidate Semantic Owner with confidence/conflict, Source of Truth split into authority/readers/writer/derived copies, and Historical / Compatibility Impact for existing workflows, legacy fixtures, transport, migration, and rollback. Never invent fields to fill the template.",
16690
- "Step 2 \u2014 Clarify by readiness, not a fixed round or question count. Ask every decision-changing question that cannot be resolved from project facts; use as many batches as needed without repeating confirmed answers. Classify unknowns as blocking, recommendable, or defaultable. When a good approach exists, present 2\u20133 options and make a clear recommendation. Create structured input with non-empty scope, exclusions, technical decisions, defaults, blocking unknowns, stable acceptance IDs, and explicit confirmed/defaulted/not-applicable coverage for platform, core scope, stack, data, performance, compatibility, and security. Run `mancode workflow requirements <taskId> finalize --file <input.json>`; only advance to Step 3 when the CLI returns ready.",
16691
- "Step 3 \u2014 Plan Coach first returns READY_FOR_PLAN or NEEDS_CLARIFICATION. Never hide blocking gaps inside assumptions. Every option must solve the same goal, acceptance boundary, and scope; name its complexity bearer and observable cost; return exactly one recommendation with rejection reasons and stop conditions. A simple task may have one real direction and must not manufacture alternatives. When ready, write `plan.md` with confirmed scope, technical choices and reasons, reuse, exclusions, behavior, risks/rollback, completion criteria, defaults, and real validation. For cross-platform entry differences, unclear owner/source of truth, contract/state changes, cross-workflow/team/transport work, or multi-version compatibility, add an optional Domain Matrix inside plan.md; it is not authority. First plan is v1; revisions use `--plan-version <current+1>`.",
16755
+ "Step 1 \u2014 Scout: run a bounded, read-only decision-impact discovery; test the user premise against repository evidence, inspect the end-to-end user goal and common domain failure/edge paths, and retain at most three material findings with stable IDs F-1 through F-3 and type premise, scope, technical, risk, or acceptance. Mark each repository_fact or domain_hypothesis; an unverified domain hypothesis becomes a focused question, never a fact. Discovery produces evidence and recommendations, never execution authority. Write `scout-report.md` with the profile, implementation, dependencies, risks, unknowns, and\u2014when verifiable\u2014Current Behavior Evidence, Candidate Semantic Owner with confidence/conflict, Source of Truth split into authority/readers/writer/derived copies, and Historical / Compatibility Impact for existing workflows, legacy fixtures, transport, migration, and rollback. Never invent fields to fill the template.",
16756
+ "Step 2 \u2014 Clarify by readiness, not a fixed round or question count. Ask every decision-changing question that cannot be resolved from project facts; use as many batches as needed without repeating confirmed answers. Classify unknowns as blocking, recommendable, or defaultable. When a good approach exists, present 2\u20133 options and make a clear recommendation. Give every F-ID one type-directed disposition: blocking findings stay in blockingUnknowns; accepted scope or behavior enters confirmedScope plus matching acceptanceCriteria; accepted technical choices enter technicalDecisions; only explicitly excluded behavior enters excludedScope; low-impact reversible details may enter defaults. An unaccepted proposal remains unauthorized and is not copied into every field. Create structured input with non-empty scope, exclusions, technical decisions, defaults, blocking unknowns, stable acceptance IDs, and explicit confirmed/defaulted/not-applicable coverage for platform, core scope, stack, data, performance, compatibility, and security. Run `mancode workflow requirements <taskId> finalize --file <input.json>`; only advance to Step 3 when the CLI returns ready.",
16757
+ "Step 3 \u2014 Plan Coach first returns READY_FOR_PLAN or NEEDS_CLARIFICATION. Never hide blocking gaps inside assumptions. Every option must solve the same goal, acceptance boundary, and scope; name its complexity bearer and observable cost; return exactly one recommendation with rejection reasons and stop conditions. A simple task may have one real direction and must not manufacture alternatives. When ready, write `plan.md` with confirmed scope, technical choices and reasons, reuse, exclusions, behavior, risks/rollback, completion criteria, defaults, and real validation. Add a user-visible implementation scope with non-empty repo-relative include, exclude, and module labels; include is the file-write upper bound, exclude wins, and modules do not authorize files. For cross-platform entry differences, unclear owner/source of truth, contract/state changes, cross-workflow/team/transport work, or multi-version compatibility, add an optional Domain Matrix inside plan.md; it is not authority. First plan is v1; revisions use `--plan-version <current+1>`.",
16692
16758
  "Step 4 \u2014 Plan gate: recommend based on risk and let the user choose (1) hand the confirmed plan to lightweight solo via `mancode workflow handoff <taskId> --to solo`, (2) continue full governed execution via `mancode workflow decide <taskId> --plan-decision governed_execution` before Step 5, (3) keep the plan only via `mancode workflow decide <taskId> --plan-decision plan_only`, or (4) revise. Do not implement before this choice. Before either execution path, echo the plan version, delivery, stack, inclusions, exclusions, validation, and residual assumptions.",
16693
- "Step 5 \u2014 Implement the confirmed minimum change.",
16759
+ "Step 5 \u2014 State material assumptions and verifiable success criteria, then implement the smallest direct change inside both the confirmed plan and implementation scope. Reuse existing code and dependencies; do not add speculative features, one-off abstractions, configurability, adjacent cleanup, or unrelated defenses. A newly discovered out-of-scope need authorizes only NEEDS_REALIGNMENT until the user approves reframe. If an upgraded already-running local man task has no executable scope, show the complete boundary and wait for explicit approval, then rerun plan revise with the exact unchanged current plan plus --scope-file; this compatibility bind stales old evidence and cannot change behavior or an already executable boundary.",
16694
16760
  "Step 6 \u2014 Run `workflow verify <taskId> init`, execute detected build/lint/typecheck/test and smoke checks, and record every required acceptance ID with reproducible evidence; automated passed/failed records include the command and exit code. Use require-manual when a foreground browser, device, or human judgment is necessary; stop for explicit user confirmation before confirm-manual. The CLI blocks Step 7 and review until all checks pass. Then write `review-scope.md` and initialize targeted or full review. An explicit user review skip uses `workflow review <taskId> skip --reason <reason>` at Step 6, never generic skipped metadata.",
16695
- "Step 7 \u2014 Run one quality review limited to the changed diff and direct impact. Findings require changed-line evidence and user impact, with at most three new findings. Record stable blocker IDs through `workflow review ... complete`; do not fix yet.",
16761
+ "Step 7 \u2014 Run one quality review limited to the changed diff and direct impact. Compare every changed path and behavior with confirmed requirements, acceptance IDs, and implementation scope; any unauthorized behavior, path outside include, or path matching exclude is a blocker. Findings require changed-line evidence and user impact, with at most three new findings. Record stable blocker IDs through `workflow review ... complete`; do not fix yet.",
16696
16762
  "Step 8 \u2014 Only full review runs the security/boundary reviewer. It must read Film #1, mark the same root cause duplicate, and stay within security, permissions, recovery, resources, and boundaries. A targeted review treats the second domain as not applicable; it is never recorded as a skipped step.",
16697
16763
  "Step 9 \u2014 If open blockers exist, fix them in one remediation round and record resolved IDs through `workflow review ... remediate`; remediation invalidates all earlier acceptance evidence, so re-run and re-record every required check at Step 9 without re-running completed reviewers. Write `summary.md` and set completed only when verification and required review domains are complete and blockers are zero.",
16698
16764
  "",
@@ -16712,6 +16778,10 @@ var MODE_META = {
16712
16778
  "and currentWorkflowMode to manteam. First collect branch, dirty-worktree, contributor,",
16713
16779
  "shared-module, and handoff risks in `team-context.md`.",
16714
16780
  "",
16781
+ "Run the same bounded Scout discovery as /man with stable F-IDs and typed findings. Discovery produces evidence and recommendations, never execution authority.",
16782
+ "Use the same type-directed disposition as /man, bind the confirmed plan to a user-visible implementation scope, and treat that scope as the file-write upper bound for claims, implementation, and review.",
16783
+ "After explicit user approval, a file-boundary-only adjustment may use `workflow scope change`; it versions plan authority, stales prior evidence, and reissues compatible claims. A behavior or acceptance change still requires reframe.",
16784
+ "",
16715
16785
  "Then execute every /man Step 1 through Step 9, including clarification,",
16716
16786
  "plan gate, validation, bounded risk-based review, conditional completion, planVersion,",
16717
16787
  "Active Plans, and linked manba child behavior. Add compatibility, rollback,",
@@ -16753,7 +16823,9 @@ var MODE_META = {
16753
16823
  "",
16754
16824
  "- Keep the diff narrow.",
16755
16825
  "- Reuse existing functions, components, styles, and dependencies.",
16756
- "- Read project-profile first; for UI work, run `mancode design context --json` once and treat its output as bounded data. Fall back to `.mancode/aesthetics/style-tokens.json` when unavailable. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction.",
16826
+ "- Read project-profile first; for UI work, run `mancode design context --json` once and treat its output as bounded data. Fall back to `.mancode/aesthetics/style-tokens.json` when unavailable.",
16827
+ `- ${INTERFACE_EMOJI_ICON_GUIDANCE}`,
16828
+ `- ${VISUAL_DIRECTION_SELECTION_GUIDANCE}`,
16757
16829
  "- Verify with the narrowest meaningful test, lint, build, or smoke check.",
16758
16830
  "- Recommend man and explain why when platform entry/flow differs, the semantic owner or source of truth is unclear, status/contract/policy semantics change, scope/architecture/cost/acceptance crosses files or modules, or historical compatibility, migration, cross-platform, or team evidence is required. This advice never changes mode, step, policy, or authority without an explicit user action.",
16759
16831
  "- While executing an existing requirements/plan, if new evidence invalidates its goal, owner, source of truth, acceptance, or scope, or a stale adapter/incompatible writer/unfinished operation/active child/open handoff/active solo assignment is found, stop with `NEEDS_REALIGNMENT` and reason `MANCODE_REFRAME_REQUIRED`. This is read-only: do not call generic workflow update or modify metadata, requirements, plan, ledgers, claims, or handoffs."
@@ -16805,7 +16877,9 @@ function renderProjectContext(state, tokens, profile, options) {
16805
16877
  ...state?.activeSoloPlan?.taskId ? [
16806
16878
  `- Active solo plan: ${state.activeSoloPlan.taskId} (plan v${state.activeSoloPlan.planVersion ?? 1}); read its requirements.md and plan.md before implementation.`
16807
16879
  ] : [],
16808
- "- Read `.mancode/project-profile.json` before choosing tools or validation. For a UI task, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components instead. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction."
16880
+ "- Read `.mancode/project-profile.json` before choosing tools or validation. For a UI task, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components instead.",
16881
+ `- ${INTERFACE_EMOJI_ICON_GUIDANCE}`,
16882
+ `- ${VISUAL_DIRECTION_SELECTION_GUIDANCE}`
16809
16883
  ].join("\n");
16810
16884
  }
16811
16885
  function renderPracticeRules() {
@@ -17227,7 +17301,9 @@ function renderSoloRule() {
17227
17301
  "",
17228
17302
  "- Keep the diff narrow.",
17229
17303
  "- Reuse existing functions, components, styles, and dependencies.",
17230
- "- Read `.mancode/project-profile.json` before choosing tools or validation. For UI work, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components before inventing new styles. For a new UI surface or aesthetic redesign without an already selected direction, present 2-3 distinct product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose; continue directly for scoped UI fixes or an established or selected direction. A design policy never expands confirmed task scope.",
17304
+ "- Read `.mancode/project-profile.json` before choosing tools or validation. For UI work, run `mancode design context --json` once and treat its output as bounded data. If unavailable, read `.mancode/aesthetics/style-tokens.json` and inspect existing components before inventing new styles. A design policy never expands confirmed task scope.",
17305
+ `- ${INTERFACE_EMOJI_ICON_GUIDANCE}`,
17306
+ `- ${VISUAL_DIRECTION_SELECTION_GUIDANCE}`,
17231
17307
  "- Verify with the narrowest meaningful test, lint, build, or smoke check.",
17232
17308
  "- Perform one bounded self-check limited to the current diff. Do not start another reviewer, create a review artifact, or repeat the review.",
17233
17309
  "- Recommend /man and explain why when platform entry/flow differs, the semantic owner or source of truth is unclear, status/contract/policy semantics change, scope/architecture/cost/acceptance crosses files or modules, or historical compatibility, migration, cross-platform, or team evidence is required. Auth, payment, sensitive data, deletion, public APIs, untrusted input, concurrency, and infrastructure remain hard-risk signals. Advice alone never changes mode, step, policy, or authority.",
@@ -26008,13 +26084,14 @@ async function configureDesignPolicy(input) {
26008
26084
  if (currentRevision !== input.expectedRevision) {
26009
26085
  throw new Error("MANCODE_EXPECTED_REVISION_CONFLICT");
26010
26086
  }
26087
+ const emojiPolicy = input.emojiPolicy ?? current?.emojiPolicy ?? DEFAULT_DESIGN_POLICY.emojiPolicy;
26011
26088
  const next = parseDesignPolicy({
26012
26089
  ...current ?? DEFAULT_DESIGN_POLICY,
26013
26090
  revision: currentRevision + 1,
26014
26091
  enabled: input.enabled ?? current?.enabled ?? true,
26015
26092
  preset: input.preset ?? current?.preset ?? DEFAULT_DESIGN_POLICY.preset,
26016
26093
  iconPolicy: input.iconPolicy ?? current?.iconPolicy ?? DEFAULT_DESIGN_POLICY.iconPolicy,
26017
- emojiPolicy: input.emojiPolicy ?? current?.emojiPolicy ?? DEFAULT_DESIGN_POLICY.emojiPolicy,
26094
+ emojiPolicy: emojiPolicy === "allow" ? "forbid-as-interface-icon" : emojiPolicy,
26018
26095
  motionPolicy: input.motionPolicy ?? current?.motionPolicy ?? DEFAULT_DESIGN_POLICY.motionPolicy,
26019
26096
  browserValidation: input.browserValidation ?? current?.browserValidation ?? DEFAULT_DESIGN_POLICY.browserValidation,
26020
26097
  lastOperationId: operationId,
@@ -26134,12 +26211,14 @@ async function designStatus(rootDir = process2.cwd(), options = {}) {
26134
26211
  policyStatus: policyResult.status,
26135
26212
  policy: policyResult.policy,
26136
26213
  effectivePreset: policyResult.policy?.enabled === true ? policyResult.policy.preset : "preserve",
26214
+ effectiveEmojiPolicy: "forbid-as-interface-icon",
26137
26215
  policyPath: relativePath(rootDir, designPolicyPath(rootDir)),
26138
- warning: policyResult.warning
26216
+ warning: effectivePolicyWarning(policyResult.policy, policyResult.warning)
26139
26217
  };
26140
26218
  return printResult(options.json, payload, [
26141
26219
  `Design policy: ${payload.policyStatus}`,
26142
26220
  `Effective preset: ${payload.effectivePreset}`,
26221
+ `Effective emoji policy: ${payload.effectiveEmojiPolicy}`,
26143
26222
  `Revision: ${payload.policy?.revision ?? 0}`,
26144
26223
  ...payload.warning === null ? [] : [`Warning: ${payload.warning}`]
26145
26224
  ]);
@@ -26162,7 +26241,7 @@ async function designContext(rootDir = process2.cwd(), options = {}) {
26162
26241
  ]);
26163
26242
  const configured = policyResult.policy;
26164
26243
  const active = configured?.enabled === true;
26165
- const policy = active ? configured : disabledPolicy();
26244
+ const policy = effectivePolicy(active ? configured : disabledPolicy());
26166
26245
  const rootUiDetected = profile?.uiAssets === "detected";
26167
26246
  const scopedUiDetected = style.scopeRoot !== "." && style.lastScanned !== null;
26168
26247
  const applicable = rootUiDetected || scopedUiDetected;
@@ -26185,10 +26264,16 @@ async function designContext(rootDir = process2.cwd(), options = {}) {
26185
26264
  doNotExpandTaskScope: true,
26186
26265
  reuseExistingDesignSystem: true,
26187
26266
  dependencyChangesRequireTaskApproval: true,
26188
- experimentalDoesNotAuthorizeProductChanges: true
26267
+ experimentalDoesNotAuthorizeProductChanges: true,
26268
+ interfaceEmojiIconsForbidden: true,
26269
+ contentEmojiAllowed: true,
26270
+ iconFallbackMustNotBeEmoji: true
26189
26271
  } : {
26190
26272
  doNotExpandTaskScope: true,
26191
- reuseExistingDesignSystem: true
26273
+ reuseExistingDesignSystem: true,
26274
+ interfaceEmojiIconsForbidden: true,
26275
+ contentEmojiAllowed: true,
26276
+ iconFallbackMustNotBeEmoji: true
26192
26277
  },
26193
26278
  project: {
26194
26279
  kind: profile?.projectKind ?? "unknown",
@@ -26198,7 +26283,7 @@ async function designContext(rootDir = process2.cwd(), options = {}) {
26198
26283
  guidance: designGuidance(policy),
26199
26284
  qualityGates: designQualityGates(policy),
26200
26285
  style,
26201
- warning: policyResult.warning
26286
+ warning: effectivePolicyWarning(configured, policyResult.warning)
26202
26287
  };
26203
26288
  return printResult(options.json, payload, [
26204
26289
  `Applicable: ${payload.applicable ? "yes" : "no"}`,
@@ -26237,6 +26322,7 @@ async function designConfigure(rootDir, options) {
26237
26322
  );
26238
26323
  }
26239
26324
  try {
26325
+ const legacyEmojiAllow = options.emoji === "allow";
26240
26326
  const result2 = await configureDesignPolicy({
26241
26327
  projectRoot: rootDir,
26242
26328
  expectedRevision,
@@ -26244,9 +26330,11 @@ async function designConfigure(rootDir, options) {
26244
26330
  confirmExperimental: options.confirmExperimental,
26245
26331
  ...values
26246
26332
  });
26247
- return printResult(options.json, { schemaVersion: 1, ...result2 }, [
26333
+ const warning = legacyEmojiAllow ? "--emoji allow is deprecated and was normalized to forbid-as-interface-icon; emoji remains allowed in user-authored content, chat messages, editorial copy, and domain data." : null;
26334
+ return printResult(options.json, { schemaVersion: 1, ...result2, warning }, [
26248
26335
  `Design policy configured: ${result2.policy.preset}`,
26249
- `Revision: ${result2.policy.revision}`
26336
+ `Revision: ${result2.policy.revision}`,
26337
+ ...warning === null ? [] : [`Warning: ${warning}`]
26250
26338
  ]);
26251
26339
  } catch (error) {
26252
26340
  const code = errorCode3(error, "MANCODE_DESIGN_CONFIGURE_FAILED");
@@ -26304,7 +26392,7 @@ function parseConfigureValues(options) {
26304
26392
  return {
26305
26393
  preset: options.preset,
26306
26394
  iconPolicy: options.icons,
26307
- emojiPolicy: options.emoji,
26395
+ emojiPolicy: options.emoji === "allow" ? "forbid-as-interface-icon" : options.emoji,
26308
26396
  motionPolicy: options.motion,
26309
26397
  browserValidation: options.browserValidation
26310
26398
  };
@@ -26389,22 +26477,28 @@ async function styleFreshness(rootDir, scopeRoot, lastScanned, sourceFiles) {
26389
26477
  function disabledPolicy() {
26390
26478
  return {
26391
26479
  ...DEFAULT_DESIGN_POLICY,
26392
- emojiPolicy: "allow",
26393
26480
  motionPolicy: "minimal",
26394
26481
  browserValidation: "off"
26395
26482
  };
26396
26483
  }
26484
+ function effectivePolicy(policy) {
26485
+ return policy.emojiPolicy === "forbid-as-interface-icon" ? policy : { ...policy, emojiPolicy: "forbid-as-interface-icon" };
26486
+ }
26487
+ function effectivePolicyWarning(policy, warning) {
26488
+ const legacyWarning = policy?.emojiPolicy === "allow" ? 'The legacy emoji policy "allow" is constrained to forbid-as-interface-icon; emoji remains allowed in user-authored content, chat messages, editorial copy, and domain data.' : null;
26489
+ return [warning, legacyWarning].filter(Boolean).join(" ") || null;
26490
+ }
26397
26491
  function designGuidance(policy) {
26398
26492
  return [
26399
26493
  directionSelectionGuidance(),
26400
26494
  presetGuidance(policy.preset),
26401
26495
  iconGuidance(policy.iconPolicy),
26402
- emojiGuidance(policy.emojiPolicy),
26496
+ emojiGuidance(),
26403
26497
  motionGuidance(policy.motionPolicy)
26404
26498
  ];
26405
26499
  }
26406
26500
  function directionSelectionGuidance() {
26407
- return "Before implementing a new UI surface or an aesthetic redesign when the user has not chosen a visual direction, present 2-3 distinct, product-appropriate directions with concise tradeoffs and a recommendation, then wait for the user to choose. Continue directly for scoped UI fixes or work within an established or already selected direction.";
26501
+ return VISUAL_DIRECTION_SELECTION_GUIDANCE;
26408
26502
  }
26409
26503
  function presetGuidance(preset) {
26410
26504
  if (preset === "refine") {
@@ -26418,8 +26512,8 @@ function presetGuidance(preset) {
26418
26512
  function iconGuidance(policy) {
26419
26513
  return policy === "lucide" ? "Use Lucide for interface icons when it is already available; adding or replacing a dependency requires explicit task approval." : "Reuse the project's existing icon system; do not introduce another icon library without explicit task approval.";
26420
26514
  }
26421
- function emojiGuidance(policy) {
26422
- return policy === "forbid-as-interface-icon" ? "Do not use emoji as interface icons." : "Follow the existing product conventions for emoji.";
26515
+ function emojiGuidance() {
26516
+ return INTERFACE_EMOJI_ICON_GUIDANCE.replace("Never use", "Do not use");
26423
26517
  }
26424
26518
  function motionGuidance(policy) {
26425
26519
  return policy === "purposeful" ? "Use motion only to clarify hierarchy, state changes, or spatial relationships, and preserve reduced-motion accessibility." : "Keep motion minimal and preserve reduced-motion accessibility.";
@@ -26429,6 +26523,7 @@ function designQualityGates(policy) {
26429
26523
  return [
26430
26524
  "Preserve task-critical workflows, keyboard access, visible focus, readable contrast, and responsive behavior on changed surfaces.",
26431
26525
  "Check changed surfaces for clipping, unintended overlap, horizontal overflow, and unstable layout.",
26526
+ "Inspect changed navigation, buttons, controls, actions, and status indicators to confirm that no emoji is used as an interface icon; do not flag emoji in user-authored content, chat messages, editorial copy, or domain data.",
26432
26527
  browserGate
26433
26528
  ];
26434
26529
  }
@@ -41775,311 +41870,41 @@ function assertPositiveRevision6(value, label) {
41775
41870
  }
41776
41871
  }
41777
41872
 
41778
- // src/context/plan-revision.ts
41779
- async function reviseV3Plan(input) {
41873
+ // src/context/scope-change.ts
41874
+ import { createHash as createHash11 } from "crypto";
41875
+ async function changeV3WorkflowScope(input) {
41780
41876
  const taskRef = parseTaskRefValue(input.taskRef);
41781
- const plan = requirePlan(input.plan);
41782
- const planDecision = parsePlanDecision(input.planDecision);
41783
- if (taskRef.namespace === "shared") {
41784
- assertSharedTextSafe(plan, "plan");
41785
- }
41786
- const context = await openV3TaskOperation({
41787
- projectRoot: input.projectRoot,
41788
- taskRef,
41789
- sessionId: input.sessionId,
41790
- expectedTaskRevision: input.expectedTaskRevision,
41791
- operationId: input.operationId,
41792
- extraEntityLocks: taskRef.namespace === "shared" ? [taskHeadEntityKey(taskRef)] : [],
41793
- now: input.now
41794
- });
41795
- let journal = null;
41796
- try {
41797
- assertPlanRevisionEligible(
41798
- context.task.metadata,
41799
- context.task.requirements
41800
- );
41801
- if (context.task.metadata.workflowMode === "manteam" && planDecision === "governed_execution") {
41802
- assertManteamPlanContent(plan);
41803
- }
41804
- if (context.task.plan?.content === plan && planDecision === null) {
41805
- throw new Error("MANCODE_PLAN_CONTENT_UNCHANGED");
41806
- }
41807
- const planChanged = context.task.plan?.content !== plan;
41808
- const timestamp4 = context.now.toISOString();
41809
- const planDigest = planChanged ? digestCanonicalJson({
41810
- artifactRef: { taskRef, kind: "plan" },
41811
- content: plan
41812
- }) : context.task.plan?.digest;
41813
- if (planDigest === void 0) {
41814
- throw new Error("MANCODE_PLAN_FILE_REQUIRED");
41815
- }
41816
- const review = planChanged ? markTaskReviewStale(context.task.review, context.operationId, timestamp4) : context.task.review;
41817
- const verification = planChanged ? markTaskVerificationStale(
41818
- context.task.verification,
41819
- context.operationId,
41820
- timestamp4
41821
- ) : context.task.verification;
41822
- const metadata = updateMetadata(
41823
- context.task.metadata,
41824
- context.task.requirements,
41825
- review,
41826
- verification,
41827
- planChanged,
41828
- planDecision,
41829
- context.operationId,
41830
- timestamp4
41831
- );
41832
- const aggregate = buildTaskAggregateManifest({
41833
- metadata,
41834
- requirements: context.task.requirements,
41835
- review,
41836
- verification,
41837
- planDigest,
41838
- latestCheckpoint: context.task.latestCheckpoint
41839
- });
41840
- const taskHeadFence = nextTaskHeadFence(context, aggregate, timestamp4);
41841
- if (planDecision === "plan_only") {
41842
- await enqueueSessionPointerProjection(context.projectRoot, {
41843
- operationId: context.operationId,
41844
- action: "clear",
41845
- sessionId: context.session.sessionId,
41846
- expectedPreviousTaskRef: context.session.activeTaskRef,
41847
- taskRef,
41848
- workflowMode: metadata.workflowMode,
41849
- taskRevision: metadata.revision,
41850
- now: context.now
41851
- });
41852
- }
41853
- journal = await createTaskOperationJournal(context, {
41854
- type: "plan_revision",
41855
- action: taskRef.namespace === "shared" ? "shared_metadata_plan_mutation" : "local_workflow_mutation",
41856
- expectedRevisions: taskMutationExpectedRevisions(context, [
41857
- "plan",
41858
- "review",
41859
- "verification"
41860
- ]),
41861
- recovery: {
41862
- actions: [
41863
- ...planChanged ? [
41864
- createTaskAuthorityFileRecoveryAction({
41865
- stepId: "write-plan",
41866
- taskRef,
41867
- fileName: "plan.md",
41868
- beforeContent: context.task.plan?.content ?? null,
41869
- targetContent: plan
41870
- })
41871
- ] : [],
41872
- createTaskAuthorityFileRecoveryAction({
41873
- stepId: "update-metadata",
41874
- taskRef,
41875
- fileName: "metadata.json",
41876
- beforeContent: serializeTaskAuthority(context.task.metadata),
41877
- targetContent: serializeTaskAuthority(metadata)
41878
- }),
41879
- ...planChanged ? [
41880
- createTaskAuthorityFileRecoveryAction({
41881
- stepId: "mark-review-verification-stale",
41882
- taskRef,
41883
- fileName: "review-ledger.json",
41884
- beforeContent: serializeTaskAuthority(context.task.review),
41885
- targetContent: serializeTaskAuthority(review)
41886
- }),
41887
- createTaskAuthorityFileRecoveryAction({
41888
- stepId: "mark-review-verification-stale",
41889
- taskRef,
41890
- fileName: "verification-ledger.json",
41891
- beforeContent: serializeTaskAuthority(
41892
- context.task.verification
41893
- ),
41894
- targetContent: serializeTaskAuthority(verification)
41895
- })
41896
- ] : [],
41897
- ...taskHeadFence === null ? [] : [
41898
- createTaskHeadFenceRecoveryAction({
41899
- stepId: "update-task-head-fence",
41900
- before: context.coordination.taskHeadFence,
41901
- fence: taskHeadFence
41902
- })
41903
- ]
41904
- ],
41905
- noOpStepIds: [
41906
- ...planChanged ? [] : ["write-plan", "mark-review-verification-stale"],
41907
- ...taskHeadFence === null ? ["update-task-head-fence"] : []
41908
- ]
41909
- }
41910
- });
41911
- journal = await advanceTaskOperation(context, journal, "validate", true);
41912
- journal = await advanceTaskOperation(context, journal, "write-plan", false);
41913
- if (planChanged) {
41914
- await writeTaskAuthorityFile(context, "plan.md", plan);
41915
- }
41916
- journal = await advanceTaskOperation(
41917
- context,
41918
- journal,
41919
- "update-metadata",
41920
- false
41921
- );
41922
- await writeTaskAuthorityFile(
41923
- context,
41924
- "metadata.json",
41925
- `${JSON.stringify(metadata, null, 2)}
41926
- `
41927
- );
41928
- journal = await advanceTaskOperation(
41929
- context,
41930
- journal,
41931
- "mark-review-verification-stale",
41932
- false
41933
- );
41934
- if (planChanged) {
41935
- await writeTaskAuthorityFile(
41936
- context,
41937
- "review-ledger.json",
41938
- `${JSON.stringify(review, null, 2)}
41939
- `
41940
- );
41941
- await writeTaskAuthorityFile(
41942
- context,
41943
- "verification-ledger.json",
41944
- `${JSON.stringify(verification, null, 2)}
41945
- `
41946
- );
41947
- }
41948
- journal = await advanceTaskOperation(
41949
- context,
41950
- journal,
41951
- "update-task-head-fence",
41952
- false
41953
- );
41954
- if (taskHeadFence !== null) {
41955
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
41956
- await replaceTaskHeadFence(context.homeStore, taskHeadFence);
41957
- }
41958
- const operation = await commitTaskOperation(context, journal);
41959
- if (planDecision === "plan_only") {
41960
- try {
41961
- await reconcileProjectionIntents(
41962
- context.projectRoot,
41963
- context.operationId,
41964
- context.now
41965
- );
41966
- } catch {
41967
- }
41968
- }
41969
- return {
41970
- metadata,
41971
- review,
41972
- verification,
41973
- planDigest,
41974
- aggregate,
41975
- taskHeadFence,
41976
- operation
41977
- };
41978
- } catch (error) {
41979
- if (journal !== null) {
41980
- try {
41981
- await handleTaskOperationFailure(context, journal);
41982
- } catch {
41983
- }
41984
- }
41985
- throw error;
41986
- } finally {
41987
- await context.release();
41988
- }
41989
- }
41990
- function requirePlan(value) {
41991
- if (typeof value !== "string" || !value.trim() || value.includes("\0")) {
41992
- throw new Error("MANCODE_PLAN_CONTENT_REQUIRED");
41993
- }
41994
- return value;
41995
- }
41996
- function parsePlanDecision(value) {
41997
- if (value === void 0) return null;
41998
- if (value !== "plan_only" && value !== "governed_execution") {
41999
- throw new Error("MANCODE_PLAN_DECISION_INVALID");
42000
- }
42001
- return value;
42002
- }
42003
- function assertPlanRevisionEligible(metadata, requirements) {
42004
- if (metadata.workflowMode !== "man" && metadata.workflowMode !== "manteam") {
42005
- throw new Error("MANCODE_PLAN_WORKFLOW_MODE_INVALID");
42006
- }
42007
- if (metadata.status !== "in_progress") {
42008
- throw new Error("MANCODE_PLAN_WORKFLOW_NOT_ACTIVE");
42009
- }
42010
- if (metadata.currentStep < 2 || metadata.currentStep > 4) {
42011
- throw new Error("MANCODE_PLAN_STEP_INVALID");
42012
- }
42013
- if (metadata.governance.planDecision !== null || metadata.governance.requirementsStatus !== "ready" || metadata.governance.requirementsDigest !== requirements.contentDigest || requirements.status !== "confirmed" || !requirementsAreReady(requirements)) {
42014
- throw new Error("MANCODE_PLAN_REQUIREMENTS_OR_DECISION_INVALID");
41877
+ if (taskRef.namespace !== "shared") {
41878
+ throw new Error("MANCODE_SCOPE_CHANGE_REQUIRES_SHARED_TASK");
42015
41879
  }
42016
- }
42017
- function updateMetadata(previous, requirements, review, verification, planChanged, planDecision, operationId, updatedAt) {
42018
- const status2 = planDecision === "plan_only" ? "planned" : "in_progress";
42019
- const currentStep = planDecision === "governed_execution" ? 5 : 4;
42020
- const next = parseWorkflowMetadata({
42021
- ...previous,
42022
- status: status2,
42023
- currentStep,
42024
- revision: previous.revision + 1,
42025
- transitionState: "stable",
42026
- lastOperationId: operationId,
42027
- governance: {
42028
- ...previous.governance,
42029
- requirementsStatus: "ready",
42030
- requirementsDigest: requirements.contentDigest,
42031
- planVersion: previous.governance.planVersion + (planChanged ? 1 : 0),
42032
- planDecision,
42033
- reviewStatus: planChanged ? "stale" : previous.governance.reviewStatus,
42034
- reviewLedgerDigest: review.contentDigest,
42035
- verificationStatus: planChanged ? "stale" : previous.governance.verificationStatus,
42036
- verificationLedgerDigest: verification.contentDigest
42037
- },
42038
- updatedAt
42039
- });
42040
- assertWorkflowMetadataTransition(previous, next, "ordinary");
42041
- return next;
42042
- }
42043
-
42044
- // src/context/reframe.ts
42045
- async function reframeV3Workflow(input) {
42046
- const taskRef = parseTaskRefValue(input.taskRef);
42047
- assertUlid(input.checkpointId, "reframe checkpointId");
41880
+ const scope = normalizeImplementationScope(input.scope);
42048
41881
  const now = input.now ?? /* @__PURE__ */ new Date();
41882
+ const timestamp4 = now.toISOString();
41883
+ const checkpointId = input.checkpointId ?? createUlid(now.getTime());
42049
41884
  const operationId = input.operationId ?? createUlid(now.getTime());
42050
- assertUlid(operationId, "reframe operationId");
42051
- const opened = await openReframeContext({
41885
+ assertUlid(checkpointId, "scope change checkpointId");
41886
+ assertUlid(operationId, "scope change operationId");
41887
+ const opened = await openScopeChangeContext({
42052
41888
  projectRoot: input.projectRoot,
42053
41889
  taskRef,
42054
41890
  sessionId: input.sessionId,
42055
41891
  expectedTaskRevision: input.expectedTaskRevision,
42056
- checkpointId: input.checkpointId,
41892
+ scope,
41893
+ checkpointId,
41894
+ successorClaimIds: input.successorClaimIds,
42057
41895
  operationId,
42058
41896
  now
42059
41897
  });
42060
- const { context, activeClaims: activeClaims2, openHandoffs, activeChildren } = opened;
41898
+ const { context, activeClaims: activeClaims2, successorClaimIds, successorPredecessors } = opened;
42061
41899
  let journal = null;
42062
41900
  try {
42063
- assertReframeEligible(context, activeClaims2, openHandoffs, activeChildren);
42064
- assertReframeClaimsFresh(context, activeClaims2);
42065
- const timestamp4 = context.now.toISOString();
42066
- const archivedRequirementsContent = await readTaskAuthorityFileAtRoot(
42067
- context.task.location.taskRoot,
42068
- "requirements.json"
42069
- );
42070
- if (archivedRequirementsContent === null) {
42071
- throw new Error("MANCODE_REFRAME_REQUIREMENTS_MISSING");
42072
- }
42073
- const pendingMetadata = markReframeOperationPending(
41901
+ assertScopeChangeEligible(context, scope);
41902
+ assertClaimsFreshForScopeChange(context, activeClaims2);
41903
+ const pendingMetadata = markScopeChangeOperationPending(
42074
41904
  context.task.metadata,
42075
41905
  context.operationId,
42076
41906
  timestamp4
42077
41907
  );
42078
- const requirements = createReframedRequirements(
42079
- context.task.requirements,
42080
- context.operationId,
42081
- timestamp4
42082
- );
42083
41908
  const review = markTaskReviewStale(
42084
41909
  context.task.review,
42085
41910
  context.operationId,
@@ -42090,71 +41915,80 @@ async function reframeV3Workflow(input) {
42090
41915
  context.operationId,
42091
41916
  timestamp4
42092
41917
  );
42093
- const releasedClaims = activeClaims2.map(
42094
- (claim) => releaseClaimForReframe(claim, context.operationId, timestamp4)
42095
- );
42096
- const archiveAction = createTaskArchiveRecoveryAction({
42097
- stepId: "archive-requirements-plan",
42098
- taskRef,
42099
- archiveId: context.operationId,
42100
- sourceTaskRevision: context.task.metadata.revision,
42101
- sourcePlanVersion: context.task.metadata.governance.planVersion,
42102
- createdAt: timestamp4,
42103
- requirementsContent: archivedRequirementsContent,
42104
- planContent: context.task.plan?.content ?? null
42105
- });
42106
- const branch = await readCheckoutBranch(context.projectRoot);
42107
- const checkpoint = buildReframeCheckpoint({
41918
+ const branch = await readCheckoutBranch(context.projectRoot) ?? "HEAD";
41919
+ const checkpoint = buildScopeChangedCheckpoint(
42108
41920
  context,
42109
- checkpointId: input.checkpointId,
42110
- taskRevision: pendingMetadata.revision + 1,
42111
- requirements,
42112
- review,
42113
- verification,
42114
- summary: input.summary,
42115
- nextAction: input.nextAction,
41921
+ pendingMetadata,
41922
+ checkpointId,
41923
+ input.checkpointSummary,
41924
+ input.checkpointNextAction,
42116
41925
  branch,
42117
- timestamp: timestamp4
42118
- });
42119
- const metadata = completeReframeMetadata(
41926
+ pendingMetadata.governance.planVersion + 1,
41927
+ review.contentDigest,
41928
+ verification.contentDigest,
41929
+ timestamp4
41930
+ );
41931
+ const metadata = completeScopeChangeMetadata(
42120
41932
  pendingMetadata,
42121
- requirements,
42122
- review,
42123
- verification,
41933
+ scope,
42124
41934
  checkpoint,
41935
+ review.contentDigest,
41936
+ verification.contentDigest,
42125
41937
  context.operationId,
42126
41938
  timestamp4
42127
41939
  );
41940
+ const pendingSuccessorClaims = buildPendingSuccessorClaims2(
41941
+ successorPredecessors,
41942
+ successorClaimIds,
41943
+ metadata,
41944
+ branch,
41945
+ requireCodeHead3(context),
41946
+ context.operationId,
41947
+ timestamp4,
41948
+ capabilitiesFromProjectConfig(context.project.config)
41949
+ );
41950
+ const successorByPredecessor = new Map(
41951
+ successorPredecessors.map((claim, index) => {
41952
+ const successorClaimId = successorClaimIds[index];
41953
+ if (successorClaimId === void 0) {
41954
+ throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
41955
+ }
41956
+ return [claim.claimId, successorClaimId];
41957
+ })
41958
+ );
41959
+ const terminatedClaims = activeClaims2.map(
41960
+ (claim) => terminateClaimForScopeChange(
41961
+ claim,
41962
+ successorByPredecessor.get(claim.claimId) ?? null,
41963
+ context.operationId,
41964
+ timestamp4
41965
+ )
41966
+ );
41967
+ const activeSuccessorClaims = pendingSuccessorClaims.map(
41968
+ (claim) => activateSuccessorClaim3(claim, context.operationId, timestamp4)
41969
+ );
42128
41970
  const aggregate = buildTaskAggregateManifest({
42129
41971
  metadata,
42130
- requirements,
41972
+ requirements: context.task.requirements,
42131
41973
  review,
42132
41974
  verification,
42133
41975
  planDigest: context.task.plan?.digest ?? null,
42134
41976
  latestCheckpoint: checkpoint
42135
41977
  });
42136
41978
  const taskHeadFence = nextTaskHeadFence(context, aggregate, timestamp4);
42137
- const refreshesSessionPointer = context.session.activeTaskRef !== null && sameTaskRef(context.session.activeTaskRef, taskRef);
42138
- if (refreshesSessionPointer) {
42139
- await enqueueSessionPointerProjection(context.projectRoot, {
42140
- operationId: context.operationId,
42141
- action: "resume",
42142
- sessionId: context.session.sessionId,
42143
- expectedPreviousTaskRef: context.session.activeTaskRef,
42144
- taskRef,
42145
- workflowMode: metadata.workflowMode,
42146
- taskRevision: metadata.revision,
42147
- now: context.now
42148
- });
41979
+ if (taskHeadFence === null) {
41980
+ throw new Error("MANCODE_TASK_HEAD_FENCE_MISSING");
42149
41981
  }
42150
41982
  journal = await createTaskOperationJournal(context, {
42151
- type: "reframe",
42152
- action: taskRef.namespace === "shared" ? "shared_metadata_plan_mutation" : "local_workflow_mutation",
42153
- expectedRevisions: reframeExpectedRevisions(
41983
+ type: "scope_change_reclaim",
41984
+ action: "task_complete_scope_change_child_merge",
41985
+ expectedRevisions: scopeChangeExpectedRevisions(
42154
41986
  context,
42155
- input.checkpointId,
42156
- activeClaims2
41987
+ checkpointId,
41988
+ activeClaims2,
41989
+ successorClaimIds
42157
41990
  ),
41991
+ conditions: { completionGateSatisfied: true },
42158
41992
  recovery: {
42159
41993
  actions: [
42160
41994
  createTaskAuthorityFileRecoveryAction({
@@ -42164,20 +41998,28 @@ async function reframeV3Workflow(input) {
42164
41998
  beforeContent: serializeTaskAuthority(context.task.metadata),
42165
41999
  targetContent: serializeTaskAuthority(pendingMetadata)
42166
42000
  }),
42167
- archiveAction,
42168
- ...releasedClaims.map(
42169
- (claim, index) => createClaimRecoveryAction({
42170
- stepId: "release-active-claims",
42171
- before: activeClaims2[index] ?? null,
42001
+ createCheckpointRecoveryAction({
42002
+ stepId: "write-scope-changed-checkpoint",
42003
+ before: null,
42004
+ checkpoint
42005
+ }),
42006
+ ...pendingSuccessorClaims.map(
42007
+ (claim) => createClaimRecoveryAction({
42008
+ stepId: "create-pending-successor-claims",
42009
+ before: null,
42172
42010
  claim
42173
42011
  })
42174
42012
  ),
42175
- createTaskAuthorityFileRecoveryAction({
42176
- stepId: "write-requirements-draft",
42177
- taskRef,
42178
- fileName: "requirements.json",
42179
- beforeContent: serializeTaskAuthority(context.task.requirements),
42180
- targetContent: serializeTaskAuthority(requirements)
42013
+ ...terminatedClaims.map((claim, index) => {
42014
+ const before = activeClaims2[index];
42015
+ if (before === void 0) {
42016
+ throw new Error("MANCODE_CLAIM_SET_CHANGED");
42017
+ }
42018
+ return createClaimRecoveryAction({
42019
+ stepId: "terminate-old-claims",
42020
+ before,
42021
+ claim
42022
+ });
42181
42023
  }),
42182
42024
  createTaskAuthorityFileRecoveryAction({
42183
42025
  stepId: "mark-review-verification-stale",
@@ -42193,29 +42035,34 @@ async function reframeV3Workflow(input) {
42193
42035
  beforeContent: serializeTaskAuthority(context.task.verification),
42194
42036
  targetContent: serializeTaskAuthority(verification)
42195
42037
  }),
42196
- createCheckpointRecoveryAction({
42197
- stepId: "write-reframe-checkpoint",
42198
- before: null,
42199
- checkpoint
42200
- }),
42201
42038
  createTaskAuthorityFileRecoveryAction({
42202
- stepId: "commit-reframed-metadata",
42039
+ stepId: "update-metadata-scope",
42203
42040
  taskRef,
42204
42041
  fileName: "metadata.json",
42205
42042
  beforeContent: serializeTaskAuthority(pendingMetadata),
42206
42043
  targetContent: serializeTaskAuthority(metadata)
42207
42044
  }),
42208
- ...taskHeadFence === null ? [] : [
42209
- createTaskHeadFenceRecoveryAction({
42210
- stepId: "update-task-head-fence",
42211
- before: context.coordination.taskHeadFence,
42212
- fence: taskHeadFence
42213
- })
42214
- ]
42045
+ ...activeSuccessorClaims.map((claim, index) => {
42046
+ const before = pendingSuccessorClaims[index];
42047
+ if (before === void 0) {
42048
+ throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
42049
+ }
42050
+ return createClaimRecoveryAction({
42051
+ stepId: "activate-successor-claims",
42052
+ before,
42053
+ claim
42054
+ });
42055
+ }),
42056
+ createTaskHeadFenceRecoveryAction({
42057
+ stepId: "update-task-head-fence",
42058
+ before: context.coordination.taskHeadFence,
42059
+ fence: taskHeadFence
42060
+ })
42215
42061
  ],
42216
42062
  noOpStepIds: [
42217
- ...releasedClaims.length === 0 ? ["release-active-claims"] : [],
42218
- ...taskHeadFence === null ? ["update-task-head-fence"] : []
42063
+ ...pendingSuccessorClaims.length === 0 ? ["create-pending-successor-claims"] : [],
42064
+ ...terminatedClaims.length === 0 ? ["terminate-old-claims"] : [],
42065
+ ...activeSuccessorClaims.length === 0 ? ["activate-successor-claims"] : []
42219
42066
  ]
42220
42067
  }
42221
42068
  });
@@ -42226,36 +42073,986 @@ async function reframeV3Workflow(input) {
42226
42073
  "mark-task-operation-pending",
42227
42074
  false
42228
42075
  );
42229
- await assertReframeCodeHeadUnchanged(context);
42076
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42230
42077
  await writeTaskAuthorityFile(
42231
42078
  context,
42232
42079
  "metadata.json",
42233
- serializeTaskAuthority(pendingMetadata)
42080
+ `${JSON.stringify(pendingMetadata, null, 2)}
42081
+ `
42234
42082
  );
42235
42083
  journal = await advanceTaskOperation(
42236
42084
  context,
42237
42085
  journal,
42238
- "archive-requirements-plan",
42086
+ "write-scope-changed-checkpoint",
42239
42087
  false
42240
42088
  );
42241
- await assertReframeCodeHeadUnchanged(context);
42242
- await writeTaskArchive(context, archiveAction);
42089
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42090
+ await writeTaskCheckpoint(context, checkpoint);
42243
42091
  journal = await advanceTaskOperation(
42244
42092
  context,
42245
42093
  journal,
42246
- "release-active-claims",
42094
+ "create-pending-successor-claims",
42247
42095
  false
42248
42096
  );
42249
- await assertReframeCodeHeadUnchanged(context);
42250
- for (const [index, claim] of releasedClaims.entries()) {
42097
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42098
+ for (const claim of pendingSuccessorClaims) {
42099
+ await createClaim(context.homeStore, claim);
42100
+ }
42101
+ journal = await advanceTaskOperation(
42102
+ context,
42103
+ journal,
42104
+ "terminate-old-claims",
42105
+ false
42106
+ );
42107
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42108
+ for (const [index, claim] of terminatedClaims.entries()) {
42251
42109
  const previous = activeClaims2[index];
42252
- if (previous === void 0) throw new Error("MANCODE_CLAIM_SET_CHANGED");
42110
+ if (previous === void 0) {
42111
+ throw new Error("MANCODE_CLAIM_SET_CHANGED");
42112
+ }
42253
42113
  await updateClaim(context.homeStore, claim, previous.revision);
42254
42114
  }
42255
42115
  journal = await advanceTaskOperation(
42256
42116
  context,
42257
42117
  journal,
42258
- "write-requirements-draft",
42118
+ "mark-review-verification-stale",
42119
+ false
42120
+ );
42121
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42122
+ await writeTaskAuthorityFile(
42123
+ context,
42124
+ "review-ledger.json",
42125
+ `${JSON.stringify(review, null, 2)}
42126
+ `
42127
+ );
42128
+ await writeTaskAuthorityFile(
42129
+ context,
42130
+ "verification-ledger.json",
42131
+ `${JSON.stringify(verification, null, 2)}
42132
+ `
42133
+ );
42134
+ journal = await advanceTaskOperation(
42135
+ context,
42136
+ journal,
42137
+ "update-metadata-scope",
42138
+ false
42139
+ );
42140
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42141
+ await writeTaskAuthorityFile(
42142
+ context,
42143
+ "metadata.json",
42144
+ `${JSON.stringify(metadata, null, 2)}
42145
+ `
42146
+ );
42147
+ journal = await advanceTaskOperation(
42148
+ context,
42149
+ journal,
42150
+ "activate-successor-claims",
42151
+ false
42152
+ );
42153
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42154
+ for (const claim of activeSuccessorClaims) {
42155
+ await updateClaim(context.homeStore, claim, 1);
42156
+ }
42157
+ journal = await advanceTaskOperation(
42158
+ context,
42159
+ journal,
42160
+ "update-task-head-fence",
42161
+ false
42162
+ );
42163
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42164
+ await replaceTaskHeadFence(context.homeStore, taskHeadFence);
42165
+ const operation = await commitTaskOperation(context, journal);
42166
+ return {
42167
+ metadata,
42168
+ checkpoint,
42169
+ terminatedClaims,
42170
+ successorClaims: activeSuccessorClaims,
42171
+ aggregate,
42172
+ taskHeadFence,
42173
+ operation
42174
+ };
42175
+ } catch (error) {
42176
+ if (journal !== null) {
42177
+ try {
42178
+ await handleTaskOperationFailure(context, journal);
42179
+ } catch {
42180
+ }
42181
+ }
42182
+ throw error;
42183
+ } finally {
42184
+ await context.release();
42185
+ }
42186
+ }
42187
+ async function openScopeChangeContext(input) {
42188
+ for (let attempt = 0; attempt < 3; attempt += 1) {
42189
+ const runtime = await readProjectRuntimeContext(input.projectRoot);
42190
+ const store = new V3ContextStore(input.projectRoot);
42191
+ const homeStore = resolveTaskEntityHomeStore(
42192
+ runtime.entityHomeStoreContext,
42193
+ input.taskRef
42194
+ );
42195
+ const preflight = await store.readCoordinationSnapshot(
42196
+ input.taskRef,
42197
+ homeStore
42198
+ );
42199
+ const preflightClaims = activeClaims(preflight.claims);
42200
+ const preflightSuccessors = claimsWithinScope(preflightClaims, input.scope);
42201
+ const preflightSuccessorIds = resolveSuccessorClaimIds2(
42202
+ preflightSuccessors,
42203
+ input.successorClaimIds,
42204
+ input.operationId,
42205
+ input.now.toISOString()
42206
+ );
42207
+ const context = await openV3TaskOperation({
42208
+ projectRoot: input.projectRoot,
42209
+ taskRef: input.taskRef,
42210
+ sessionId: input.sessionId,
42211
+ expectedTaskRevision: input.expectedTaskRevision,
42212
+ operationId: input.operationId,
42213
+ extraEntityLocks: [
42214
+ `checkpoint:${input.checkpointId}`,
42215
+ taskHeadEntityKey(input.taskRef),
42216
+ ...preflightClaims.map((claim) => `claim:${claim.claimId}`),
42217
+ ...preflightSuccessorIds.map((claimId) => `claim:${claimId}`)
42218
+ ],
42219
+ now: input.now
42220
+ });
42221
+ const lockedClaims = activeClaims(context.coordination.claims);
42222
+ if (sameClaimIdSet(preflightClaims, lockedClaims)) {
42223
+ const successors = claimsWithinScope(lockedClaims, input.scope);
42224
+ const successorIds = resolveSuccessorClaimIds2(
42225
+ successors,
42226
+ input.successorClaimIds,
42227
+ input.operationId,
42228
+ input.now.toISOString()
42229
+ );
42230
+ return {
42231
+ context,
42232
+ activeClaims: lockedClaims,
42233
+ successorPredecessors: successors,
42234
+ successorClaimIds: successorIds
42235
+ };
42236
+ }
42237
+ await context.release();
42238
+ }
42239
+ throw new Error("MANCODE_CLAIM_SET_CHANGED");
42240
+ }
42241
+ function assertScopeChangeEligible(context, scope) {
42242
+ const metadata = context.task.metadata;
42243
+ if (context.project.config.transport.mode !== "local") {
42244
+ throw new Error("MANCODE_GIT_REF_TRANSPORT_NOT_IMPLEMENTED");
42245
+ }
42246
+ if (metadata.workflowMode !== "manteam") {
42247
+ throw new Error("MANCODE_SCOPE_CHANGE_WORKFLOW_MODE_INVALID");
42248
+ }
42249
+ if (metadata.status !== "in_progress") {
42250
+ throw new Error("MANCODE_SCOPE_CHANGE_WORKFLOW_NOT_ACTIVE");
42251
+ }
42252
+ if (metadata.ownerActorId !== context.session.actorId) {
42253
+ throw new Error("MANCODE_TASK_OWNER_REQUIRED");
42254
+ }
42255
+ if (metadata.parent !== null) {
42256
+ throw new Error("MANCODE_PARENT_SCOPE_INHERITANCE_REQUIRED");
42257
+ }
42258
+ if (metadata.implementationScope.digest === scope.digest) {
42259
+ throw new Error("MANCODE_SCOPE_CHANGE_NOOP");
42260
+ }
42261
+ }
42262
+ function assertClaimsFreshForScopeChange(context, claims) {
42263
+ const codeHead = requireCodeHead3(context);
42264
+ for (const claim of claims) {
42265
+ if (claim.authority.mode !== "local") {
42266
+ throw new Error("MANCODE_OPERATION_REPAIR_REQUIRED");
42267
+ }
42268
+ const validity = deriveClaimValidity(claim, {
42269
+ taskRef: context.taskRef,
42270
+ taskRevision: context.task.metadata.revision,
42271
+ implementationScopeDigest: context.task.metadata.implementationScope.digest,
42272
+ ownershipEpoch: context.task.metadata.ownershipEpoch,
42273
+ codeRefHead: codeHead,
42274
+ now: context.now,
42275
+ transportFreshness: "fresh"
42276
+ });
42277
+ if (validity !== "fresh") {
42278
+ throw new Error("MANCODE_CLAIM_REVALIDATION_REQUIRED");
42279
+ }
42280
+ }
42281
+ }
42282
+ function normalizeImplementationScope(value) {
42283
+ assertRecord(value, "workflow scope change");
42284
+ assertKnownKeys(
42285
+ value,
42286
+ ["include", "exclude", "modules"],
42287
+ "workflow scope change"
42288
+ );
42289
+ const scope = {
42290
+ source: "explicit",
42291
+ include: normalizeScopeValues(value.include, "include", true),
42292
+ exclude: normalizeScopeValues(value.exclude, "exclude", true),
42293
+ modules: normalizeScopeValues(value.modules, "modules", false)
42294
+ };
42295
+ const included = new Set(scope.include);
42296
+ if (scope.exclude.some((item) => included.has(item))) {
42297
+ throw new Error("MANCODE_SCOPE_INCLUDE_EXCLUDE_CONFLICT");
42298
+ }
42299
+ return { ...scope, digest: digestCanonicalJson(scope) };
42300
+ }
42301
+ function normalizeScopeValues(value, label, paths) {
42302
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
42303
+ throw new Error(`MANCODE_SCOPE_${label.toUpperCase()}_INVALID`);
42304
+ }
42305
+ const values = value.map((item) => item.trim());
42306
+ const normalized = sortUtf8StringSet(values);
42307
+ if (normalized.length !== values.length) {
42308
+ throw new Error(`MANCODE_SCOPE_${label.toUpperCase()}_DUPLICATE`);
42309
+ }
42310
+ for (const item of normalized) {
42311
+ assertSharedTextSafe(item, `workflow scope ${label}`);
42312
+ if (paths) assertScopePath(item);
42313
+ }
42314
+ return normalized;
42315
+ }
42316
+ function assertScopePath(value) {
42317
+ if (value.startsWith("/") || value.startsWith("~") || /^[A-Za-z]:/.test(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
42318
+ throw new Error("MANCODE_SCOPE_PATH_INVALID");
42319
+ }
42320
+ }
42321
+ function markScopeChangeOperationPending(previous, operationId, updatedAt) {
42322
+ const next = parseWorkflowMetadata({
42323
+ ...previous,
42324
+ revision: previous.revision + 1,
42325
+ transitionState: "operation_pending",
42326
+ lastOperationId: operationId,
42327
+ updatedAt
42328
+ });
42329
+ assertWorkflowMetadataTransition(previous, next, "ordinary");
42330
+ return next;
42331
+ }
42332
+ function completeScopeChangeMetadata(previous, scope, checkpoint, reviewLedgerDigest2, verificationLedgerDigest2, operationId, updatedAt) {
42333
+ const next = parseWorkflowMetadata({
42334
+ ...previous,
42335
+ revision: previous.revision + 1,
42336
+ transitionState: "stable",
42337
+ implementationScope: scope,
42338
+ governance: {
42339
+ ...previous.governance,
42340
+ planVersion: previous.governance.planVersion + 1,
42341
+ reviewStatus: "stale",
42342
+ reviewLedgerDigest: reviewLedgerDigest2,
42343
+ verificationStatus: "stale",
42344
+ verificationLedgerDigest: verificationLedgerDigest2
42345
+ },
42346
+ latestCheckpointRef: {
42347
+ taskRef: checkpoint.taskRef,
42348
+ kind: "checkpoint",
42349
+ artifactId: checkpoint.checkpointId
42350
+ },
42351
+ lastOperationId: operationId,
42352
+ updatedAt
42353
+ });
42354
+ assertWorkflowMetadataTransition(previous, next, "ordinary");
42355
+ return next;
42356
+ }
42357
+ function buildScopeChangedCheckpoint(context, pendingMetadata, checkpointId, summary, nextAction, branch, planVersion, reviewLedgerDigest2, verificationLedgerDigest2, timestamp4) {
42358
+ return parseCheckpoint({
42359
+ schemaVersion: 1,
42360
+ checkpointId,
42361
+ operationId: context.operationId,
42362
+ taskRef: context.taskRef,
42363
+ taskRevision: pendingMetadata.revision,
42364
+ ownershipEpochAtOffer: pendingMetadata.ownershipEpoch,
42365
+ kind: "scope_changed",
42366
+ git: {
42367
+ branch,
42368
+ head: requireCodeHead3(context),
42369
+ base: pendingMetadata.base?.head ?? null
42370
+ },
42371
+ summary: summary ?? "Changed the implementation scope and replaced affected coordination claims.",
42372
+ governance: {
42373
+ requirementsDigest: context.task.requirements.contentDigest,
42374
+ planVersion,
42375
+ reviewLedgerDigest: reviewLedgerDigest2,
42376
+ verificationLedgerDigest: verificationLedgerDigest2
42377
+ },
42378
+ nextAction: nextAction ?? "Re-read the updated scope and continue only with the successor claim.",
42379
+ createdBy: {
42380
+ actorId: context.session.actorId,
42381
+ client: context.session.client
42382
+ },
42383
+ createdAt: timestamp4
42384
+ });
42385
+ }
42386
+ function buildPendingSuccessorClaims2(predecessors, successorClaimIds, metadata, branch, codeHead, operationId, timestamp4, capabilities) {
42387
+ return predecessors.map((previous, index) => {
42388
+ const claimId = successorClaimIds[index];
42389
+ if (claimId === void 0) {
42390
+ throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
42391
+ }
42392
+ return parseClaim({
42393
+ ...previous,
42394
+ claimId,
42395
+ authority: { mode: "local", remoteRevision: null },
42396
+ taskRevisionAtAcquire: metadata.revision,
42397
+ lastValidatedTaskRevision: metadata.revision,
42398
+ implementationScopeDigest: metadata.implementationScope.digest,
42399
+ ownershipEpochAtAcquire: metadata.ownershipEpoch,
42400
+ state: "pending",
42401
+ revision: 1,
42402
+ codeRefAtAcquire: { branch, head: codeHead },
42403
+ lastValidatedCodeRef: { branch, head: codeHead },
42404
+ acquisitionEnforcement: capabilities.claimAcquisition,
42405
+ writeGuard: capabilities.writeGuard,
42406
+ predecessorClaimId: previous.claimId,
42407
+ successorClaimId: null,
42408
+ lastOperationId: operationId,
42409
+ createdAt: timestamp4,
42410
+ updatedAt: timestamp4
42411
+ });
42412
+ });
42413
+ }
42414
+ function terminateClaimForScopeChange(previous, successorClaimId, operationId, timestamp4) {
42415
+ const next = parseClaim({
42416
+ ...previous,
42417
+ state: successorClaimId === null ? "released" : "transferred",
42418
+ revision: previous.revision + 1,
42419
+ successorClaimId,
42420
+ lastOperationId: operationId,
42421
+ updatedAt: timestamp4
42422
+ });
42423
+ assertClaimTransition(previous, next);
42424
+ return next;
42425
+ }
42426
+ function activateSuccessorClaim3(previous, operationId, timestamp4) {
42427
+ const next = parseClaim({
42428
+ ...previous,
42429
+ state: "active",
42430
+ revision: previous.revision + 1,
42431
+ lastOperationId: operationId,
42432
+ updatedAt: timestamp4
42433
+ });
42434
+ assertClaimTransition(previous, next);
42435
+ return next;
42436
+ }
42437
+ function scopeChangeExpectedRevisions(context, checkpointId, predecessors, successorClaimIds) {
42438
+ const expected = {
42439
+ [taskEntityKey(context.taskRef)]: context.task.metadata.revision,
42440
+ [`review:${context.taskRef.taskId}`]: context.task.review.revision,
42441
+ [`verification:${context.taskRef.taskId}`]: context.task.verification.revision,
42442
+ [`checkpoint:${checkpointId}`]: 0
42443
+ };
42444
+ for (const claim of predecessors) {
42445
+ expected[`claim:${claim.claimId}`] = claim.revision;
42446
+ }
42447
+ for (const claimId of successorClaimIds) {
42448
+ expected[`claim:${claimId}`] = 0;
42449
+ }
42450
+ const fence = context.coordination.taskHeadFence;
42451
+ if (fence === null) throw new Error("MANCODE_TASK_HEAD_FENCE_MISSING");
42452
+ expected[taskHeadEntityKey(context.taskRef)] = fence.fenceRevision;
42453
+ return expected;
42454
+ }
42455
+ function activeClaims(claims) {
42456
+ return claims.filter((claim) => claim.state === "active").sort((left, right) => compareUtf815(left.claimId, right.claimId));
42457
+ }
42458
+ function claimsWithinScope(claims, scope) {
42459
+ return claims.filter(
42460
+ (claim) => evaluateClaimScopeSubset(claim.scope, {
42461
+ source: scope.source,
42462
+ include: scope.include,
42463
+ exclude: scope.exclude,
42464
+ modules: scope.modules
42465
+ }).allowed
42466
+ );
42467
+ }
42468
+ function resolveSuccessorClaimIds2(predecessors, requested, operationId, timestamp4) {
42469
+ const ids = requested ?? predecessors.map(
42470
+ (claim) => scopeSuccessorClaimId(operationId, claim.claimId, timestamp4)
42471
+ );
42472
+ if (ids.length !== predecessors.length) {
42473
+ throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
42474
+ }
42475
+ const predecessorIds = new Set(predecessors.map((claim) => claim.claimId));
42476
+ const seen = /* @__PURE__ */ new Set();
42477
+ for (const claimId of ids) {
42478
+ assertUlid(claimId, "scope successor claimId");
42479
+ if (predecessorIds.has(claimId) || seen.has(claimId)) {
42480
+ throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_INVALID");
42481
+ }
42482
+ seen.add(claimId);
42483
+ }
42484
+ return ids;
42485
+ }
42486
+ function scopeSuccessorClaimId(operationId, predecessorClaimId, timestamp4) {
42487
+ assertUlid(operationId, "scope change operationId");
42488
+ assertUlid(predecessorClaimId, "scope predecessor claimId");
42489
+ const milliseconds = Date.parse(timestamp4);
42490
+ if (Number.isNaN(milliseconds)) {
42491
+ throw new Error("MANCODE_SCOPE_TIMESTAMP_INVALID");
42492
+ }
42493
+ const entropy = createHash11("sha256").update(`scope-change:${operationId}:${predecessorClaimId}`, "utf8").digest().subarray(0, 10);
42494
+ return createUlid(milliseconds, entropy);
42495
+ }
42496
+ function requireCodeHead3(context) {
42497
+ if (context.codeHead === null) {
42498
+ throw new Error("MANCODE_TASK_HEAD_CODE_REF_UNAVAILABLE");
42499
+ }
42500
+ return context.codeHead;
42501
+ }
42502
+ function sameClaimIdSet(left, right) {
42503
+ return left.length === right.length && left.every((claim, index) => claim.claimId === right[index]?.claimId);
42504
+ }
42505
+ function compareUtf815(left, right) {
42506
+ return Buffer.from(left, "utf8").compare(Buffer.from(right, "utf8"));
42507
+ }
42508
+
42509
+ // src/context/plan-revision.ts
42510
+ async function reviseV3Plan(input) {
42511
+ const taskRef = parseTaskRefValue(input.taskRef);
42512
+ const plan = requirePlan(input.plan);
42513
+ const planDecision = parsePlanDecision(input.planDecision);
42514
+ const submittedScope = input.implementationScope === void 0 ? null : normalizeImplementationScope(input.implementationScope);
42515
+ if (taskRef.namespace === "shared") {
42516
+ assertSharedTextSafe(plan, "plan");
42517
+ }
42518
+ const context = await openV3TaskOperation({
42519
+ projectRoot: input.projectRoot,
42520
+ taskRef,
42521
+ sessionId: input.sessionId,
42522
+ expectedTaskRevision: input.expectedTaskRevision,
42523
+ operationId: input.operationId,
42524
+ extraEntityLocks: taskRef.namespace === "shared" ? [taskHeadEntityKey(taskRef)] : [],
42525
+ now: input.now
42526
+ });
42527
+ let journal = null;
42528
+ try {
42529
+ const planChanged = context.task.plan?.content !== plan;
42530
+ const executionScopeBinding = assertExecutionScopeBindingAttempt({
42531
+ metadata: context.task.metadata,
42532
+ currentPlan: context.task.plan?.content ?? null,
42533
+ submittedPlan: plan,
42534
+ submittedScope,
42535
+ planDecisionSupplied: input.planDecision !== void 0,
42536
+ sessionActorId: context.session.actorId
42537
+ });
42538
+ assertPlanRevisionEligible(
42539
+ context.task.metadata,
42540
+ context.task.requirements,
42541
+ executionScopeBinding
42542
+ );
42543
+ const implementationScope = submittedScope ?? context.task.metadata.implementationScope;
42544
+ const scopeChanged = submittedScope !== null && submittedScope.digest !== context.task.metadata.implementationScope.digest;
42545
+ if (planDecision === "governed_execution") {
42546
+ assertExecutableImplementationScope(implementationScope);
42547
+ }
42548
+ if (executionScopeBinding) {
42549
+ assertExecutableImplementationScope(implementationScope);
42550
+ }
42551
+ if (context.task.metadata.workflowMode === "manteam" && planDecision === "governed_execution") {
42552
+ assertManteamPlanContent(plan);
42553
+ }
42554
+ if (context.task.plan?.content === plan && planDecision === null && !scopeChanged) {
42555
+ throw new Error("MANCODE_PLAN_CONTENT_UNCHANGED");
42556
+ }
42557
+ const authorityChanged = planChanged || scopeChanged;
42558
+ const timestamp4 = context.now.toISOString();
42559
+ const planDigest = planChanged ? digestCanonicalJson({
42560
+ artifactRef: { taskRef, kind: "plan" },
42561
+ content: plan
42562
+ }) : context.task.plan?.digest;
42563
+ if (planDigest === void 0) {
42564
+ throw new Error("MANCODE_PLAN_FILE_REQUIRED");
42565
+ }
42566
+ const review = authorityChanged ? markTaskReviewStale(context.task.review, context.operationId, timestamp4) : context.task.review;
42567
+ const verification = authorityChanged ? markTaskVerificationStale(
42568
+ context.task.verification,
42569
+ context.operationId,
42570
+ timestamp4
42571
+ ) : context.task.verification;
42572
+ const metadata = updateMetadata(
42573
+ context.task.metadata,
42574
+ context.task.requirements,
42575
+ review,
42576
+ verification,
42577
+ implementationScope,
42578
+ authorityChanged,
42579
+ planDecision,
42580
+ executionScopeBinding,
42581
+ context.operationId,
42582
+ timestamp4
42583
+ );
42584
+ const aggregate = buildTaskAggregateManifest({
42585
+ metadata,
42586
+ requirements: context.task.requirements,
42587
+ review,
42588
+ verification,
42589
+ planDigest,
42590
+ latestCheckpoint: context.task.latestCheckpoint
42591
+ });
42592
+ const taskHeadFence = nextTaskHeadFence(context, aggregate, timestamp4);
42593
+ if (planDecision === "plan_only") {
42594
+ await enqueueSessionPointerProjection(context.projectRoot, {
42595
+ operationId: context.operationId,
42596
+ action: "clear",
42597
+ sessionId: context.session.sessionId,
42598
+ expectedPreviousTaskRef: context.session.activeTaskRef,
42599
+ taskRef,
42600
+ workflowMode: metadata.workflowMode,
42601
+ taskRevision: metadata.revision,
42602
+ now: context.now
42603
+ });
42604
+ }
42605
+ journal = await createTaskOperationJournal(context, {
42606
+ type: "plan_revision",
42607
+ action: taskRef.namespace === "shared" ? "shared_metadata_plan_mutation" : "local_workflow_mutation",
42608
+ expectedRevisions: taskMutationExpectedRevisions(context, [
42609
+ "plan",
42610
+ "review",
42611
+ "verification"
42612
+ ]),
42613
+ recovery: {
42614
+ actions: [
42615
+ ...planChanged ? [
42616
+ createTaskAuthorityFileRecoveryAction({
42617
+ stepId: "write-plan",
42618
+ taskRef,
42619
+ fileName: "plan.md",
42620
+ beforeContent: context.task.plan?.content ?? null,
42621
+ targetContent: plan
42622
+ })
42623
+ ] : [],
42624
+ createTaskAuthorityFileRecoveryAction({
42625
+ stepId: "update-metadata",
42626
+ taskRef,
42627
+ fileName: "metadata.json",
42628
+ beforeContent: serializeTaskAuthority(context.task.metadata),
42629
+ targetContent: serializeTaskAuthority(metadata)
42630
+ }),
42631
+ ...authorityChanged ? [
42632
+ createTaskAuthorityFileRecoveryAction({
42633
+ stepId: "mark-review-verification-stale",
42634
+ taskRef,
42635
+ fileName: "review-ledger.json",
42636
+ beforeContent: serializeTaskAuthority(context.task.review),
42637
+ targetContent: serializeTaskAuthority(review)
42638
+ }),
42639
+ createTaskAuthorityFileRecoveryAction({
42640
+ stepId: "mark-review-verification-stale",
42641
+ taskRef,
42642
+ fileName: "verification-ledger.json",
42643
+ beforeContent: serializeTaskAuthority(
42644
+ context.task.verification
42645
+ ),
42646
+ targetContent: serializeTaskAuthority(verification)
42647
+ })
42648
+ ] : [],
42649
+ ...taskHeadFence === null ? [] : [
42650
+ createTaskHeadFenceRecoveryAction({
42651
+ stepId: "update-task-head-fence",
42652
+ before: context.coordination.taskHeadFence,
42653
+ fence: taskHeadFence
42654
+ })
42655
+ ]
42656
+ ],
42657
+ noOpStepIds: [
42658
+ ...planChanged ? [] : ["write-plan"],
42659
+ ...authorityChanged ? [] : ["mark-review-verification-stale"],
42660
+ ...taskHeadFence === null ? ["update-task-head-fence"] : []
42661
+ ]
42662
+ }
42663
+ });
42664
+ journal = await advanceTaskOperation(context, journal, "validate", true);
42665
+ journal = await advanceTaskOperation(context, journal, "write-plan", false);
42666
+ if (planChanged) {
42667
+ await writeTaskAuthorityFile(context, "plan.md", plan);
42668
+ }
42669
+ journal = await advanceTaskOperation(
42670
+ context,
42671
+ journal,
42672
+ "update-metadata",
42673
+ false
42674
+ );
42675
+ await writeTaskAuthorityFile(
42676
+ context,
42677
+ "metadata.json",
42678
+ `${JSON.stringify(metadata, null, 2)}
42679
+ `
42680
+ );
42681
+ journal = await advanceTaskOperation(
42682
+ context,
42683
+ journal,
42684
+ "mark-review-verification-stale",
42685
+ false
42686
+ );
42687
+ if (authorityChanged) {
42688
+ await writeTaskAuthorityFile(
42689
+ context,
42690
+ "review-ledger.json",
42691
+ `${JSON.stringify(review, null, 2)}
42692
+ `
42693
+ );
42694
+ await writeTaskAuthorityFile(
42695
+ context,
42696
+ "verification-ledger.json",
42697
+ `${JSON.stringify(verification, null, 2)}
42698
+ `
42699
+ );
42700
+ }
42701
+ journal = await advanceTaskOperation(
42702
+ context,
42703
+ journal,
42704
+ "update-task-head-fence",
42705
+ false
42706
+ );
42707
+ if (taskHeadFence !== null) {
42708
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42709
+ await replaceTaskHeadFence(context.homeStore, taskHeadFence);
42710
+ }
42711
+ const operation = await commitTaskOperation(context, journal);
42712
+ if (planDecision === "plan_only") {
42713
+ try {
42714
+ await reconcileProjectionIntents(
42715
+ context.projectRoot,
42716
+ context.operationId,
42717
+ context.now
42718
+ );
42719
+ } catch {
42720
+ }
42721
+ }
42722
+ return {
42723
+ metadata,
42724
+ review,
42725
+ verification,
42726
+ planDigest,
42727
+ aggregate,
42728
+ taskHeadFence,
42729
+ operation
42730
+ };
42731
+ } catch (error) {
42732
+ if (journal !== null) {
42733
+ try {
42734
+ await handleTaskOperationFailure(context, journal);
42735
+ } catch {
42736
+ }
42737
+ }
42738
+ throw error;
42739
+ } finally {
42740
+ await context.release();
42741
+ }
42742
+ }
42743
+ function requirePlan(value) {
42744
+ if (typeof value !== "string" || !value.trim() || value.includes("\0")) {
42745
+ throw new Error("MANCODE_PLAN_CONTENT_REQUIRED");
42746
+ }
42747
+ return value;
42748
+ }
42749
+ function parsePlanDecision(value) {
42750
+ if (value === void 0) return null;
42751
+ if (value !== "plan_only" && value !== "governed_execution") {
42752
+ throw new Error("MANCODE_PLAN_DECISION_INVALID");
42753
+ }
42754
+ return value;
42755
+ }
42756
+ function assertPlanRevisionEligible(metadata, requirements, executionScopeBinding) {
42757
+ if (executionScopeBinding) {
42758
+ assertReadyPlanRequirements(metadata, requirements);
42759
+ return;
42760
+ }
42761
+ if (metadata.workflowMode !== "man" && metadata.workflowMode !== "manteam") {
42762
+ throw new Error("MANCODE_PLAN_WORKFLOW_MODE_INVALID");
42763
+ }
42764
+ if (metadata.status !== "in_progress") {
42765
+ throw new Error("MANCODE_PLAN_WORKFLOW_NOT_ACTIVE");
42766
+ }
42767
+ if (metadata.currentStep < 2 || metadata.currentStep > 4) {
42768
+ throw new Error("MANCODE_PLAN_STEP_INVALID");
42769
+ }
42770
+ if (metadata.governance.planDecision !== null) {
42771
+ throw new Error("MANCODE_PLAN_REQUIREMENTS_OR_DECISION_INVALID");
42772
+ }
42773
+ assertReadyPlanRequirements(metadata, requirements);
42774
+ }
42775
+ function assertReadyPlanRequirements(metadata, requirements) {
42776
+ if (metadata.governance.requirementsStatus !== "ready" || metadata.governance.requirementsDigest !== requirements.contentDigest || requirements.status !== "confirmed" || !requirementsAreReady(requirements)) {
42777
+ throw new Error("MANCODE_PLAN_REQUIREMENTS_OR_DECISION_INVALID");
42778
+ }
42779
+ assertRequirementsScopeConsistent(requirements);
42780
+ }
42781
+ function assertExecutionScopeBindingAttempt(input) {
42782
+ const decision = input.metadata.governance.planDecision;
42783
+ if (decision !== "governed_execution" && decision !== "solo_handoff") {
42784
+ return false;
42785
+ }
42786
+ if (input.metadata.workflowMode !== "man" || input.metadata.coordination !== "single" || input.metadata.taskRef.namespace !== "local") {
42787
+ throw new Error("MANCODE_EXECUTION_SCOPE_BINDING_LOCAL_MAN_ONLY");
42788
+ }
42789
+ const activeExecution = decision === "governed_execution" && input.metadata.status === "in_progress" && input.metadata.currentStep >= 5 || decision === "solo_handoff" && input.metadata.status === "planned" && input.metadata.currentStep === 4 && input.metadata.soloExecution?.state === "active";
42790
+ if (!activeExecution) {
42791
+ throw new Error("MANCODE_EXECUTION_SCOPE_BINDING_NOT_ACTIVE");
42792
+ }
42793
+ if (input.metadata.ownerActorId !== input.sessionActorId) {
42794
+ throw new Error("MANCODE_TASK_OWNER_REQUIRED");
42795
+ }
42796
+ if (implementationScopeIsExecutable(input.metadata.implementationScope)) {
42797
+ throw new Error("MANCODE_EXECUTION_SCOPE_ALREADY_BOUND");
42798
+ }
42799
+ if (input.submittedScope === null) {
42800
+ throw new Error("MANCODE_IMPLEMENTATION_SCOPE_REQUIRED");
42801
+ }
42802
+ if (input.currentPlan === null || input.currentPlan !== input.submittedPlan) {
42803
+ throw new Error("MANCODE_EXECUTION_SCOPE_BINDING_PLAN_CHANGED");
42804
+ }
42805
+ if (input.planDecisionSupplied) {
42806
+ throw new Error("MANCODE_EXECUTION_SCOPE_BINDING_DECISION_INVALID");
42807
+ }
42808
+ assertExecutableImplementationScope(input.submittedScope);
42809
+ return true;
42810
+ }
42811
+ function updateMetadata(previous, requirements, review, verification, implementationScope, authorityChanged, planDecision, executionScopeBinding, operationId, updatedAt) {
42812
+ const status2 = executionScopeBinding ? previous.status : planDecision === "plan_only" ? "planned" : "in_progress";
42813
+ const currentStep = executionScopeBinding ? previous.currentStep : planDecision === "governed_execution" ? 5 : 4;
42814
+ const nextPlanVersion = previous.governance.planVersion + (authorityChanged ? 1 : 0);
42815
+ const next = parseWorkflowMetadata({
42816
+ ...previous,
42817
+ status: status2,
42818
+ currentStep,
42819
+ revision: previous.revision + 1,
42820
+ transitionState: "stable",
42821
+ lastOperationId: operationId,
42822
+ implementationScope,
42823
+ governance: {
42824
+ ...previous.governance,
42825
+ requirementsStatus: "ready",
42826
+ requirementsDigest: requirements.contentDigest,
42827
+ planVersion: nextPlanVersion,
42828
+ planDecision: executionScopeBinding ? previous.governance.planDecision : planDecision,
42829
+ reviewStatus: authorityChanged ? "stale" : previous.governance.reviewStatus,
42830
+ reviewLedgerDigest: review.contentDigest,
42831
+ verificationStatus: authorityChanged ? "stale" : previous.governance.verificationStatus,
42832
+ verificationLedgerDigest: verification.contentDigest
42833
+ },
42834
+ soloExecution: executionScopeBinding && previous.soloExecution !== null ? { ...previous.soloExecution, planVersion: nextPlanVersion } : previous.soloExecution,
42835
+ updatedAt
42836
+ });
42837
+ assertWorkflowMetadataTransition(previous, next, "ordinary");
42838
+ return next;
42839
+ }
42840
+
42841
+ // src/context/reframe.ts
42842
+ async function reframeV3Workflow(input) {
42843
+ const taskRef = parseTaskRefValue(input.taskRef);
42844
+ assertUlid(input.checkpointId, "reframe checkpointId");
42845
+ const now = input.now ?? /* @__PURE__ */ new Date();
42846
+ const operationId = input.operationId ?? createUlid(now.getTime());
42847
+ assertUlid(operationId, "reframe operationId");
42848
+ const opened = await openReframeContext({
42849
+ projectRoot: input.projectRoot,
42850
+ taskRef,
42851
+ sessionId: input.sessionId,
42852
+ expectedTaskRevision: input.expectedTaskRevision,
42853
+ checkpointId: input.checkpointId,
42854
+ operationId,
42855
+ now
42856
+ });
42857
+ const { context, activeClaims: activeClaims2, openHandoffs, activeChildren } = opened;
42858
+ let journal = null;
42859
+ try {
42860
+ assertReframeEligible(context, activeClaims2, openHandoffs, activeChildren);
42861
+ assertReframeClaimsFresh(context, activeClaims2);
42862
+ const timestamp4 = context.now.toISOString();
42863
+ const archivedRequirementsContent = await readTaskAuthorityFileAtRoot(
42864
+ context.task.location.taskRoot,
42865
+ "requirements.json"
42866
+ );
42867
+ if (archivedRequirementsContent === null) {
42868
+ throw new Error("MANCODE_REFRAME_REQUIREMENTS_MISSING");
42869
+ }
42870
+ const pendingMetadata = markReframeOperationPending(
42871
+ context.task.metadata,
42872
+ context.operationId,
42873
+ timestamp4
42874
+ );
42875
+ const requirements = createReframedRequirements(
42876
+ context.task.requirements,
42877
+ context.operationId,
42878
+ timestamp4
42879
+ );
42880
+ const review = markTaskReviewStale(
42881
+ context.task.review,
42882
+ context.operationId,
42883
+ timestamp4
42884
+ );
42885
+ const verification = markTaskVerificationStale(
42886
+ context.task.verification,
42887
+ context.operationId,
42888
+ timestamp4
42889
+ );
42890
+ const releasedClaims = activeClaims2.map(
42891
+ (claim) => releaseClaimForReframe(claim, context.operationId, timestamp4)
42892
+ );
42893
+ const archiveAction = createTaskArchiveRecoveryAction({
42894
+ stepId: "archive-requirements-plan",
42895
+ taskRef,
42896
+ archiveId: context.operationId,
42897
+ sourceTaskRevision: context.task.metadata.revision,
42898
+ sourcePlanVersion: context.task.metadata.governance.planVersion,
42899
+ createdAt: timestamp4,
42900
+ requirementsContent: archivedRequirementsContent,
42901
+ planContent: context.task.plan?.content ?? null
42902
+ });
42903
+ const branch = await readCheckoutBranch(context.projectRoot);
42904
+ const checkpoint = buildReframeCheckpoint({
42905
+ context,
42906
+ checkpointId: input.checkpointId,
42907
+ taskRevision: pendingMetadata.revision + 1,
42908
+ requirements,
42909
+ review,
42910
+ verification,
42911
+ summary: input.summary,
42912
+ nextAction: input.nextAction,
42913
+ branch,
42914
+ timestamp: timestamp4
42915
+ });
42916
+ const metadata = completeReframeMetadata(
42917
+ pendingMetadata,
42918
+ requirements,
42919
+ review,
42920
+ verification,
42921
+ checkpoint,
42922
+ context.operationId,
42923
+ timestamp4
42924
+ );
42925
+ const aggregate = buildTaskAggregateManifest({
42926
+ metadata,
42927
+ requirements,
42928
+ review,
42929
+ verification,
42930
+ planDigest: context.task.plan?.digest ?? null,
42931
+ latestCheckpoint: checkpoint
42932
+ });
42933
+ const taskHeadFence = nextTaskHeadFence(context, aggregate, timestamp4);
42934
+ const refreshesSessionPointer = context.session.activeTaskRef !== null && sameTaskRef(context.session.activeTaskRef, taskRef);
42935
+ if (refreshesSessionPointer) {
42936
+ await enqueueSessionPointerProjection(context.projectRoot, {
42937
+ operationId: context.operationId,
42938
+ action: "resume",
42939
+ sessionId: context.session.sessionId,
42940
+ expectedPreviousTaskRef: context.session.activeTaskRef,
42941
+ taskRef,
42942
+ workflowMode: metadata.workflowMode,
42943
+ taskRevision: metadata.revision,
42944
+ now: context.now
42945
+ });
42946
+ }
42947
+ journal = await createTaskOperationJournal(context, {
42948
+ type: "reframe",
42949
+ action: taskRef.namespace === "shared" ? "shared_metadata_plan_mutation" : "local_workflow_mutation",
42950
+ expectedRevisions: reframeExpectedRevisions(
42951
+ context,
42952
+ input.checkpointId,
42953
+ activeClaims2
42954
+ ),
42955
+ recovery: {
42956
+ actions: [
42957
+ createTaskAuthorityFileRecoveryAction({
42958
+ stepId: "mark-task-operation-pending",
42959
+ taskRef,
42960
+ fileName: "metadata.json",
42961
+ beforeContent: serializeTaskAuthority(context.task.metadata),
42962
+ targetContent: serializeTaskAuthority(pendingMetadata)
42963
+ }),
42964
+ archiveAction,
42965
+ ...releasedClaims.map(
42966
+ (claim, index) => createClaimRecoveryAction({
42967
+ stepId: "release-active-claims",
42968
+ before: activeClaims2[index] ?? null,
42969
+ claim
42970
+ })
42971
+ ),
42972
+ createTaskAuthorityFileRecoveryAction({
42973
+ stepId: "write-requirements-draft",
42974
+ taskRef,
42975
+ fileName: "requirements.json",
42976
+ beforeContent: serializeTaskAuthority(context.task.requirements),
42977
+ targetContent: serializeTaskAuthority(requirements)
42978
+ }),
42979
+ createTaskAuthorityFileRecoveryAction({
42980
+ stepId: "mark-review-verification-stale",
42981
+ taskRef,
42982
+ fileName: "review-ledger.json",
42983
+ beforeContent: serializeTaskAuthority(context.task.review),
42984
+ targetContent: serializeTaskAuthority(review)
42985
+ }),
42986
+ createTaskAuthorityFileRecoveryAction({
42987
+ stepId: "mark-review-verification-stale",
42988
+ taskRef,
42989
+ fileName: "verification-ledger.json",
42990
+ beforeContent: serializeTaskAuthority(context.task.verification),
42991
+ targetContent: serializeTaskAuthority(verification)
42992
+ }),
42993
+ createCheckpointRecoveryAction({
42994
+ stepId: "write-reframe-checkpoint",
42995
+ before: null,
42996
+ checkpoint
42997
+ }),
42998
+ createTaskAuthorityFileRecoveryAction({
42999
+ stepId: "commit-reframed-metadata",
43000
+ taskRef,
43001
+ fileName: "metadata.json",
43002
+ beforeContent: serializeTaskAuthority(pendingMetadata),
43003
+ targetContent: serializeTaskAuthority(metadata)
43004
+ }),
43005
+ ...taskHeadFence === null ? [] : [
43006
+ createTaskHeadFenceRecoveryAction({
43007
+ stepId: "update-task-head-fence",
43008
+ before: context.coordination.taskHeadFence,
43009
+ fence: taskHeadFence
43010
+ })
43011
+ ]
43012
+ ],
43013
+ noOpStepIds: [
43014
+ ...releasedClaims.length === 0 ? ["release-active-claims"] : [],
43015
+ ...taskHeadFence === null ? ["update-task-head-fence"] : []
43016
+ ]
43017
+ }
43018
+ });
43019
+ journal = await advanceTaskOperation(context, journal, "validate", true);
43020
+ journal = await advanceTaskOperation(
43021
+ context,
43022
+ journal,
43023
+ "mark-task-operation-pending",
43024
+ false
43025
+ );
43026
+ await assertReframeCodeHeadUnchanged(context);
43027
+ await writeTaskAuthorityFile(
43028
+ context,
43029
+ "metadata.json",
43030
+ serializeTaskAuthority(pendingMetadata)
43031
+ );
43032
+ journal = await advanceTaskOperation(
43033
+ context,
43034
+ journal,
43035
+ "archive-requirements-plan",
43036
+ false
43037
+ );
43038
+ await assertReframeCodeHeadUnchanged(context);
43039
+ await writeTaskArchive(context, archiveAction);
43040
+ journal = await advanceTaskOperation(
43041
+ context,
43042
+ journal,
43043
+ "release-active-claims",
43044
+ false
43045
+ );
43046
+ await assertReframeCodeHeadUnchanged(context);
43047
+ for (const [index, claim] of releasedClaims.entries()) {
43048
+ const previous = activeClaims2[index];
43049
+ if (previous === void 0) throw new Error("MANCODE_CLAIM_SET_CHANGED");
43050
+ await updateClaim(context.homeStore, claim, previous.revision);
43051
+ }
43052
+ journal = await advanceTaskOperation(
43053
+ context,
43054
+ journal,
43055
+ "write-requirements-draft",
42259
43056
  false
42260
43057
  );
42261
43058
  await assertReframeCodeHeadUnchanged(context);
@@ -42612,6 +43409,9 @@ async function writeV3Requirements(input, action) {
42612
43409
  if (action === "finalize" && submitted.status !== "confirmed") {
42613
43410
  throw new Error("MANCODE_REQUIREMENTS_CONFIRMATION_REQUIRED");
42614
43411
  }
43412
+ if (action === "finalize") {
43413
+ assertRequirementsScopeConsistent(submitted);
43414
+ }
42615
43415
  if (action === "draft" && submitted.status !== "draft") {
42616
43416
  throw new Error("MANCODE_REQUIREMENTS_DRAFT_REQUIRED");
42617
43417
  }
@@ -42884,454 +43684,95 @@ async function applyV3ReviewLedger(input) {
42884
43684
  journal = await createTaskOperationJournal(context, {
42885
43685
  type: "review_remediation",
42886
43686
  action: authorization.action,
42887
- evidence: authorization.evidence,
42888
- conditions: authorization.conditions,
42889
- expectedRevisions: taskMutationExpectedRevisions(context, [
42890
- "review",
42891
- "verification"
42892
- ]),
42893
- recovery: {
42894
- actions: [
42895
- createTaskAuthorityFileRecoveryAction({
42896
- stepId: "write-review-ledger",
42897
- taskRef,
42898
- fileName: "review-ledger.json",
42899
- beforeContent: serializeTaskAuthority(context.task.review),
42900
- targetContent: serializeTaskAuthority(review)
42901
- }),
42902
- createTaskAuthorityFileRecoveryAction({
42903
- stepId: "mark-verification-stale",
42904
- taskRef,
42905
- fileName: "verification-ledger.json",
42906
- beforeContent: serializeTaskAuthority(context.task.verification),
42907
- targetContent: serializeTaskAuthority(verification)
42908
- }),
42909
- createTaskAuthorityFileRecoveryAction({
42910
- stepId: "update-metadata",
42911
- taskRef,
42912
- fileName: "metadata.json",
42913
- beforeContent: serializeTaskAuthority(context.task.metadata),
42914
- targetContent: serializeTaskAuthority(metadata)
42915
- }),
42916
- ...taskHeadFence === null ? [] : [
42917
- createTaskHeadFenceRecoveryAction({
42918
- stepId: "update-task-head-fence",
42919
- before: context.coordination.taskHeadFence,
42920
- fence: taskHeadFence
42921
- })
42922
- ]
42923
- ],
42924
- noOpStepIds: taskHeadFence === null ? ["update-task-head-fence"] : []
42925
- }
42926
- });
42927
- journal = await advanceTaskOperation(context, journal, "validate", true);
42928
- journal = await advanceTaskOperation(
42929
- context,
42930
- journal,
42931
- "write-review-ledger",
42932
- false
42933
- );
42934
- await writeTaskAuthorityFile(
42935
- context,
42936
- "review-ledger.json",
42937
- serializeTaskAuthority(review)
42938
- );
42939
- journal = await advanceTaskOperation(
42940
- context,
42941
- journal,
42942
- "mark-verification-stale",
42943
- false
42944
- );
42945
- await writeTaskAuthorityFile(
42946
- context,
42947
- "verification-ledger.json",
42948
- serializeTaskAuthority(verification)
42949
- );
42950
- journal = await advanceTaskOperation(
42951
- context,
42952
- journal,
42953
- "update-metadata",
42954
- false
42955
- );
42956
- await writeTaskAuthorityFile(
42957
- context,
42958
- "metadata.json",
42959
- serializeTaskAuthority(metadata)
42960
- );
42961
- journal = await advanceTaskOperation(
42962
- context,
42963
- journal,
42964
- "update-task-head-fence",
42965
- false
42966
- );
42967
- if (taskHeadFence !== null) {
42968
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
42969
- await replaceTaskHeadFence(context.homeStore, taskHeadFence);
42970
- }
42971
- const operation = await commitTaskOperation(context, journal);
42972
- return {
42973
- metadata,
42974
- review,
42975
- verification,
42976
- aggregate,
42977
- taskHeadFence,
42978
- operation
42979
- };
42980
- } catch (error) {
42981
- if (journal !== null) {
42982
- try {
42983
- await handleTaskOperationFailure(context, journal);
42984
- } catch {
42985
- }
42986
- }
42987
- throw error;
42988
- } finally {
42989
- await context.release();
42990
- }
42991
- }
42992
- function assertReviewEligible(metadata, hasPlan) {
42993
- if (metadata.workflowMode !== "man" && metadata.workflowMode !== "manteam") {
42994
- throw new Error("MANCODE_REVIEW_WORKFLOW_MODE_INVALID");
42995
- }
42996
- if (metadata.status !== "in_progress" && metadata.status !== "blocked") {
42997
- throw new Error("MANCODE_REVIEW_WORKFLOW_NOT_ACTIVE");
42998
- }
42999
- if (metadata.currentStep < 5 || metadata.governance.planDecision !== "governed_execution" || !hasPlan) {
43000
- throw new Error("MANCODE_REVIEW_PLAN_GATE_REQUIRED");
43001
- }
43002
- }
43003
- function createCurrentReview(previous, submitted, metadata, operationId, updatedAt) {
43004
- if (submitted.requirementsDigest !== metadata.governance.requirementsDigest || submitted.planVersion !== metadata.governance.planVersion) {
43005
- throw new Error("MANCODE_REVIEW_CONTEXT_STALE");
43006
- }
43007
- const draft = {
43008
- ...submitted,
43009
- taskRef: previous.taskRef,
43010
- revision: previous.revision + 1,
43011
- contentDigest: "",
43012
- lastOperationId: operationId,
43013
- updatedAt
43014
- };
43015
- const next = parseReviewLedger({
43016
- ...draft,
43017
- contentDigest: reviewLedgerDigest(draft)
43018
- });
43019
- assertReviewLedgerTransition(previous, next);
43020
- assertReviewLedgerAgainstContext(next, {
43021
- requirementsDigest: metadata.governance.requirementsDigest,
43022
- planVersion: metadata.governance.planVersion
43023
- });
43024
- return next;
43025
- }
43026
- function updateMetadata3(previous, review, verification, operationId, updatedAt) {
43027
- const next = parseWorkflowMetadata({
43028
- ...previous,
43029
- revision: previous.revision + 1,
43030
- transitionState: "stable",
43031
- lastOperationId: operationId,
43032
- governance: {
43033
- ...previous.governance,
43034
- reviewStatus: review.status,
43035
- reviewLedgerDigest: review.contentDigest,
43036
- verificationStatus: verification.status,
43037
- verificationLedgerDigest: verification.contentDigest
43038
- },
43039
- updatedAt
43040
- });
43041
- assertWorkflowMetadataTransition(previous, next, "ordinary");
43042
- return next;
43043
- }
43044
- function reviewAuthorization(context, next) {
43045
- if (context.taskRef.namespace === "local") {
43046
- return { action: "local_workflow_mutation" };
43047
- }
43048
- if (next.skip !== null) {
43049
- return {
43050
- action: "review_skip_or_waiver",
43051
- conditions: { reviewAction: "skip", reason: next.skip.reason }
43052
- };
43053
- }
43054
- const waivers = next.blockers.filter(
43055
- (blocker) => blocker.status === "waived"
43056
- );
43057
- if (waivers.length > 0) {
43058
- for (const blocker of waivers) {
43059
- if (blocker.severity === "p0" || blocker.severity === "legacy_unknown" || blocker.waiver === null) {
43060
- throw new Error("MANCODE_WAIVER_FORBIDDEN");
43061
- }
43062
- }
43063
- const first = waivers[0];
43064
- if (first?.waiver === null || first === void 0) {
43065
- throw new Error("MANCODE_WAIVER_FORBIDDEN");
43066
- }
43067
- return {
43068
- action: "review_skip_or_waiver",
43069
- conditions: {
43070
- reviewAction: "waiver",
43071
- reviewSeverity: first.severity,
43072
- reason: first.waiver.reason
43073
- }
43074
- };
43075
- }
43076
- return {
43077
- action: "shared_ledger_evidence",
43078
- evidence: {
43079
- assignedToActor: context.task.metadata.ownerActorId === context.session.actorId,
43080
- restrictsWriteToAssignedItem: true
43081
- }
43082
- };
43083
- }
43084
-
43085
- // src/context/scope-change.ts
43086
- import { createHash as createHash11 } from "crypto";
43087
- async function changeV3WorkflowScope(input) {
43088
- const taskRef = parseTaskRefValue(input.taskRef);
43089
- if (taskRef.namespace !== "shared") {
43090
- throw new Error("MANCODE_SCOPE_CHANGE_REQUIRES_SHARED_TASK");
43091
- }
43092
- const scope = normalizeImplementationScope(input.scope);
43093
- const now = input.now ?? /* @__PURE__ */ new Date();
43094
- const timestamp4 = now.toISOString();
43095
- const checkpointId = input.checkpointId ?? createUlid(now.getTime());
43096
- const operationId = input.operationId ?? createUlid(now.getTime());
43097
- assertUlid(checkpointId, "scope change checkpointId");
43098
- assertUlid(operationId, "scope change operationId");
43099
- const opened = await openScopeChangeContext({
43100
- projectRoot: input.projectRoot,
43101
- taskRef,
43102
- sessionId: input.sessionId,
43103
- expectedTaskRevision: input.expectedTaskRevision,
43104
- scope,
43105
- checkpointId,
43106
- successorClaimIds: input.successorClaimIds,
43107
- operationId,
43108
- now
43109
- });
43110
- const { context, activeClaims: activeClaims2, successorClaimIds, successorPredecessors } = opened;
43111
- let journal = null;
43112
- try {
43113
- assertScopeChangeEligible(context, scope);
43114
- assertClaimsFreshForScopeChange(context, activeClaims2);
43115
- const pendingMetadata = markScopeChangeOperationPending(
43116
- context.task.metadata,
43117
- context.operationId,
43118
- timestamp4
43119
- );
43120
- const branch = await readCheckoutBranch(context.projectRoot) ?? "HEAD";
43121
- const checkpoint = buildScopeChangedCheckpoint(
43122
- context,
43123
- pendingMetadata,
43124
- checkpointId,
43125
- input.checkpointSummary,
43126
- input.checkpointNextAction,
43127
- branch,
43128
- timestamp4
43129
- );
43130
- const metadata = completeScopeChangeMetadata(
43131
- pendingMetadata,
43132
- scope,
43133
- checkpoint,
43134
- context.operationId,
43135
- timestamp4
43136
- );
43137
- const pendingSuccessorClaims = buildPendingSuccessorClaims2(
43138
- successorPredecessors,
43139
- successorClaimIds,
43140
- metadata,
43141
- branch,
43142
- requireCodeHead3(context),
43143
- context.operationId,
43144
- timestamp4,
43145
- capabilitiesFromProjectConfig(context.project.config)
43146
- );
43147
- const successorByPredecessor = new Map(
43148
- successorPredecessors.map((claim, index) => {
43149
- const successorClaimId = successorClaimIds[index];
43150
- if (successorClaimId === void 0) {
43151
- throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
43152
- }
43153
- return [claim.claimId, successorClaimId];
43154
- })
43155
- );
43156
- const terminatedClaims = activeClaims2.map(
43157
- (claim) => terminateClaimForScopeChange(
43158
- claim,
43159
- successorByPredecessor.get(claim.claimId) ?? null,
43160
- context.operationId,
43161
- timestamp4
43162
- )
43163
- );
43164
- const activeSuccessorClaims = pendingSuccessorClaims.map(
43165
- (claim) => activateSuccessorClaim3(claim, context.operationId, timestamp4)
43166
- );
43167
- const aggregate = buildTaskAggregateManifest({
43168
- metadata,
43169
- requirements: context.task.requirements,
43170
- review: context.task.review,
43171
- verification: context.task.verification,
43172
- planDigest: context.task.plan?.digest ?? null,
43173
- latestCheckpoint: checkpoint
43174
- });
43175
- const taskHeadFence = nextTaskHeadFence(context, aggregate, timestamp4);
43176
- if (taskHeadFence === null) {
43177
- throw new Error("MANCODE_TASK_HEAD_FENCE_MISSING");
43178
- }
43179
- journal = await createTaskOperationJournal(context, {
43180
- type: "scope_change_reclaim",
43181
- action: "task_complete_scope_change_child_merge",
43182
- expectedRevisions: scopeChangeExpectedRevisions(
43183
- context,
43184
- checkpointId,
43185
- activeClaims2,
43186
- successorClaimIds
43187
- ),
43188
- conditions: { completionGateSatisfied: true },
43687
+ evidence: authorization.evidence,
43688
+ conditions: authorization.conditions,
43689
+ expectedRevisions: taskMutationExpectedRevisions(context, [
43690
+ "review",
43691
+ "verification"
43692
+ ]),
43189
43693
  recovery: {
43190
43694
  actions: [
43191
43695
  createTaskAuthorityFileRecoveryAction({
43192
- stepId: "mark-task-operation-pending",
43696
+ stepId: "write-review-ledger",
43193
43697
  taskRef,
43194
- fileName: "metadata.json",
43195
- beforeContent: serializeTaskAuthority(context.task.metadata),
43196
- targetContent: serializeTaskAuthority(pendingMetadata)
43197
- }),
43198
- createCheckpointRecoveryAction({
43199
- stepId: "write-scope-changed-checkpoint",
43200
- before: null,
43201
- checkpoint
43698
+ fileName: "review-ledger.json",
43699
+ beforeContent: serializeTaskAuthority(context.task.review),
43700
+ targetContent: serializeTaskAuthority(review)
43202
43701
  }),
43203
- ...pendingSuccessorClaims.map(
43204
- (claim) => createClaimRecoveryAction({
43205
- stepId: "create-pending-successor-claims",
43206
- before: null,
43207
- claim
43208
- })
43209
- ),
43210
- ...terminatedClaims.map((claim, index) => {
43211
- const before = activeClaims2[index];
43212
- if (before === void 0) {
43213
- throw new Error("MANCODE_CLAIM_SET_CHANGED");
43214
- }
43215
- return createClaimRecoveryAction({
43216
- stepId: "terminate-old-claims",
43217
- before,
43218
- claim
43219
- });
43702
+ createTaskAuthorityFileRecoveryAction({
43703
+ stepId: "mark-verification-stale",
43704
+ taskRef,
43705
+ fileName: "verification-ledger.json",
43706
+ beforeContent: serializeTaskAuthority(context.task.verification),
43707
+ targetContent: serializeTaskAuthority(verification)
43220
43708
  }),
43221
43709
  createTaskAuthorityFileRecoveryAction({
43222
- stepId: "update-metadata-scope",
43710
+ stepId: "update-metadata",
43223
43711
  taskRef,
43224
43712
  fileName: "metadata.json",
43225
- beforeContent: serializeTaskAuthority(pendingMetadata),
43713
+ beforeContent: serializeTaskAuthority(context.task.metadata),
43226
43714
  targetContent: serializeTaskAuthority(metadata)
43227
43715
  }),
43228
- ...activeSuccessorClaims.map((claim, index) => {
43229
- const before = pendingSuccessorClaims[index];
43230
- if (before === void 0) {
43231
- throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
43232
- }
43233
- return createClaimRecoveryAction({
43234
- stepId: "activate-successor-claims",
43235
- before,
43236
- claim
43237
- });
43238
- }),
43239
- createTaskHeadFenceRecoveryAction({
43240
- stepId: "update-task-head-fence",
43241
- before: context.coordination.taskHeadFence,
43242
- fence: taskHeadFence
43243
- })
43716
+ ...taskHeadFence === null ? [] : [
43717
+ createTaskHeadFenceRecoveryAction({
43718
+ stepId: "update-task-head-fence",
43719
+ before: context.coordination.taskHeadFence,
43720
+ fence: taskHeadFence
43721
+ })
43722
+ ]
43244
43723
  ],
43245
- noOpStepIds: [
43246
- ...pendingSuccessorClaims.length === 0 ? ["create-pending-successor-claims"] : [],
43247
- ...terminatedClaims.length === 0 ? ["terminate-old-claims"] : [],
43248
- ...activeSuccessorClaims.length === 0 ? ["activate-successor-claims"] : []
43249
- ]
43724
+ noOpStepIds: taskHeadFence === null ? ["update-task-head-fence"] : []
43250
43725
  }
43251
43726
  });
43252
43727
  journal = await advanceTaskOperation(context, journal, "validate", true);
43253
43728
  journal = await advanceTaskOperation(
43254
43729
  context,
43255
43730
  journal,
43256
- "mark-task-operation-pending",
43731
+ "write-review-ledger",
43257
43732
  false
43258
43733
  );
43259
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43260
43734
  await writeTaskAuthorityFile(
43261
43735
  context,
43262
- "metadata.json",
43263
- `${JSON.stringify(pendingMetadata, null, 2)}
43264
- `
43265
- );
43266
- journal = await advanceTaskOperation(
43267
- context,
43268
- journal,
43269
- "write-scope-changed-checkpoint",
43270
- false
43736
+ "review-ledger.json",
43737
+ serializeTaskAuthority(review)
43271
43738
  );
43272
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43273
- await writeTaskCheckpoint(context, checkpoint);
43274
43739
  journal = await advanceTaskOperation(
43275
43740
  context,
43276
43741
  journal,
43277
- "create-pending-successor-claims",
43742
+ "mark-verification-stale",
43278
43743
  false
43279
43744
  );
43280
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43281
- for (const claim of pendingSuccessorClaims) {
43282
- await createClaim(context.homeStore, claim);
43283
- }
43284
- journal = await advanceTaskOperation(
43745
+ await writeTaskAuthorityFile(
43285
43746
  context,
43286
- journal,
43287
- "terminate-old-claims",
43288
- false
43747
+ "verification-ledger.json",
43748
+ serializeTaskAuthority(verification)
43289
43749
  );
43290
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43291
- for (const [index, claim] of terminatedClaims.entries()) {
43292
- const previous = activeClaims2[index];
43293
- if (previous === void 0) {
43294
- throw new Error("MANCODE_CLAIM_SET_CHANGED");
43295
- }
43296
- await updateClaim(context.homeStore, claim, previous.revision);
43297
- }
43298
43750
  journal = await advanceTaskOperation(
43299
43751
  context,
43300
43752
  journal,
43301
- "update-metadata-scope",
43753
+ "update-metadata",
43302
43754
  false
43303
43755
  );
43304
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43305
43756
  await writeTaskAuthorityFile(
43306
43757
  context,
43307
43758
  "metadata.json",
43308
- `${JSON.stringify(metadata, null, 2)}
43309
- `
43310
- );
43311
- journal = await advanceTaskOperation(
43312
- context,
43313
- journal,
43314
- "activate-successor-claims",
43315
- false
43759
+ serializeTaskAuthority(metadata)
43316
43760
  );
43317
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43318
- for (const claim of activeSuccessorClaims) {
43319
- await updateClaim(context.homeStore, claim, 1);
43320
- }
43321
43761
  journal = await advanceTaskOperation(
43322
43762
  context,
43323
43763
  journal,
43324
43764
  "update-task-head-fence",
43325
43765
  false
43326
43766
  );
43327
- await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43328
- await replaceTaskHeadFence(context.homeStore, taskHeadFence);
43767
+ if (taskHeadFence !== null) {
43768
+ await assertTaskCodeHeadUnchanged(context.projectRoot, context.codeHead);
43769
+ await replaceTaskHeadFence(context.homeStore, taskHeadFence);
43770
+ }
43329
43771
  const operation = await commitTaskOperation(context, journal);
43330
43772
  return {
43331
43773
  metadata,
43332
- checkpoint,
43333
- terminatedClaims,
43334
- successorClaims: activeSuccessorClaims,
43774
+ review,
43775
+ verification,
43335
43776
  aggregate,
43336
43777
  taskHeadFence,
43337
43778
  operation
@@ -43348,312 +43789,97 @@ async function changeV3WorkflowScope(input) {
43348
43789
  await context.release();
43349
43790
  }
43350
43791
  }
43351
- async function openScopeChangeContext(input) {
43352
- for (let attempt = 0; attempt < 3; attempt += 1) {
43353
- const runtime = await readProjectRuntimeContext(input.projectRoot);
43354
- const store = new V3ContextStore(input.projectRoot);
43355
- const homeStore = resolveTaskEntityHomeStore(
43356
- runtime.entityHomeStoreContext,
43357
- input.taskRef
43358
- );
43359
- const preflight = await store.readCoordinationSnapshot(
43360
- input.taskRef,
43361
- homeStore
43362
- );
43363
- const preflightClaims = activeClaims(preflight.claims);
43364
- const preflightSuccessors = claimsWithinScope(preflightClaims, input.scope);
43365
- const preflightSuccessorIds = resolveSuccessorClaimIds2(
43366
- preflightSuccessors,
43367
- input.successorClaimIds,
43368
- input.operationId,
43369
- input.now.toISOString()
43370
- );
43371
- const context = await openV3TaskOperation({
43372
- projectRoot: input.projectRoot,
43373
- taskRef: input.taskRef,
43374
- sessionId: input.sessionId,
43375
- expectedTaskRevision: input.expectedTaskRevision,
43376
- operationId: input.operationId,
43377
- extraEntityLocks: [
43378
- `checkpoint:${input.checkpointId}`,
43379
- taskHeadEntityKey(input.taskRef),
43380
- ...preflightClaims.map((claim) => `claim:${claim.claimId}`),
43381
- ...preflightSuccessorIds.map((claimId) => `claim:${claimId}`)
43382
- ],
43383
- now: input.now
43384
- });
43385
- const lockedClaims = activeClaims(context.coordination.claims);
43386
- if (sameClaimIdSet(preflightClaims, lockedClaims)) {
43387
- const successors = claimsWithinScope(lockedClaims, input.scope);
43388
- const successorIds = resolveSuccessorClaimIds2(
43389
- successors,
43390
- input.successorClaimIds,
43391
- input.operationId,
43392
- input.now.toISOString()
43393
- );
43394
- return {
43395
- context,
43396
- activeClaims: lockedClaims,
43397
- successorPredecessors: successors,
43398
- successorClaimIds: successorIds
43399
- };
43400
- }
43401
- await context.release();
43402
- }
43403
- throw new Error("MANCODE_CLAIM_SET_CHANGED");
43404
- }
43405
- function assertScopeChangeEligible(context, scope) {
43406
- const metadata = context.task.metadata;
43407
- if (context.project.config.transport.mode !== "local") {
43408
- throw new Error("MANCODE_GIT_REF_TRANSPORT_NOT_IMPLEMENTED");
43409
- }
43410
- if (metadata.workflowMode !== "manteam") {
43411
- throw new Error("MANCODE_SCOPE_CHANGE_WORKFLOW_MODE_INVALID");
43412
- }
43413
- if (metadata.status !== "in_progress") {
43414
- throw new Error("MANCODE_SCOPE_CHANGE_WORKFLOW_NOT_ACTIVE");
43415
- }
43416
- if (metadata.ownerActorId !== context.session.actorId) {
43417
- throw new Error("MANCODE_TASK_OWNER_REQUIRED");
43418
- }
43419
- if (metadata.parent !== null) {
43420
- throw new Error("MANCODE_PARENT_SCOPE_INHERITANCE_REQUIRED");
43421
- }
43422
- if (metadata.implementationScope.digest === scope.digest) {
43423
- throw new Error("MANCODE_SCOPE_CHANGE_NOOP");
43424
- }
43425
- }
43426
- function assertClaimsFreshForScopeChange(context, claims) {
43427
- const codeHead = requireCodeHead3(context);
43428
- for (const claim of claims) {
43429
- if (claim.authority.mode !== "local") {
43430
- throw new Error("MANCODE_OPERATION_REPAIR_REQUIRED");
43431
- }
43432
- const validity = deriveClaimValidity(claim, {
43433
- taskRef: context.taskRef,
43434
- taskRevision: context.task.metadata.revision,
43435
- implementationScopeDigest: context.task.metadata.implementationScope.digest,
43436
- ownershipEpoch: context.task.metadata.ownershipEpoch,
43437
- codeRefHead: codeHead,
43438
- now: context.now,
43439
- transportFreshness: "fresh"
43440
- });
43441
- if (validity !== "fresh") {
43442
- throw new Error("MANCODE_CLAIM_REVALIDATION_REQUIRED");
43443
- }
43444
- }
43445
- }
43446
- function normalizeImplementationScope(value) {
43447
- assertRecord(value, "workflow scope change");
43448
- assertKnownKeys(
43449
- value,
43450
- ["include", "exclude", "modules"],
43451
- "workflow scope change"
43452
- );
43453
- const scope = {
43454
- source: "explicit",
43455
- include: normalizeScopeValues(value.include, "include", true),
43456
- exclude: normalizeScopeValues(value.exclude, "exclude", true),
43457
- modules: normalizeScopeValues(value.modules, "modules", false)
43458
- };
43459
- return { ...scope, digest: digestCanonicalJson(scope) };
43460
- }
43461
- function normalizeScopeValues(value, label, paths) {
43462
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
43463
- throw new Error(`MANCODE_SCOPE_${label.toUpperCase()}_INVALID`);
43792
+ function assertReviewEligible(metadata, hasPlan) {
43793
+ if (metadata.workflowMode !== "man" && metadata.workflowMode !== "manteam") {
43794
+ throw new Error("MANCODE_REVIEW_WORKFLOW_MODE_INVALID");
43464
43795
  }
43465
- const values = value.map((item) => item.trim());
43466
- const normalized = sortUtf8StringSet(values);
43467
- if (normalized.length !== values.length) {
43468
- throw new Error(`MANCODE_SCOPE_${label.toUpperCase()}_DUPLICATE`);
43796
+ if (metadata.status !== "in_progress" && metadata.status !== "blocked") {
43797
+ throw new Error("MANCODE_REVIEW_WORKFLOW_NOT_ACTIVE");
43469
43798
  }
43470
- for (const item of normalized) {
43471
- assertSharedTextSafe(item, `workflow scope ${label}`);
43472
- if (paths) assertScopePath(item);
43799
+ if (metadata.currentStep < 5 || metadata.governance.planDecision !== "governed_execution" || !hasPlan) {
43800
+ throw new Error("MANCODE_REVIEW_PLAN_GATE_REQUIRED");
43473
43801
  }
43474
- return normalized;
43475
43802
  }
43476
- function assertScopePath(value) {
43477
- if (value.startsWith("/") || value.startsWith("~") || /^[A-Za-z]:/.test(value) || value.includes("\\") || value.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) {
43478
- throw new Error("MANCODE_SCOPE_PATH_INVALID");
43803
+ function createCurrentReview(previous, submitted, metadata, operationId, updatedAt) {
43804
+ if (submitted.requirementsDigest !== metadata.governance.requirementsDigest || submitted.planVersion !== metadata.governance.planVersion) {
43805
+ throw new Error("MANCODE_REVIEW_CONTEXT_STALE");
43479
43806
  }
43480
- }
43481
- function markScopeChangeOperationPending(previous, operationId, updatedAt) {
43482
- const next = parseWorkflowMetadata({
43483
- ...previous,
43807
+ const draft = {
43808
+ ...submitted,
43809
+ taskRef: previous.taskRef,
43484
43810
  revision: previous.revision + 1,
43485
- transitionState: "operation_pending",
43811
+ contentDigest: "",
43486
43812
  lastOperationId: operationId,
43487
43813
  updatedAt
43814
+ };
43815
+ const next = parseReviewLedger({
43816
+ ...draft,
43817
+ contentDigest: reviewLedgerDigest(draft)
43818
+ });
43819
+ assertReviewLedgerTransition(previous, next);
43820
+ assertReviewLedgerAgainstContext(next, {
43821
+ requirementsDigest: metadata.governance.requirementsDigest,
43822
+ planVersion: metadata.governance.planVersion
43488
43823
  });
43489
- assertWorkflowMetadataTransition(previous, next, "ordinary");
43490
43824
  return next;
43491
43825
  }
43492
- function completeScopeChangeMetadata(previous, scope, checkpoint, operationId, updatedAt) {
43826
+ function updateMetadata3(previous, review, verification, operationId, updatedAt) {
43493
43827
  const next = parseWorkflowMetadata({
43494
43828
  ...previous,
43495
43829
  revision: previous.revision + 1,
43496
43830
  transitionState: "stable",
43497
- implementationScope: scope,
43498
- latestCheckpointRef: {
43499
- taskRef: checkpoint.taskRef,
43500
- kind: "checkpoint",
43501
- artifactId: checkpoint.checkpointId
43502
- },
43503
43831
  lastOperationId: operationId,
43504
- updatedAt
43505
- });
43506
- assertWorkflowMetadataTransition(previous, next, "ordinary");
43507
- return next;
43508
- }
43509
- function buildScopeChangedCheckpoint(context, pendingMetadata, checkpointId, summary, nextAction, branch, timestamp4) {
43510
- return parseCheckpoint({
43511
- schemaVersion: 1,
43512
- checkpointId,
43513
- operationId: context.operationId,
43514
- taskRef: context.taskRef,
43515
- taskRevision: pendingMetadata.revision,
43516
- ownershipEpochAtOffer: pendingMetadata.ownershipEpoch,
43517
- kind: "scope_changed",
43518
- git: {
43519
- branch,
43520
- head: requireCodeHead3(context),
43521
- base: pendingMetadata.base?.head ?? null
43522
- },
43523
- summary: summary ?? "Changed the implementation scope and replaced affected coordination claims.",
43524
43832
  governance: {
43525
- requirementsDigest: context.task.requirements.contentDigest,
43526
- planVersion: pendingMetadata.governance.planVersion,
43527
- reviewLedgerDigest: context.task.review.contentDigest,
43528
- verificationLedgerDigest: context.task.verification.contentDigest
43529
- },
43530
- nextAction: nextAction ?? "Re-read the updated scope and continue only with the successor claim.",
43531
- createdBy: {
43532
- actorId: context.session.actorId,
43533
- client: context.session.client
43833
+ ...previous.governance,
43834
+ reviewStatus: review.status,
43835
+ reviewLedgerDigest: review.contentDigest,
43836
+ verificationStatus: verification.status,
43837
+ verificationLedgerDigest: verification.contentDigest
43534
43838
  },
43535
- createdAt: timestamp4
43536
- });
43537
- }
43538
- function buildPendingSuccessorClaims2(predecessors, successorClaimIds, metadata, branch, codeHead, operationId, timestamp4, capabilities) {
43539
- return predecessors.map((previous, index) => {
43540
- const claimId = successorClaimIds[index];
43541
- if (claimId === void 0) {
43542
- throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
43543
- }
43544
- return parseClaim({
43545
- ...previous,
43546
- claimId,
43547
- authority: { mode: "local", remoteRevision: null },
43548
- taskRevisionAtAcquire: metadata.revision,
43549
- lastValidatedTaskRevision: metadata.revision,
43550
- implementationScopeDigest: metadata.implementationScope.digest,
43551
- ownershipEpochAtAcquire: metadata.ownershipEpoch,
43552
- state: "pending",
43553
- revision: 1,
43554
- codeRefAtAcquire: { branch, head: codeHead },
43555
- lastValidatedCodeRef: { branch, head: codeHead },
43556
- acquisitionEnforcement: capabilities.claimAcquisition,
43557
- writeGuard: capabilities.writeGuard,
43558
- predecessorClaimId: previous.claimId,
43559
- successorClaimId: null,
43560
- lastOperationId: operationId,
43561
- createdAt: timestamp4,
43562
- updatedAt: timestamp4
43563
- });
43564
- });
43565
- }
43566
- function terminateClaimForScopeChange(previous, successorClaimId, operationId, timestamp4) {
43567
- const next = parseClaim({
43568
- ...previous,
43569
- state: successorClaimId === null ? "released" : "transferred",
43570
- revision: previous.revision + 1,
43571
- successorClaimId,
43572
- lastOperationId: operationId,
43573
- updatedAt: timestamp4
43574
- });
43575
- assertClaimTransition(previous, next);
43576
- return next;
43577
- }
43578
- function activateSuccessorClaim3(previous, operationId, timestamp4) {
43579
- const next = parseClaim({
43580
- ...previous,
43581
- state: "active",
43582
- revision: previous.revision + 1,
43583
- lastOperationId: operationId,
43584
- updatedAt: timestamp4
43839
+ updatedAt
43585
43840
  });
43586
- assertClaimTransition(previous, next);
43841
+ assertWorkflowMetadataTransition(previous, next, "ordinary");
43587
43842
  return next;
43588
43843
  }
43589
- function scopeChangeExpectedRevisions(context, checkpointId, predecessors, successorClaimIds) {
43590
- const expected = {
43591
- [taskEntityKey(context.taskRef)]: context.task.metadata.revision,
43592
- [`checkpoint:${checkpointId}`]: 0
43593
- };
43594
- for (const claim of predecessors) {
43595
- expected[`claim:${claim.claimId}`] = claim.revision;
43844
+ function reviewAuthorization(context, next) {
43845
+ if (context.taskRef.namespace === "local") {
43846
+ return { action: "local_workflow_mutation" };
43596
43847
  }
43597
- for (const claimId of successorClaimIds) {
43598
- expected[`claim:${claimId}`] = 0;
43848
+ if (next.skip !== null) {
43849
+ return {
43850
+ action: "review_skip_or_waiver",
43851
+ conditions: { reviewAction: "skip", reason: next.skip.reason }
43852
+ };
43599
43853
  }
43600
- const fence = context.coordination.taskHeadFence;
43601
- if (fence === null) throw new Error("MANCODE_TASK_HEAD_FENCE_MISSING");
43602
- expected[taskHeadEntityKey(context.taskRef)] = fence.fenceRevision;
43603
- return expected;
43604
- }
43605
- function activeClaims(claims) {
43606
- return claims.filter((claim) => claim.state === "active").sort((left, right) => compareUtf815(left.claimId, right.claimId));
43607
- }
43608
- function claimsWithinScope(claims, scope) {
43609
- return claims.filter(
43610
- (claim) => evaluateClaimScopeSubset(claim.scope, {
43611
- source: scope.source,
43612
- include: scope.include,
43613
- exclude: scope.exclude,
43614
- modules: scope.modules
43615
- }).allowed
43616
- );
43617
- }
43618
- function resolveSuccessorClaimIds2(predecessors, requested, operationId, timestamp4) {
43619
- const ids = requested ?? predecessors.map(
43620
- (claim) => scopeSuccessorClaimId(operationId, claim.claimId, timestamp4)
43854
+ const waivers = next.blockers.filter(
43855
+ (blocker) => blocker.status === "waived"
43621
43856
  );
43622
- if (ids.length !== predecessors.length) {
43623
- throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_COUNT_INVALID");
43624
- }
43625
- const predecessorIds = new Set(predecessors.map((claim) => claim.claimId));
43626
- const seen = /* @__PURE__ */ new Set();
43627
- for (const claimId of ids) {
43628
- assertUlid(claimId, "scope successor claimId");
43629
- if (predecessorIds.has(claimId) || seen.has(claimId)) {
43630
- throw new Error("MANCODE_SCOPE_SUCCESSOR_CLAIM_INVALID");
43857
+ if (waivers.length > 0) {
43858
+ for (const blocker of waivers) {
43859
+ if (blocker.severity === "p0" || blocker.severity === "legacy_unknown" || blocker.waiver === null) {
43860
+ throw new Error("MANCODE_WAIVER_FORBIDDEN");
43861
+ }
43631
43862
  }
43632
- seen.add(claimId);
43633
- }
43634
- return ids;
43635
- }
43636
- function scopeSuccessorClaimId(operationId, predecessorClaimId, timestamp4) {
43637
- assertUlid(operationId, "scope change operationId");
43638
- assertUlid(predecessorClaimId, "scope predecessor claimId");
43639
- const milliseconds = Date.parse(timestamp4);
43640
- if (Number.isNaN(milliseconds)) {
43641
- throw new Error("MANCODE_SCOPE_TIMESTAMP_INVALID");
43642
- }
43643
- const entropy = createHash11("sha256").update(`scope-change:${operationId}:${predecessorClaimId}`, "utf8").digest().subarray(0, 10);
43644
- return createUlid(milliseconds, entropy);
43645
- }
43646
- function requireCodeHead3(context) {
43647
- if (context.codeHead === null) {
43648
- throw new Error("MANCODE_TASK_HEAD_CODE_REF_UNAVAILABLE");
43863
+ const first = waivers[0];
43864
+ if (first?.waiver === null || first === void 0) {
43865
+ throw new Error("MANCODE_WAIVER_FORBIDDEN");
43866
+ }
43867
+ return {
43868
+ action: "review_skip_or_waiver",
43869
+ conditions: {
43870
+ reviewAction: "waiver",
43871
+ reviewSeverity: first.severity,
43872
+ reason: first.waiver.reason
43873
+ }
43874
+ };
43649
43875
  }
43650
- return context.codeHead;
43651
- }
43652
- function sameClaimIdSet(left, right) {
43653
- return left.length === right.length && left.every((claim, index) => claim.claimId === right[index]?.claimId);
43654
- }
43655
- function compareUtf815(left, right) {
43656
- return Buffer.from(left, "utf8").compare(Buffer.from(right, "utf8"));
43876
+ return {
43877
+ action: "shared_ledger_evidence",
43878
+ evidence: {
43879
+ assignedToActor: context.task.metadata.ownerActorId === context.session.actorId,
43880
+ restrictsWriteToAssignedItem: true
43881
+ }
43882
+ };
43657
43883
  }
43658
43884
 
43659
43885
  // src/context/solo-handoff.ts
@@ -43903,6 +44129,8 @@ function assertSoloStartEligible(context) {
43903
44129
  if (metadata.workflowMode !== "man" || metadata.coordination !== "single" || metadata.status !== "in_progress" || metadata.currentStep !== 4 || metadata.governance.planDecision !== null || metadata.soloExecution !== null || metadata.ownerActorId !== context.session.actorId || plan === null || requirements.status !== "confirmed" || !requirementsAreReady(requirements) || metadata.governance.requirementsStatus !== "ready" || metadata.governance.requirementsDigest !== requirements.contentDigest) {
43904
44130
  throw new Error("MANCODE_SOLO_HANDOFF_NOT_ELIGIBLE");
43905
44131
  }
44132
+ assertRequirementsScopeConsistent(requirements);
44133
+ assertExecutableImplementationScope(metadata.implementationScope);
43906
44134
  }
43907
44135
  function assertSoloCompletionEligible(context) {
43908
44136
  const { metadata } = context.task;
@@ -45191,11 +45419,20 @@ function initialScope(parent, explicitScope) {
45191
45419
  };
45192
45420
  return { ...inherited, digest: digestCanonicalJson(inherited) };
45193
45421
  }
45422
+ if (explicitScope === void 0) {
45423
+ const unspecified = {
45424
+ source: "legacy_unspecified",
45425
+ include: [],
45426
+ exclude: [],
45427
+ modules: []
45428
+ };
45429
+ return { ...unspecified, digest: digestCanonicalJson(unspecified) };
45430
+ }
45194
45431
  const explicit = {
45195
45432
  source: "explicit",
45196
- include: [...explicitScope?.include ?? []],
45197
- exclude: [...explicitScope?.exclude ?? []],
45198
- modules: [...explicitScope?.modules ?? []]
45433
+ include: [...explicitScope.include ?? []],
45434
+ exclude: [...explicitScope.exclude ?? []],
45435
+ modules: [...explicitScope.modules ?? []]
45199
45436
  };
45200
45437
  return { ...explicit, digest: digestCanonicalJson(explicit) };
45201
45438
  }
@@ -45657,10 +45894,22 @@ async function changeGitRefWorkflowScope(input) {
45657
45894
  operationId,
45658
45895
  timestamp4
45659
45896
  );
45897
+ const review = markTaskReviewStale(
45898
+ opened.context.task.review,
45899
+ operationId,
45900
+ timestamp4
45901
+ );
45902
+ const verification = markTaskVerificationStale(
45903
+ opened.context.task.verification,
45904
+ operationId,
45905
+ timestamp4
45906
+ );
45660
45907
  const metadata = scopeChangedMetadata(
45661
45908
  pendingMetadata,
45662
45909
  scope,
45663
45910
  checkpointId,
45911
+ review.contentDigest,
45912
+ verification.contentDigest,
45664
45913
  operationId,
45665
45914
  timestamp4
45666
45915
  );
@@ -45671,6 +45920,9 @@ async function changeGitRefWorkflowScope(input) {
45671
45920
  summary: input.checkpointSummary,
45672
45921
  nextAction: input.checkpointNextAction,
45673
45922
  codeRef: opened.bundle.codeRef,
45923
+ planVersion: pendingMetadata.governance.planVersion + 1,
45924
+ reviewLedgerDigest: review.contentDigest,
45925
+ verificationLedgerDigest: verification.contentDigest,
45674
45926
  timestamp: timestamp4
45675
45927
  });
45676
45928
  const finalMetadata = parseWorkflowMetadata({
@@ -45684,8 +45936,8 @@ async function changeGitRefWorkflowScope(input) {
45684
45936
  const aggregate = buildTaskAggregateManifest({
45685
45937
  metadata: finalMetadata,
45686
45938
  requirements: opened.context.task.requirements,
45687
- review: opened.context.task.review,
45688
- verification: opened.context.task.verification,
45939
+ review,
45940
+ verification,
45689
45941
  planDigest: opened.context.task.plan?.digest ?? null,
45690
45942
  latestCheckpoint: checkpoint
45691
45943
  });
@@ -45708,6 +45960,8 @@ async function changeGitRefWorkflowScope(input) {
45708
45960
  task: {
45709
45961
  ...opened.context.task,
45710
45962
  metadata: finalMetadata,
45963
+ review,
45964
+ verification,
45711
45965
  latestCheckpoint: checkpoint,
45712
45966
  aggregate
45713
45967
  },
@@ -46127,12 +46381,20 @@ function assertClaimsFresh(context, bundle, claims) {
46127
46381
  }
46128
46382
  }
46129
46383
  }
46130
- function scopeChangedMetadata(previous, scope, checkpointId, operationId, updatedAt) {
46384
+ function scopeChangedMetadata(previous, scope, checkpointId, reviewLedgerDigest2, verificationLedgerDigest2, operationId, updatedAt) {
46131
46385
  const next = parseWorkflowMetadata({
46132
46386
  ...previous,
46133
46387
  revision: previous.revision + 1,
46134
46388
  transitionState: "stable",
46135
46389
  implementationScope: scope,
46390
+ governance: {
46391
+ ...previous.governance,
46392
+ planVersion: previous.governance.planVersion + 1,
46393
+ reviewStatus: "stale",
46394
+ reviewLedgerDigest: reviewLedgerDigest2,
46395
+ verificationStatus: "stale",
46396
+ verificationLedgerDigest: verificationLedgerDigest2
46397
+ },
46136
46398
  latestCheckpointRef: {
46137
46399
  taskRef: previous.taskRef,
46138
46400
  kind: "checkpoint",
@@ -46161,9 +46423,9 @@ function scopeChangedCheckpoint(input) {
46161
46423
  summary: input.summary ?? "Changed the implementation scope and replaced affected coordination claims.",
46162
46424
  governance: {
46163
46425
  requirementsDigest: input.context.task.requirements.contentDigest,
46164
- planVersion: input.metadata.governance.planVersion,
46165
- reviewLedgerDigest: input.context.task.review.contentDigest,
46166
- verificationLedgerDigest: input.context.task.verification.contentDigest
46426
+ planVersion: input.planVersion,
46427
+ reviewLedgerDigest: input.reviewLedgerDigest,
46428
+ verificationLedgerDigest: input.verificationLedgerDigest
46167
46429
  },
46168
46430
  nextAction: input.nextAction ?? "Re-read the updated scope and continue only with the successor claim.",
46169
46431
  createdBy: {
@@ -47354,7 +47616,7 @@ async function workflowPlanV3(rootDir, args, options) {
47354
47616
  return printV3Error(
47355
47617
  options.json,
47356
47618
  "MANCODE_PLAN_ARGUMENT_INVALID",
47357
- "Use: workflow plan <namespace:ULID> revise --expected-revision <n> --file <path>, or confirm --expected-revision <n> --plan-decision <plan_only|governed_execution>.",
47619
+ "Use: workflow plan <namespace:ULID> revise --expected-revision <n> --file <path> [--scope-file <path>], or confirm --expected-revision <n> --plan-decision <plan_only|governed_execution>.",
47358
47620
  EXIT_INVALID_ARG3
47359
47621
  );
47360
47622
  }
@@ -47383,6 +47645,14 @@ async function workflowPlanV3(rootDir, args, options) {
47383
47645
  EXIT_INVALID_ARG3
47384
47646
  );
47385
47647
  }
47648
+ if (action === "confirm" && options.scopeFile !== void 0) {
47649
+ return printV3Error(
47650
+ options.json,
47651
+ "MANCODE_PLAN_SCOPE_REVISE_REQUIRED",
47652
+ "Bind implementation scope with workflow plan revise before confirmation.",
47653
+ EXIT_INVALID_ARG3
47654
+ );
47655
+ }
47386
47656
  try {
47387
47657
  const project = await readV3CommandProject(rootDir);
47388
47658
  const taskRef = parseTaskRef(task);
@@ -47399,12 +47669,17 @@ async function workflowPlanV3(rootDir, args, options) {
47399
47669
  if (plan === void 0 || plan === null) {
47400
47670
  throw new Error("MANCODE_PLAN_FILE_REQUIRED");
47401
47671
  }
47672
+ const implementationScope = action === "revise" && options.scopeFile !== void 0 ? await readWorkflowJsonInputFile(
47673
+ project.projectRoot,
47674
+ options.scopeFile
47675
+ ) : void 0;
47402
47676
  const result2 = await reviseV3Plan({
47403
47677
  projectRoot: project.projectRoot,
47404
47678
  taskRef,
47405
47679
  sessionId: session.sessionId,
47406
47680
  expectedTaskRevision,
47407
47681
  plan,
47682
+ implementationScope,
47408
47683
  planDecision: parseV3PlanDecision(options.planDecision)
47409
47684
  });
47410
47685
  return printV3Result(options.json, {
@@ -47657,6 +47932,7 @@ async function workflowRequirements(rootDir, args, options) {
47657
47932
  const inputPath = path69.isAbsolute(options.file) ? options.file : path69.resolve(rootDir, options.file);
47658
47933
  const input = await readFile48(inputPath, "utf-8");
47659
47934
  const requirements = parseRequirementsLedger2(input);
47935
+ assertRequirementsScopeConsistent2(requirements);
47660
47936
  [originalJson, originalMarkdown, originalMetadata] = await Promise.all([
47661
47937
  readOptionalText2(jsonPath),
47662
47938
  readOptionalText2(markdownPath),
@@ -48841,6 +49117,9 @@ program.command("workflow <subcommand> [args...]").description("Manage mancode w
48841
49117
  ).option(
48842
49118
  "--file <path>",
48843
49119
  "Semantic requirements JSON, plan Markdown, or ledger input file"
49120
+ ).option(
49121
+ "--scope-file <path>",
49122
+ "Plan implementation scope JSON {include,exclude,modules}"
48844
49123
  ).option("--acceptance <id>", "Acceptance criterion id (for example AC-1)").option("--method <method>", "Verification method: automated or manual").option("--result <result>", "Verification result").option("--evidence <text>", "Verification evidence or user confirmation").option("--command <command>", "Command used for automated verification").option("--exit-code <code>", "Exit code from automated verification").option("--evidence-file <path>", "Existing verification report or artifact").option("--reason <reason>", "Reason for an explicit review skip").option("--json", "Output as JSON (for scripts)").action(async (subcommand, args, options) => {
48845
49124
  const code = await workflow(process.cwd(), subcommand, args ?? [], {
48846
49125
  ...options,
@@ -49174,7 +49453,10 @@ designProgram.command("context").description("Emit bounded UI design context for
49174
49453
  designProgram.command("configure").description("CAS-update the optional project design policy").requiredOption(
49175
49454
  "--expected-revision <n>",
49176
49455
  "Current policy revision; use 0 when absent"
49177
- ).option("--preset <preset>", "preserve, refine, or experimental").option("--icons <policy>", "existing-first or lucide").option("--emoji <policy>", "allow or forbid-as-interface-icon").option("--motion <policy>", "minimal or purposeful").option("--browser-validation <mode>", "off, when-available, or required").option("--confirm-experimental", "Explicitly allow the experimental preset").option("--json", "Output as JSON (for scripts)").action(async (options) => {
49456
+ ).option("--preset <preset>", "preserve, refine, or experimental").option("--icons <policy>", "existing-first or lucide").option(
49457
+ "--emoji <policy>",
49458
+ "forbid-as-interface-icon; legacy allow is normalized"
49459
+ ).option("--motion <policy>", "minimal or purposeful").option("--browser-validation <mode>", "off, when-available, or required").option("--confirm-experimental", "Explicitly allow the experimental preset").option("--json", "Output as JSON (for scripts)").action(async (options) => {
49178
49460
  process.exitCode = await designConfigure(process.cwd(), options);
49179
49461
  });
49180
49462
  designProgram.command("disable").description("Disable the project design policy without deleting it").requiredOption("--expected-revision <n>", "Current policy revision").option("--json", "Output as JSON (for scripts)").action(async (options) => {