universal-dev-standards 6.8.0 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/bin/uds.js +12 -2
  2. package/bundled/ai/standards/acceptance-criteria-traceability.ai.yaml +14 -2
  3. package/bundled/ai/standards/adr-standards.ai.yaml +14 -2
  4. package/bundled/ai/standards/code-review.ai.yaml +13 -3
  5. package/bundled/ai/standards/commit-message.ai.yaml +8 -4
  6. package/bundled/ai/standards/deferred-item-exit.ai.yaml +225 -0
  7. package/bundled/ai/standards/feature-discovery-standards.ai.yaml +14 -2
  8. package/bundled/ai/standards/governance-layer.ai.yaml +128 -2
  9. package/bundled/ai/standards/logging.ai.yaml +2 -2
  10. package/bundled/ai/standards/retrospective-standards.ai.yaml +14 -2
  11. package/bundled/ai/standards/reverse-engineering-standards.ai.yaml +73 -2
  12. package/bundled/ai/standards/security-standards.ai.yaml +2 -2
  13. package/bundled/ai/standards/spec-driven-development.ai.yaml +14 -2
  14. package/bundled/ai/standards/tech-debt-standards.ai.yaml +87 -3
  15. package/bundled/ai/standards/turn-completion-integrity.ai.yaml +131 -0
  16. package/bundled/core/acceptance-criteria-traceability.md +5 -2
  17. package/bundled/core/adr-standards.md +26 -2
  18. package/bundled/core/agent-communication-protocol.md +8 -0
  19. package/bundled/core/branch-completion.md +8 -0
  20. package/bundled/core/change-batching-standards.md +8 -0
  21. package/bundled/core/code-review-checklist.md +5 -2
  22. package/bundled/core/context-aware-loading.md +1 -1
  23. package/bundled/core/deferred-item-exit.md +254 -0
  24. package/bundled/core/execution-history.md +8 -0
  25. package/bundled/core/feature-discovery-standards.md +5 -1
  26. package/bundled/core/governance-layer.md +114 -2
  27. package/bundled/core/pipeline-integration-standards.md +8 -0
  28. package/bundled/core/retrospective-standards.md +4 -2
  29. package/bundled/core/reverse-engineering-standards.md +81 -2
  30. package/bundled/core/spec-driven-development.md +8 -2
  31. package/bundled/core/tech-debt-standards.md +67 -8
  32. package/bundled/core/turn-completion-integrity.md +196 -0
  33. package/bundled/core/workflow-enforcement.md +8 -0
  34. package/bundled/core/workflow-state-protocol.md +8 -0
  35. package/bundled/hooks/check-dangerous-cmd.mjs +60 -0
  36. package/bundled/hooks/check-logging-standard.mjs +59 -0
  37. package/bundled/hooks/check-turn-completion.mjs +233 -0
  38. package/bundled/hooks/inject-standards.mjs +183 -0
  39. package/bundled/hooks/telemetry-wrapper.mjs +77 -0
  40. package/bundled/hooks/turn-completion/detect.mjs +99 -0
  41. package/bundled/hooks/turn-completion/locales/en.mjs +159 -0
  42. package/bundled/hooks/turn-completion/locales/zh-TW.mjs +166 -0
  43. package/bundled/hooks/validate-commit-msg.mjs +104 -0
  44. package/bundled/locales/zh-CN/CHANGELOG.md +73 -3
  45. package/bundled/locales/zh-CN/CLAUDE.md +1 -1
  46. package/bundled/locales/zh-CN/README.md +2 -2
  47. package/bundled/locales/zh-CN/SECURITY.md +1 -1
  48. package/bundled/locales/zh-CN/core/adr-standards.md +1 -1
  49. package/bundled/locales/zh-CN/core/agent-communication-protocol.md +7 -0
  50. package/bundled/locales/zh-CN/core/branch-completion.md +7 -0
  51. package/bundled/locales/zh-CN/core/change-batching-standards.md +7 -0
  52. package/bundled/locales/zh-CN/core/execution-history.md +7 -0
  53. package/bundled/locales/zh-CN/core/governance-layer.md +118 -6
  54. package/bundled/locales/zh-CN/core/pipeline-integration-standards.md +7 -0
  55. package/bundled/locales/zh-CN/core/retrospective-standards.md +1 -1
  56. package/bundled/locales/zh-CN/core/tech-debt-standards.md +71 -4
  57. package/bundled/locales/zh-CN/core/turn-completion-integrity.md +190 -0
  58. package/bundled/locales/zh-CN/core/workflow-enforcement.md +7 -0
  59. package/bundled/locales/zh-CN/core/workflow-state-protocol.md +7 -0
  60. package/bundled/locales/zh-CN/docs/CHEATSHEET.md +8 -1
  61. package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +29 -68
  62. package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +25 -15
  63. package/bundled/locales/zh-CN/docs/MIGRATION-v6.md +8 -4
  64. package/bundled/locales/zh-CN/docs/USAGE-MODES-COMPARISON.md +1 -2
  65. package/bundled/locales/zh-CN/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  66. package/bundled/locales/zh-CN/integrations/google-antigravity/README.md +3 -3
  67. package/bundled/locales/zh-CN/skills/atdd-assistant/SKILL.md +2 -0
  68. package/bundled/locales/zh-CN/skills/bdd-assistant/SKILL.md +2 -0
  69. package/bundled/locales/zh-CN/skills/brainstorm-assistant/SKILL.md +22 -12
  70. package/bundled/locales/zh-CN/skills/brainstorm-assistant/guide.md +12 -9
  71. package/bundled/locales/zh-CN/skills/code-review-assistant/SKILL.md +1 -0
  72. package/bundled/locales/zh-CN/skills/commands/brainstorm.md +17 -13
  73. package/bundled/locales/zh-CN/skills/commands/config.md +0 -1
  74. package/bundled/locales/zh-CN/skills/commands/init.md +1 -2
  75. package/bundled/locales/zh-CN/skills/commit-standards/SKILL.md +2 -0
  76. package/bundled/locales/zh-CN/skills/contract-test-assistant/SKILL.md +1 -0
  77. package/bundled/locales/zh-CN/skills/dev-methodology/SKILL.md +2 -0
  78. package/bundled/locales/zh-CN/skills/observability-assistant/SKILL.md +1 -0
  79. package/bundled/locales/zh-CN/skills/project-structure-guide/SKILL.md +1 -0
  80. package/bundled/locales/zh-CN/skills/release-standards/SKILL.md +3 -0
  81. package/bundled/locales/zh-CN/skills/requirement-assistant/SKILL.md +2 -0
  82. package/bundled/locales/zh-CN/skills/reverse-engineer/SKILL.md +3 -0
  83. package/bundled/locales/zh-CN/skills/runbook-assistant/SKILL.md +1 -0
  84. package/bundled/locales/zh-CN/skills/slo-assistant/SKILL.md +1 -0
  85. package/bundled/locales/zh-CN/skills/tdd-assistant/SKILL.md +2 -0
  86. package/bundled/locales/zh-TW/CHANGELOG.md +74 -3
  87. package/bundled/locales/zh-TW/CLAUDE.md +1 -1
  88. package/bundled/locales/zh-TW/README.md +2 -2
  89. package/bundled/locales/zh-TW/SECURITY.md +1 -1
  90. package/bundled/locales/zh-TW/core/acceptance-criteria-traceability.md +2 -0
  91. package/bundled/locales/zh-TW/core/adr-standards.md +26 -5
  92. package/bundled/locales/zh-TW/core/agent-communication-protocol.md +7 -0
  93. package/bundled/locales/zh-TW/core/branch-completion.md +7 -0
  94. package/bundled/locales/zh-TW/core/change-batching-standards.md +7 -0
  95. package/bundled/locales/zh-TW/core/code-review-checklist.md +2 -0
  96. package/bundled/locales/zh-TW/core/container-image-standards.md +2 -2
  97. package/bundled/locales/zh-TW/core/contract-testing-standards.md +2 -2
  98. package/bundled/locales/zh-TW/core/cross-flow-regression.md +8 -7
  99. package/bundled/locales/zh-TW/core/data-contract.md +2 -2
  100. package/bundled/locales/zh-TW/core/data-migration-testing.md +2 -2
  101. package/bundled/locales/zh-TW/core/data-pipeline.md +2 -2
  102. package/bundled/locales/zh-TW/core/deferred-item-exit.md +251 -0
  103. package/bundled/locales/zh-TW/core/documentation-writing-standards.md +228 -3
  104. package/bundled/locales/zh-TW/core/execution-history.md +7 -0
  105. package/bundled/locales/zh-TW/core/full-coverage-testing.md +15 -2
  106. package/bundled/locales/zh-TW/core/governance-layer.md +118 -5
  107. package/bundled/locales/zh-TW/core/iac-design-principles.md +2 -2
  108. package/bundled/locales/zh-TW/core/incident-response.md +2 -2
  109. package/bundled/locales/zh-TW/core/model-provenance.md +4 -2
  110. package/bundled/locales/zh-TW/core/pii-classification.md +42 -6
  111. package/bundled/locales/zh-TW/core/pipeline-integration-standards.md +7 -0
  112. package/bundled/locales/zh-TW/core/prd-standards.md +4 -2
  113. package/bundled/locales/zh-TW/core/product-metrics-standards.md +4 -2
  114. package/bundled/locales/zh-TW/core/release-readiness-gate.md +2 -2
  115. package/bundled/locales/zh-TW/core/resource-cost-boundary.md +2 -2
  116. package/bundled/locales/zh-TW/core/retrospective-standards.md +5 -3
  117. package/bundled/locales/zh-TW/core/reverse-engineering-standards.md +83 -5
  118. package/bundled/locales/zh-TW/core/runbook.md +2 -2
  119. package/bundled/locales/zh-TW/core/schema-evolution.md +2 -2
  120. package/bundled/locales/zh-TW/core/secret-management-standards.md +2 -2
  121. package/bundled/locales/zh-TW/core/slo-sli.md +2 -2
  122. package/bundled/locales/zh-TW/core/spec-driven-development.md +2 -0
  123. package/bundled/locales/zh-TW/core/tech-debt-standards.md +71 -4
  124. package/bundled/locales/zh-TW/core/turn-completion-integrity.md +190 -0
  125. package/bundled/locales/zh-TW/core/user-journey-testing.md +2 -2
  126. package/bundled/locales/zh-TW/core/user-story-mapping.md +2 -2
  127. package/bundled/locales/zh-TW/core/verification-oracle.md +2 -2
  128. package/bundled/locales/zh-TW/core/workflow-enforcement.md +7 -0
  129. package/bundled/locales/zh-TW/core/workflow-state-protocol.md +7 -0
  130. package/bundled/locales/zh-TW/docs/CHEATSHEET.md +8 -1
  131. package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +29 -68
  132. package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +25 -15
  133. package/bundled/locales/zh-TW/docs/MIGRATION-v6.md +8 -4
  134. package/bundled/locales/zh-TW/docs/USAGE-MODES-COMPARISON.md +1 -2
  135. package/bundled/locales/zh-TW/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  136. package/bundled/locales/zh-TW/integrations/google-antigravity/README.md +3 -3
  137. package/bundled/locales/zh-TW/skills/adr-assistant/SKILL.md +1 -1
  138. package/bundled/locales/zh-TW/skills/atdd-assistant/SKILL.md +2 -0
  139. package/bundled/locales/zh-TW/skills/bdd-assistant/SKILL.md +2 -0
  140. package/bundled/locales/zh-TW/skills/brainstorm-assistant/SKILL.md +22 -12
  141. package/bundled/locales/zh-TW/skills/brainstorm-assistant/guide.md +12 -9
  142. package/bundled/locales/zh-TW/skills/code-review-assistant/SKILL.md +1 -0
  143. package/bundled/locales/zh-TW/skills/commands/brainstorm.md +17 -13
  144. package/bundled/locales/zh-TW/skills/commands/config.md +0 -1
  145. package/bundled/locales/zh-TW/skills/commands/init.md +1 -2
  146. package/bundled/locales/zh-TW/skills/commit-standards/SKILL.md +2 -0
  147. package/bundled/locales/zh-TW/skills/contract-test-assistant/SKILL.md +2 -1
  148. package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +2 -0
  149. package/bundled/locales/zh-TW/skills/dev-workflow-guide/SKILL.md +1 -1
  150. package/bundled/locales/zh-TW/skills/knowledge-graph/guide.md +2 -2
  151. package/bundled/locales/zh-TW/skills/migration-assistant/SKILL.md +1 -1
  152. package/bundled/locales/zh-TW/skills/observability-assistant/SKILL.md +1 -0
  153. package/bundled/locales/zh-TW/skills/project-discovery/SKILL.md +1 -0
  154. package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +1 -0
  155. package/bundled/locales/zh-TW/skills/release-standards/SKILL.md +3 -0
  156. package/bundled/locales/zh-TW/skills/requirement-assistant/SKILL.md +2 -0
  157. package/bundled/locales/zh-TW/skills/reverse-engineer/SKILL.md +3 -0
  158. package/bundled/locales/zh-TW/skills/runbook-assistant/SKILL.md +1 -0
  159. package/bundled/locales/zh-TW/skills/slo-assistant/SKILL.md +1 -0
  160. package/bundled/locales/zh-TW/skills/tdd-assistant/SKILL.md +2 -0
  161. package/bundled/skills/atdd-assistant/SKILL.md +2 -0
  162. package/bundled/skills/bdd-assistant/SKILL.md +2 -0
  163. package/bundled/skills/brainstorm-assistant/SKILL.md +31 -13
  164. package/bundled/skills/brainstorm-assistant/guide.md +9 -6
  165. package/bundled/skills/code-review-assistant/SKILL.md +1 -0
  166. package/bundled/skills/commands/brainstorm.md +12 -9
  167. package/bundled/skills/commands/config.md +0 -1
  168. package/bundled/skills/commands/init.md +2 -3
  169. package/bundled/skills/commit-standards/SKILL.md +2 -0
  170. package/bundled/skills/contract-test-assistant/SKILL.md +1 -0
  171. package/bundled/skills/dev-methodology/SKILL.md +4 -0
  172. package/bundled/skills/observability-assistant/SKILL.md +1 -0
  173. package/bundled/skills/project-discovery/SKILL.md +1 -0
  174. package/bundled/skills/project-structure-guide/SKILL.md +1 -0
  175. package/bundled/skills/release-standards/SKILL.md +3 -0
  176. package/bundled/skills/requirement-assistant/SKILL.md +2 -0
  177. package/bundled/skills/reverse-engineer/SKILL.md +3 -0
  178. package/bundled/skills/runbook-assistant/SKILL.md +1 -0
  179. package/bundled/skills/slo-assistant/SKILL.md +1 -0
  180. package/bundled/skills/tdd-assistant/SKILL.md +2 -0
  181. package/bundled/templates/.ai-context.yaml.template +194 -0
  182. package/bundled/templates/CLAUDE.md.template +145 -0
  183. package/bundled/templates/DESIGN.md +237 -0
  184. package/bundled/templates/SKILL-BRIEF-TEMPLATE.md +57 -0
  185. package/bundled/templates/SKILL-CANDIDATES.md +39 -0
  186. package/bundled/templates/gates/check-error-exit.mjs +309 -0
  187. package/bundled/templates/mcp-config.json +10 -0
  188. package/bundled/templates/methodology-template.yaml +209 -0
  189. package/bundled/templates/migration-template.md +408 -0
  190. package/bundled/templates/requirement-checklist.md +410 -0
  191. package/bundled/templates/requirement-document-template.md +591 -0
  192. package/bundled/templates/requirement-template.md +881 -0
  193. package/bundled/templates/reverse-spec-template.md +409 -0
  194. package/bundled/templates/test-case-template.md +74 -0
  195. package/bundled/templates/test-plan-template.md +74 -0
  196. package/package.json +12 -9
  197. package/src/commands/audit.js +82 -0
  198. package/src/commands/check.js +227 -34
  199. package/src/commands/config.js +19 -19
  200. package/src/commands/init.js +174 -20
  201. package/src/commands/spec.js +2 -2
  202. package/src/commands/update.js +537 -43
  203. package/src/compilers/claude-code-compiler.js +4 -1
  204. package/src/config/ai-agent-paths.js +62 -17
  205. package/src/core/constants.js +42 -11
  206. package/src/core/manifest.js +201 -3
  207. package/src/core/paths.js +2 -2
  208. package/src/i18n/messages.js +42 -29
  209. package/src/installers/hooks-installer.js +167 -75
  210. package/src/installers/integration-installer.js +13 -9
  211. package/src/installers/skills-installer.js +4 -4
  212. package/src/installers/standards-installer.js +3 -3
  213. package/src/prompts/init.js +47 -18
  214. package/src/reconciler/diff-engine.js +57 -2
  215. package/src/reconciler/plan-executor.js +31 -11
  216. package/src/utils/detector.js +21 -1
  217. package/src/utils/effect-boundary.js +1093 -0
  218. package/src/utils/hasher.js +166 -1
  219. package/src/utils/hook-stats.js +1 -1
  220. package/src/utils/integration-generator.js +288 -82
  221. package/src/utils/reference-sync.js +107 -8
  222. package/src/utils/registry.js +57 -0
  223. package/src/utils/spinner.js +31 -0
  224. package/src/utils/yaml-generator.js +51 -9
  225. package/standards-registry.json +32 -9
@@ -3,6 +3,7 @@ import { readFileSync, existsSync, readdirSync } from 'fs';
3
3
  import { join, relative } from 'path';
4
4
  import { UDS_MARKERS } from '../core/constants.js';
5
5
  import { resolveIntegrationFile } from '../core/constants.js';
6
+ import { isProvenanceEstablished } from '../core/manifest.js';
6
7
 
7
8
  // GitHub issue #155. `git config core.autocrlf true` (the common
8
9
  // Windows default) rewrites LF to CRLF on checkout. The manifest's stored
@@ -240,6 +241,15 @@ function scanDirectory(dirPath, basePath) {
240
241
 
241
242
  /**
242
243
  * Scan for untracked files in .standards/ and integration locations
244
+ *
245
+ * ⚠ "Untracked" here means only "absent from `manifest.fileHashes`". It is NOT
246
+ * an ownership predicate, and must not be used to decide what may be deleted —
247
+ * that is what it was used for, and it is why a user's hand-written file was
248
+ * removed without warning (issue #168). Use `planStandardsRemovals` /
249
+ * `classifyFileOwnership`, which separate "did UDS write this" from "is this
250
+ * still shipped". This function survives for reporting callers that genuinely
251
+ * want the hash-table question. (XSPEC-384 R1)
252
+ *
243
253
  * @param {string} projectPath - Project root path
244
254
  * @param {Object} manifest - Manifest object
245
255
  * @returns {string[]} Array of relative paths to untracked files
@@ -271,7 +281,7 @@ export function scanForUntrackedFiles(projectPath, manifest) {
271
281
  '.clinerules',
272
282
  '.github/copilot-instructions.md',
273
283
  'CLAUDE.md',
274
- 'INSTRUCTIONS.md'
284
+ '.agents/AGENTS.md'
275
285
  ];
276
286
 
277
287
  for (const intFile of knownIntegrations) {
@@ -284,6 +294,161 @@ export function scanForUntrackedFiles(projectPath, manifest) {
284
294
  return untracked;
285
295
  }
286
296
 
297
+ /**
298
+ * The three states a file under `.standards/` can be in. (XSPEC-384 R1)
299
+ *
300
+ * `scanForUntrackedFiles` answers a two-state question — in `fileHashes` or
301
+ * not — and the caller then treated "not" as "not ours, delete it". The world
302
+ * has a third state: files UDS did write whose manifest record was lost. The
303
+ * old predicate folded that into the same branch as a user's own file, and the
304
+ * branch deletes.
305
+ */
306
+ export const FILE_OWNERSHIP = {
307
+ /** UDS wrote this file; we may remove it when it stops being shipped. */
308
+ UDS: 'uds-owned',
309
+ /** Provenance is complete and does not name this file: it is not ours. */
310
+ FOREIGN: 'foreign',
311
+ /** No provenance yet — we cannot tell, so we must not act destructively. */
312
+ UNKNOWN: 'unknown'
313
+ };
314
+
315
+ /** Paths that are never candidates for anything, with the reason. */
316
+ const STRUCTURAL_EXCLUSIONS = new Map([
317
+ ['.standards/manifest.json', 'the manifest itself']
318
+ ]);
319
+
320
+ /**
321
+ * Decide who owns one file under `.standards/`.
322
+ *
323
+ * @param {string} relPath - Path relative to project root (forward slashes)
324
+ * @param {Object} manifest - Manifest object
325
+ * @returns {string} One of FILE_OWNERSHIP
326
+ */
327
+ export function classifyFileOwnership(relPath, manifest) {
328
+ const normalized = (relPath || '').replace(/\\/g, '/');
329
+ const provenanceFiles = manifest?.provenance?.files;
330
+ if (provenanceFiles && Object.prototype.hasOwnProperty.call(provenanceFiles, normalized)) {
331
+ return FILE_OWNERSHIP.UDS;
332
+ }
333
+ // Pre-provenance evidence. A path in `fileHashes` got there because UDS put
334
+ // it there, so it is still proof of authorship — just weaker proof, since it
335
+ // is also the table that loses entries. Reading it here (rather than only
336
+ // reading provenance) is what keeps the first upgrade from disowning every
337
+ // file installed before provenance existed.
338
+ if (manifest?.fileHashes && Object.prototype.hasOwnProperty.call(manifest.fileHashes, normalized)) {
339
+ return FILE_OWNERSHIP.UDS;
340
+ }
341
+ // No record either way. Whether that means "not ours" depends entirely on
342
+ // whether our records are complete yet.
343
+ return isProvenanceEstablished(manifest) ? FILE_OWNERSHIP.FOREIGN : FILE_OWNERSHIP.UNKNOWN;
344
+ }
345
+
346
+ /**
347
+ * Walk `.standards/` and classify everything in it.
348
+ *
349
+ * A walk, not a list of expected names: `.standards/` is an open set — UDS's
350
+ * own docs invite teams to add project-specific files to it — so any
351
+ * enumeration of "files we know about" is stale the moment someone adds one,
352
+ * and being absent from that enumeration is precisely what used to get a file
353
+ * deleted. (XSPEC-384 R1)
354
+ *
355
+ * @param {string} projectPath - Project root path
356
+ * @param {Object} manifest - Manifest object
357
+ * @returns {{scanned:number, excluded:Array, udsOwned:string[], foreign:string[], unknown:string[]}}
358
+ */
359
+ export function classifyStandardsFiles(projectPath, manifest) {
360
+ const result = { scanned: 0, excluded: [], udsOwned: [], foreign: [], unknown: [] };
361
+
362
+ const standardsDir = join(projectPath, '.standards');
363
+ if (!existsSync(standardsDir)) return result;
364
+
365
+ for (const relPath of scanDirectory(standardsDir, projectPath)) {
366
+ const normalized = relPath.replace(/\\/g, '/');
367
+ result.scanned++;
368
+
369
+ const exclusionReason = STRUCTURAL_EXCLUSIONS.get(normalized);
370
+ if (exclusionReason) {
371
+ result.excluded.push({ path: normalized, reason: exclusionReason });
372
+ continue;
373
+ }
374
+
375
+ switch (classifyFileOwnership(normalized, manifest)) {
376
+ case FILE_OWNERSHIP.UDS:
377
+ result.udsOwned.push(normalized);
378
+ break;
379
+ case FILE_OWNERSHIP.FOREIGN:
380
+ result.foreign.push(normalized);
381
+ break;
382
+ default:
383
+ result.unknown.push(normalized);
384
+ }
385
+ }
386
+
387
+ return result;
388
+ }
389
+
390
+ /**
391
+ * Decide which files under `.standards/` `uds update` may delete.
392
+ *
393
+ * Deletion now needs two independent facts to line up, one per axis:
394
+ *
395
+ * 1. UDS wrote the file (ownership — provenance, or a legacy `fileHashes`
396
+ * entry as weaker evidence of the same thing)
397
+ * 2. UDS no longer ships it (currency — absence from `desiredFiles`, which
398
+ * the caller derives from the registry it just resolved)
399
+ *
400
+ * Every other combination is kept, and says why it was kept. The old rule
401
+ * collapsed both axes onto `fileHashes` membership, so it deleted files it had
402
+ * never written (#168) while retaining files it no longer shipped (#165).
403
+ *
404
+ * Nothing is removed when `desiredFiles` is null: a caller that cannot say what
405
+ * should exist has not established fact 2, and "I don't know" must not resolve
406
+ * to the destructive branch — that was the original defect.
407
+ *
408
+ * @param {string} projectPath - Project root path
409
+ * @param {Object} manifest - Manifest object
410
+ * @param {Set<string>|null} desiredFiles - Files the current registry says should exist
411
+ * @returns {{scanned:number, excluded:Array, remove:Array, keep:Array, census:Object}}
412
+ */
413
+ export function planStandardsRemovals(projectPath, manifest, desiredFiles = null) {
414
+ const census = classifyStandardsFiles(projectPath, manifest);
415
+ const remove = [];
416
+ const keep = [];
417
+
418
+ const desiredKnown = desiredFiles instanceof Set;
419
+
420
+ for (const path of census.udsOwned) {
421
+ if (!desiredKnown) {
422
+ keep.push({ path, reason: 'UDS-owned, but this run could not determine what is still shipped' });
423
+ } else if (desiredFiles.has(path)) {
424
+ keep.push({ path, reason: 'UDS-owned and still shipped' });
425
+ } else {
426
+ remove.push({ path, reason: 'UDS-owned and no longer shipped by the registry' });
427
+ }
428
+ }
429
+
430
+ for (const path of census.foreign) {
431
+ keep.push({ path, reason: 'not written by UDS' });
432
+ }
433
+
434
+ for (const path of census.unknown) {
435
+ keep.push({ path, reason: 'ownership unknown (manifest predates provenance)' });
436
+ }
437
+
438
+ return {
439
+ scanned: census.scanned,
440
+ excluded: census.excluded,
441
+ remove,
442
+ keep,
443
+ census: {
444
+ udsOwned: census.udsOwned.length,
445
+ foreign: census.foreign.length,
446
+ unknown: census.unknown.length,
447
+ desired: desiredKnown ? desiredFiles.size : null
448
+ }
449
+ };
450
+ }
451
+
287
452
  /**
288
453
  * Detect file format based on file path
289
454
  * @param {string} filePath - File path
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Hook Statistics - Context-aware loading learning loop
3
3
  *
4
- * Records and analyzes trigger statistics from inject-standards.js hook.
4
+ * Records and analyzes trigger statistics from inject-standards.mjs hook.
5
5
  * Privacy: never records full prompt content or file paths.
6
6
  *
7
7
  * @module utils/hook-stats