pumuki 6.3.55 → 6.3.57

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 (195) hide show
  1. package/README.md +16 -85
  2. package/VERSION +1 -1
  3. package/core/facts/HeuristicFact.test.ts +28 -0
  4. package/core/facts/HeuristicFact.ts +11 -0
  5. package/core/facts/detectors/text/android.test.ts +207 -0
  6. package/core/facts/detectors/text/android.ts +765 -0
  7. package/core/facts/detectors/text/ios.test.ts +207 -0
  8. package/core/facts/detectors/text/ios.ts +848 -0
  9. package/core/facts/detectors/typescript/index.test.ts +447 -0
  10. package/core/facts/detectors/typescript/index.ts +1214 -54
  11. package/core/facts/extractHeuristicFacts.ts +285 -1
  12. package/core/gate/Finding.test.ts +28 -0
  13. package/core/gate/Finding.ts +12 -0
  14. package/core/gate/evaluateRules.ts +22 -0
  15. package/core/rules/presets/androidRuleSet.test.ts +52 -2
  16. package/core/rules/presets/androidRuleSet.ts +130 -0
  17. package/core/rules/presets/iosEnterpriseRuleSet.test.ts +276 -1
  18. package/core/rules/presets/iosEnterpriseRuleSet.ts +156 -0
  19. package/core/rules/presets/rulePackVersions.test.ts +2 -2
  20. package/core/rules/presets/rulePackVersions.ts +2 -2
  21. package/docs/README.md +44 -15
  22. package/docs/codex-skills/{windsurf-rules-android.md → android-enterprise-rules.md} +1 -1
  23. package/docs/codex-skills/{windsurf-rules-backend.md → backend-enterprise-rules.md} +1 -1
  24. package/docs/codex-skills/{windsurf-rules-frontend.md → frontend-enterprise-rules.md} +1 -1
  25. package/docs/codex-skills/{windsurf-rules-ios.md → ios-enterprise-rules.md} +1 -1
  26. package/docs/mcp/{MCP_AGENT_CONTEXT_CONSUMPTION.md → agent-context-consumption.md} +2 -2
  27. package/docs/mcp/{MCP_SERVERS.md → mcp-servers-overview.md} +2 -2
  28. package/docs/operations/RELEASE_NOTES.md +28 -4
  29. package/docs/product/API_REFERENCE.md +2 -2
  30. package/docs/product/INSTALLATION.md +16 -108
  31. package/docs/product/USAGE.md +7 -2
  32. package/docs/rule-packs/engineering-baseline.md +1 -1
  33. package/docs/rule-packs/ios.md +1 -1
  34. package/docs/validation/README.md +6 -5
  35. package/integrations/config/skillsCustomRules.ts +176 -16
  36. package/integrations/config/skillsEffectiveLock.ts +109 -2
  37. package/integrations/config/skillsRuleSet.ts +5 -1
  38. package/integrations/evidence/buildEvidence.ts +55 -0
  39. package/integrations/evidence/generateEvidence.test.ts +46 -0
  40. package/integrations/evidence/schema.ts +18 -0
  41. package/integrations/evidence/writeEvidence.ts +52 -0
  42. package/integrations/gate/evaluateAiGate.ts +186 -22
  43. package/integrations/git/findingTraceability.ts +15 -0
  44. package/integrations/git/gitAtomicity.ts +30 -2
  45. package/integrations/git/runPlatformGate.ts +56 -3
  46. package/integrations/sdd/syncDocs.ts +16 -375
  47. package/integrations/sdd/syncDocsTargets.ts +380 -0
  48. package/package.json +2 -1
  49. package/scripts/backlog-action-reasons-lib.ts +18 -22
  50. package/scripts/backlog-action-reasons-types.ts +25 -0
  51. package/scripts/backlog-consumer-gh.ts +117 -0
  52. package/scripts/backlog-consumer-patterns.ts +36 -0
  53. package/scripts/backlog-consumer-types.ts +7 -0
  54. package/scripts/backlog-id-issue-map-lib.ts +9 -42
  55. package/scripts/backlog-id-issue-map-parse.ts +40 -0
  56. package/scripts/backlog-id-issue-map-types.ts +4 -0
  57. package/scripts/check-self-worktree-hygiene.ts +94 -0
  58. package/scripts/check-tracking-single-active.sh +4 -2
  59. package/scripts/framework-menu-advanced-view-help.ts +39 -0
  60. package/scripts/framework-menu-advanced-view-lib.ts +6 -63
  61. package/scripts/framework-menu-advanced-view-status.ts +31 -0
  62. package/scripts/framework-menu-consumer-preflight-hints.ts +119 -0
  63. package/scripts/framework-menu-consumer-preflight-lib.ts +14 -247
  64. package/scripts/framework-menu-consumer-preflight-render.ts +41 -0
  65. package/scripts/framework-menu-consumer-preflight-run.ts +105 -0
  66. package/scripts/framework-menu-consumer-preflight-types.ts +40 -0
  67. package/scripts/framework-menu-consumer-runtime-actions.ts +139 -0
  68. package/scripts/framework-menu-consumer-runtime-audit.ts +86 -0
  69. package/scripts/framework-menu-consumer-runtime-lib.ts +46 -223
  70. package/scripts/framework-menu-consumer-runtime-menu.ts +104 -0
  71. package/scripts/framework-menu-consumer-runtime-types.ts +52 -0
  72. package/scripts/framework-menu-evidence-summary-file.ts +42 -0
  73. package/scripts/framework-menu-evidence-summary-format.ts +49 -0
  74. package/scripts/framework-menu-evidence-summary-lib.ts +7 -258
  75. package/scripts/framework-menu-evidence-summary-normalize.ts +87 -0
  76. package/scripts/framework-menu-evidence-summary-read.ts +60 -0
  77. package/scripts/framework-menu-evidence-summary-severity.ts +70 -0
  78. package/scripts/framework-menu-evidence-summary-types.ts +28 -0
  79. package/scripts/framework-menu-layout-data.ts +52 -0
  80. package/scripts/framework-menu-layout-lib.ts +8 -116
  81. package/scripts/framework-menu-layout-resolve.ts +51 -0
  82. package/scripts/framework-menu-layout-types.ts +16 -0
  83. package/scripts/framework-menu-legacy-audit-lib.ts +14 -1229
  84. package/scripts/framework-menu-legacy-audit-markdown-document.ts +31 -0
  85. package/scripts/framework-menu-legacy-audit-markdown-links.ts +29 -0
  86. package/scripts/framework-menu-legacy-audit-markdown.ts +19 -0
  87. package/scripts/framework-menu-legacy-audit-render-panel.ts +249 -0
  88. package/scripts/framework-menu-legacy-audit-render-report.ts +162 -0
  89. package/scripts/framework-menu-legacy-audit-render-sections.ts +97 -0
  90. package/scripts/framework-menu-legacy-audit-render.ts +16 -0
  91. package/scripts/framework-menu-legacy-audit-summary-metrics.ts +50 -0
  92. package/scripts/framework-menu-legacy-audit-summary-normalize.ts +195 -0
  93. package/scripts/framework-menu-legacy-audit-summary-platforms.ts +183 -0
  94. package/scripts/framework-menu-legacy-audit-summary-ranked.ts +76 -0
  95. package/scripts/framework-menu-legacy-audit-summary-types.ts +42 -0
  96. package/scripts/framework-menu-legacy-audit-summary.ts +105 -0
  97. package/scripts/framework-menu-legacy-audit-types.ts +74 -0
  98. package/scripts/framework-menu-matrix-canary-evidence.ts +34 -0
  99. package/scripts/framework-menu-matrix-canary-lib.ts +16 -140
  100. package/scripts/framework-menu-matrix-canary-scenario.ts +91 -0
  101. package/scripts/framework-menu-matrix-canary-types.ts +21 -0
  102. package/scripts/framework-menu-matrix-evidence-diagnosis.ts +46 -0
  103. package/scripts/framework-menu-matrix-evidence-lib.ts +10 -59
  104. package/scripts/framework-menu-matrix-evidence-types.ts +18 -0
  105. package/scripts/framework-menu-rule-coverage-diagnostics-build.ts +122 -0
  106. package/scripts/framework-menu-rule-coverage-diagnostics-format.ts +46 -0
  107. package/scripts/framework-menu-rule-coverage-diagnostics-lib.ts +10 -208
  108. package/scripts/framework-menu-rule-coverage-diagnostics-types.ts +54 -0
  109. package/scripts/framework-menu-system-notifications-cause.ts +54 -0
  110. package/scripts/framework-menu-system-notifications-config-choice.ts +35 -0
  111. package/scripts/framework-menu-system-notifications-config-file.ts +25 -0
  112. package/scripts/framework-menu-system-notifications-config-state.ts +62 -0
  113. package/scripts/framework-menu-system-notifications-config-types.ts +8 -0
  114. package/scripts/framework-menu-system-notifications-config.ts +7 -0
  115. package/scripts/framework-menu-system-notifications-dispatch.ts +32 -0
  116. package/scripts/framework-menu-system-notifications-effective-config.ts +18 -0
  117. package/scripts/framework-menu-system-notifications-event-types.ts +27 -0
  118. package/scripts/framework-menu-system-notifications-gate.ts +22 -0
  119. package/scripts/framework-menu-system-notifications-lib.ts +51 -867
  120. package/scripts/framework-menu-system-notifications-macos-applescript-banner.ts +16 -0
  121. package/scripts/framework-menu-system-notifications-macos-applescript-dialog.ts +18 -0
  122. package/scripts/framework-menu-system-notifications-macos-applescript-parse.ts +4 -0
  123. package/scripts/framework-menu-system-notifications-macos-applescript.ts +38 -0
  124. package/scripts/framework-menu-system-notifications-macos-banner-delivery-dispatch.ts +15 -0
  125. package/scripts/framework-menu-system-notifications-macos-banner-delivery-runner.ts +14 -0
  126. package/scripts/framework-menu-system-notifications-macos-banner-delivery.ts +21 -0
  127. package/scripts/framework-menu-system-notifications-macos-banner-result.ts +8 -0
  128. package/scripts/framework-menu-system-notifications-macos-banner-run.ts +6 -0
  129. package/scripts/framework-menu-system-notifications-macos-banner-script.ts +6 -0
  130. package/scripts/framework-menu-system-notifications-macos-banner-stage.ts +15 -0
  131. package/scripts/framework-menu-system-notifications-macos-banner.ts +18 -0
  132. package/scripts/framework-menu-system-notifications-macos-blocked-dispatch-gate.ts +11 -0
  133. package/scripts/framework-menu-system-notifications-macos-blocked-dispatch-runner.ts +9 -0
  134. package/scripts/framework-menu-system-notifications-macos-blocked-dispatch.ts +39 -0
  135. package/scripts/framework-menu-system-notifications-macos-blocked-stage.ts +30 -0
  136. package/scripts/framework-menu-system-notifications-macos-dialog-effect.ts +25 -0
  137. package/scripts/framework-menu-system-notifications-macos-dialog-enabled.ts +20 -0
  138. package/scripts/framework-menu-system-notifications-macos-dialog-mode-dispatch.ts +50 -0
  139. package/scripts/framework-menu-system-notifications-macos-dialog-mode-resolve.ts +1 -0
  140. package/scripts/framework-menu-system-notifications-macos-dialog-mode.ts +21 -0
  141. package/scripts/framework-menu-system-notifications-macos-dialog-payload.ts +35 -0
  142. package/scripts/framework-menu-system-notifications-macos-dialog.ts +54 -0
  143. package/scripts/framework-menu-system-notifications-macos-result.ts +11 -0
  144. package/scripts/framework-menu-system-notifications-macos-runner-exec.ts +11 -0
  145. package/scripts/framework-menu-system-notifications-macos-runner-output.ts +29 -0
  146. package/scripts/framework-menu-system-notifications-macos-runner-parse.ts +7 -0
  147. package/scripts/framework-menu-system-notifications-macos-runner.ts +3 -0
  148. package/scripts/framework-menu-system-notifications-macos-swift-args.ts +38 -0
  149. package/scripts/framework-menu-system-notifications-macos-swift-run.ts +52 -0
  150. package/scripts/framework-menu-system-notifications-macos-swift-source.ts +246 -0
  151. package/scripts/framework-menu-system-notifications-macos-swift.ts +6 -0
  152. package/scripts/framework-menu-system-notifications-macos.ts +48 -0
  153. package/scripts/framework-menu-system-notifications-payload-types.ts +10 -0
  154. package/scripts/framework-menu-system-notifications-payloads-audit.ts +31 -0
  155. package/scripts/framework-menu-system-notifications-payloads-blocked.ts +32 -0
  156. package/scripts/framework-menu-system-notifications-payloads-context.ts +14 -0
  157. package/scripts/framework-menu-system-notifications-payloads-events.ts +18 -0
  158. package/scripts/framework-menu-system-notifications-payloads.ts +55 -0
  159. package/scripts/framework-menu-system-notifications-remediation.ts +58 -0
  160. package/scripts/framework-menu-system-notifications-runner-types.ts +20 -0
  161. package/scripts/framework-menu-system-notifications-text.ts +31 -0
  162. package/scripts/framework-menu-system-notifications-types.ts +22 -0
  163. package/scripts/framework-menu-ui-components-lib.ts +14 -220
  164. package/scripts/framework-menu-ui-components-panel.ts +46 -0
  165. package/scripts/framework-menu-ui-components-render.ts +58 -0
  166. package/scripts/framework-menu-ui-components-tokens.ts +105 -0
  167. package/scripts/framework-menu-ui-components-types.ts +30 -0
  168. package/scripts/gitflow-cli-commands.ts +145 -0
  169. package/scripts/gitflow-cli-lib.ts +34 -244
  170. package/scripts/gitflow-cli-snapshot.ts +97 -0
  171. package/scripts/gitflow-cli-types.ts +26 -0
  172. package/scripts/legacy-parity-report-build.ts +96 -0
  173. package/scripts/legacy-parity-report-lib.ts +11 -406
  174. package/scripts/legacy-parity-report-markdown.ts +60 -0
  175. package/scripts/legacy-parity-report-normalize.ts +202 -0
  176. package/scripts/legacy-parity-report-types.ts +74 -0
  177. package/scripts/package-manifest-lib.ts +4 -4
  178. package/scripts/reconcile-consumer-backlog-issues-lib.ts +56 -578
  179. package/scripts/reconcile-consumer-backlog-issues-parse.ts +197 -0
  180. package/scripts/reconcile-consumer-backlog-issues-sync.ts +272 -0
  181. package/scripts/reconcile-consumer-backlog-issues-types.ts +71 -0
  182. package/scripts/self-worktree-hygiene-lib.ts +202 -0
  183. package/scripts/sync-codex-skills.sh +4 -4
  184. package/scripts/watch-consumer-backlog-fleet-lib.ts +131 -0
  185. package/scripts/watch-consumer-backlog-fleet-tick.ts +10 -82
  186. package/scripts/watch-consumer-backlog-fleet.ts +10 -77
  187. package/scripts/watch-consumer-backlog-lib.ts +33 -353
  188. package/scripts/watch-consumer-backlog-parse.ts +168 -0
  189. package/scripts/watch-consumer-backlog-types.ts +45 -0
  190. package/skills.lock.json +758 -758
  191. package/skills.sources.json +12 -12
  192. /package/docs/mcp/{MCP_EVIDENCE_CONTEXT_SERVER.md → evidence-context-server.md} +0 -0
  193. /package/docs/operations/{framework-menu-option-1-walkthrough.md → framework-menu-consumer-walkthrough.md} +0 -0
  194. /package/docs/operations/{OPERATIONS.md → production-operations-policy.md} +0 -0
  195. /package/docs/validation/{ast-intelligence-roadmap.md → ast-intelligence-validation-roadmap.md} +0 -0
package/README.md CHANGED
@@ -238,87 +238,18 @@ Legacy parity report (strict comparator):
238
238
  node --import tsx scripts/build-legacy-parity-report.ts --legacy=<legacy-evidence-path> --enterprise=<enterprise-evidence-path> --out=<output-path>
239
239
  ```
240
240
 
241
- ## Command Reference
241
+ ## Command Paths
242
242
 
243
- ### Lifecycle (Consumer)
243
+ Use these docs instead of treating `README.md` as the full command manual:
244
244
 
245
- ```bash
246
- npx --yes pumuki install
247
- npx --yes pumuki update --latest
248
- npx --yes pumuki uninstall --purge-artifacts
249
- npx --yes pumuki remove
250
- npx --yes pumuki doctor
251
- npx --yes pumuki status
252
- ```
253
-
254
- ### SDD / OpenSpec (Consumer)
255
-
256
- ```bash
257
- npx --yes pumuki sdd status
258
- npx --yes pumuki sdd session --open --change=<change-id>
259
- npx --yes pumuki sdd session --refresh
260
- npx --yes pumuki sdd session --close
261
- npx --yes pumuki sdd validate --stage=PRE_COMMIT
262
- ```
263
-
264
- ### Loop Runner (Consumer)
265
-
266
- ```bash
267
- npx --yes pumuki loop run --objective="stabilize gate before commit" --max-attempts=3 --json
268
- npx --yes pumuki loop status --session=<session-id> --json
269
- npx --yes pumuki loop stop --session=<session-id> --json
270
- npx --yes pumuki loop resume --session=<session-id> --json
271
- npx --yes pumuki loop list --json
272
- npx --yes pumuki loop export --session=<session-id> --output-json=.audit-reports/loop-session.json
273
- ```
274
-
275
- ### Stage Gates (Consumer)
276
-
277
- ```bash
278
- npx --yes --package pumuki@latest pumuki-pre-write
279
- npx --yes --package pumuki@latest pumuki-pre-commit
280
- npx --yes --package pumuki@latest pumuki-pre-push
281
- npx --yes --package pumuki@latest pumuki-ci
282
- ```
283
-
284
- ### MCP Servers (Optional, Long-Running)
285
-
286
- ```bash
287
- npx --yes --package pumuki@latest pumuki-mcp-evidence
288
- npx --yes --package pumuki@latest pumuki-mcp-evidence-stdio
289
- npx --yes --package pumuki@latest pumuki-mcp-enterprise
290
- npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio
291
- ```
292
-
293
- ## Validation and Diagnostics (Framework-Only)
294
-
295
- These commands are for maintainers and may require additional arguments, external repo context, or authenticated GitHub access.
296
-
297
- ```bash
298
- npm run validation:consumer-ci-artifacts -- --repo <owner/repo>
299
- npm run validation:consumer-ci-auth-check -- --repo <owner/repo>
300
- npm run validation:consumer-workflow-lint -- --repo-path <absolute-path-to-consumer-repo>
301
- npm run validation:consumer-support-bundle -- --repo <owner/repo>
302
- npm run validation:consumer-support-ticket-draft
303
- npm run validation:consumer-startup-unblock-status
304
- npm run validation:consumer-startup-triage -- --repo <owner/repo> --skip-workflow-lint
305
- npm run validation:mock-consumer-ab-report
306
- npm run validation:adapter-readiness
307
- npm run validation:adapter-session-status
308
- npm run validation:adapter-real-session-report
309
- npm run validation:phase5-blockers-readiness
310
- npm run validation:phase5-execution-closure-status
311
- npm run validation:phase5-execution-closure -- --repo <owner/repo> --skip-workflow-lint
312
- npm run validation:phase5-external-handoff
313
- npm run validation:clean-artifacts
314
- ```
315
-
316
- Important:
317
-
318
- - Several validation scripts intentionally return non-zero when verdict is `BLOCKED`, `PENDING`, or `MISSING_INPUTS`.
319
- - Non-zero in these scripts is often diagnostic output, not a runtime crash.
320
- - `validation:consumer-support-ticket-draft` expects an existing support bundle generated by `validation:consumer-support-bundle`.
321
- - If workflow lint is required in your flow, provide `--repo-path` and `--actionlint-bin`; otherwise use `--skip-workflow-lint`.
245
+ - Installation and bootstrap:
246
+ - `docs/product/INSTALLATION.md`
247
+ - Daily usage, gates, menu, lifecycle, SDD and troubleshooting:
248
+ - `docs/product/USAGE.md`
249
+ - Operator-focused short playbook:
250
+ - `PUMUKI.md`
251
+ - Validation runbooks and framework-only diagnostics:
252
+ - `docs/validation/README.md`
322
253
 
323
254
  ## Menu Walkthrough and Screenshots
324
255
 
@@ -348,13 +279,13 @@ Important:
348
279
 
349
280
  Extended annotated walkthrough:
350
281
 
351
- - `docs/operations/framework-menu-option-1-walkthrough.md`
282
+ - `docs/operations/framework-menu-consumer-walkthrough.md`
352
283
 
353
284
  ## Enterprise Operations Baseline
354
285
 
355
286
  Pumuki production SaaS operation baseline is defined in:
356
287
 
357
- - `docs/operations/OPERATIONS.md`
288
+ - `docs/operations/production-operations-policy.md`
358
289
 
359
290
  Highlights:
360
291
 
@@ -384,11 +315,11 @@ Highlights:
384
315
  - Configuration: `docs/product/CONFIGURATION.md`
385
316
  - Code standards: `docs/governance/CODE_STANDARDS.md`
386
317
  - Branch protection: `docs/governance/BRANCH_PROTECTION_GUIDE.md`
387
- - MCP servers: `docs/mcp/MCP_SERVERS.md`
388
- - MCP evidence server: `docs/mcp/MCP_EVIDENCE_CONTEXT_SERVER.md`
389
- - MCP consumption: `docs/mcp/MCP_AGENT_CONTEXT_CONSUMPTION.md`
318
+ - MCP servers: `docs/mcp/mcp-servers-overview.md`
319
+ - MCP evidence server: `docs/mcp/evidence-context-server.md`
320
+ - MCP consumption: `docs/mcp/agent-context-consumption.md`
390
321
  - Evidence schema v2.1: `docs/mcp/ai-evidence-v2.1-contract.md`
391
- - Operations policy (SLA/SLO): `docs/operations/OPERATIONS.md`
322
+ - Operations policy (SLA/SLO): `docs/operations/production-operations-policy.md`
392
323
  - Release notes: `docs/operations/RELEASE_NOTES.md`
393
324
  - Changelog: `CHANGELOG.md`
394
325
 
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.41
1
+ v6.3.57
@@ -32,3 +32,31 @@ test('HeuristicFact permite omitir filePath', () => {
32
32
  assert.equal(factWithoutPath.filePath, undefined);
33
33
  assert.equal(factWithoutPath.severity, 'INFO');
34
34
  });
35
+
36
+ test('HeuristicFact conserva metadata semantica opcional del canario iOS', () => {
37
+ const fact: HeuristicFact = {
38
+ kind: 'Heuristic',
39
+ ruleId: 'heuristics.ios.canary-001.presentation-mixed-responsibilities.ast',
40
+ severity: 'CRITICAL',
41
+ code: 'HEURISTICS_IOS_CANARY_001_PRESENTATION_MIXED_RESPONSIBILITIES_AST',
42
+ message: 'Semantic iOS canary triggered.',
43
+ filePath: 'apps/ios/Sources/AppShell/Application/AppShellViewModel.swift',
44
+ lines: [1, 2, 3, 4],
45
+ primary_node: {
46
+ kind: 'class',
47
+ name: 'AppShellViewModel',
48
+ lines: [1],
49
+ },
50
+ related_nodes: [
51
+ { kind: 'property', name: 'shared singleton', lines: [2] },
52
+ { kind: 'call', name: 'URLSession.shared', lines: [3] },
53
+ ],
54
+ why: 'Mezcla responsabilidades incompatibles.',
55
+ impact: 'Complica tests y cambios.',
56
+ expected_fix: 'Extraer collaborators.',
57
+ };
58
+
59
+ assert.equal(fact.primary_node?.name, 'AppShellViewModel');
60
+ assert.equal(fact.related_nodes?.length, 2);
61
+ assert.equal(fact.expected_fix, 'Extraer collaborators.');
62
+ });
@@ -1,5 +1,11 @@
1
1
  import type { Severity } from '../rules/Severity';
2
2
 
3
+ export type HeuristicNode = {
4
+ kind: 'class' | 'property' | 'call' | 'member';
5
+ name: string;
6
+ lines?: readonly number[];
7
+ };
8
+
3
9
  export interface HeuristicFact {
4
10
  kind: 'Heuristic';
5
11
  ruleId: string;
@@ -8,4 +14,9 @@ export interface HeuristicFact {
8
14
  message: string;
9
15
  filePath?: string;
10
16
  lines?: readonly number[];
17
+ primary_node?: HeuristicNode;
18
+ related_nodes?: readonly HeuristicNode[];
19
+ why?: string;
20
+ impact?: string;
21
+ expected_fix?: string;
11
22
  }
@@ -1,6 +1,11 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import test from 'node:test';
3
3
  import {
4
+ findKotlinConcreteDependencyDipMatch,
5
+ findKotlinInterfaceSegregationMatch,
6
+ findKotlinLiskovSubstitutionMatch,
7
+ findKotlinOpenClosedWhenMatch,
8
+ findKotlinPresentationSrpMatch,
4
9
  hasKotlinGlobalScopeUsage,
5
10
  hasKotlinRunBlockingUsage,
6
11
  hasKotlinThreadSleepCall,
@@ -85,3 +90,205 @@ fun main() {
85
90
  assert.equal(hasKotlinRunBlockingUsage(commentedSource), false);
86
91
  assert.equal(hasKotlinRunBlockingUsage(partialSource), false);
87
92
  });
93
+
94
+ test('findKotlinPresentationSrpMatch devuelve payload semantico para SRP-Android en presentation', () => {
95
+ const source = `
96
+ import android.content.SharedPreferences
97
+ import androidx.lifecycle.ViewModel
98
+ import androidx.navigation.NavController
99
+ import okhttp3.OkHttpClient
100
+ import okhttp3.Request
101
+
102
+ class PumukiSrpAndroidCanaryViewModel(
103
+ private val navController: NavController,
104
+ ) : ViewModel() {
105
+ fun restoreSessionSnapshot() {}
106
+
107
+ suspend fun fetchRemoteCatalog() {
108
+ val client = OkHttpClient()
109
+ client.newCall(
110
+ Request.Builder()
111
+ .url("https://example.com/catalog.json")
112
+ .build()
113
+ )
114
+ }
115
+
116
+ fun cacheLastStore(preferences: SharedPreferences, storeId: String) {
117
+ preferences.edit().putString("last-store-id", storeId).apply()
118
+ }
119
+
120
+ fun openStoreMap() {
121
+ navController.navigate("store-map")
122
+ }
123
+ }
124
+ `;
125
+
126
+ const match = findKotlinPresentationSrpMatch(source);
127
+
128
+ assert.ok(match);
129
+ assert.deepEqual(match.primary_node, {
130
+ kind: 'class',
131
+ name: 'PumukiSrpAndroidCanaryViewModel',
132
+ lines: [8],
133
+ });
134
+ assert.deepEqual(match.related_nodes, [
135
+ { kind: 'member', name: 'session/auth flow', lines: [11] },
136
+ { kind: 'call', name: 'remote networking', lines: [14] },
137
+ { kind: 'call', name: 'local persistence', lines: [22] },
138
+ { kind: 'member', name: 'navigation flow', lines: [27] },
139
+ ]);
140
+ assert.match(match.why, /SRP/i);
141
+ assert.match(match.impact, /múltiples razones de cambio/i);
142
+ assert.match(match.expected_fix, /casos de uso|coordinadores/i);
143
+ });
144
+
145
+ test('findKotlinConcreteDependencyDipMatch devuelve payload semantico para DIP-Android en application', () => {
146
+ const source = `
147
+ import android.content.SharedPreferences
148
+ import okhttp3.OkHttpClient
149
+ import okhttp3.Request
150
+
151
+ class PumukiDipAndroidCanaryUseCase(
152
+ private val preferences: SharedPreferences,
153
+ ) {
154
+ private val client: OkHttpClient = OkHttpClient()
155
+
156
+ suspend fun execute() {
157
+ val request = Request.Builder()
158
+ .url("https://example.com/catalog.json")
159
+ .build()
160
+
161
+ client.newCall(request)
162
+ preferences.edit().putLong("last-sync", 1L).apply()
163
+ }
164
+ }
165
+ `;
166
+
167
+ const match = findKotlinConcreteDependencyDipMatch(source);
168
+
169
+ assert.ok(match);
170
+ assert.deepEqual(match.primary_node, {
171
+ kind: 'class',
172
+ name: 'PumukiDipAndroidCanaryUseCase',
173
+ lines: [6],
174
+ });
175
+ assert.deepEqual(match.related_nodes, [
176
+ { kind: 'property', name: 'concrete dependency: SharedPreferences', lines: [7] },
177
+ { kind: 'property', name: 'concrete dependency: OkHttpClient', lines: [9] },
178
+ { kind: 'call', name: 'OkHttpClient()', lines: [9] },
179
+ ]);
180
+ assert.match(match.why, /DIP/i);
181
+ assert.match(match.impact, /infraestructura|alto nivel|coste de sustituir/i);
182
+ assert.match(match.expected_fix, /puertos|abstracciones|gateways/i);
183
+ });
184
+
185
+ test('findKotlinOpenClosedWhenMatch devuelve payload semantico para OCP-Android en application', () => {
186
+ const source = `
187
+ enum class PumukiOcpAndroidCanaryChannel {
188
+ GroceryPickup,
189
+ HomeDelivery,
190
+ }
191
+
192
+ class PumukiOcpAndroidCanaryUseCase {
193
+ fun resolve(channel: PumukiOcpAndroidCanaryChannel): String {
194
+ return when (channel) {
195
+ PumukiOcpAndroidCanaryChannel.GroceryPickup -> "pickup"
196
+ PumukiOcpAndroidCanaryChannel.HomeDelivery -> "delivery"
197
+ }
198
+ }
199
+ }
200
+ `;
201
+
202
+ const match = findKotlinOpenClosedWhenMatch(source);
203
+
204
+ assert.ok(match);
205
+ assert.deepEqual(match.primary_node, {
206
+ kind: 'class',
207
+ name: 'PumukiOcpAndroidCanaryUseCase',
208
+ lines: [7],
209
+ });
210
+ assert.deepEqual(match.related_nodes, [
211
+ { kind: 'member', name: 'discriminator switch: channel', lines: [9] },
212
+ { kind: 'member', name: 'branch GroceryPickup', lines: [10] },
213
+ { kind: 'member', name: 'branch HomeDelivery', lines: [11] },
214
+ ]);
215
+ assert.match(match.why, /OCP/i);
216
+ assert.match(match.impact, /nuevo caso|modificar/i);
217
+ assert.match(match.expected_fix, /estrategia|interfaz|registry/i);
218
+ });
219
+
220
+ test('findKotlinInterfaceSegregationMatch devuelve payload semantico para ISP-Android en application', () => {
221
+ const source = `
222
+ interface PumukiIspAndroidCanarySessionPort {
223
+ suspend fun restoreSession()
224
+ suspend fun persistSessionID(id: String)
225
+ suspend fun clearSession()
226
+ suspend fun refreshToken(): String
227
+ }
228
+
229
+ class PumukiIspAndroidCanaryUseCase(
230
+ private val sessionPort: PumukiIspAndroidCanarySessionPort,
231
+ ) {
232
+ suspend fun execute() {
233
+ sessionPort.restoreSession()
234
+ }
235
+ }
236
+ `;
237
+
238
+ const match = findKotlinInterfaceSegregationMatch(source);
239
+
240
+ assert.ok(match);
241
+ assert.deepEqual(match.primary_node, {
242
+ kind: 'class',
243
+ name: 'PumukiIspAndroidCanaryUseCase',
244
+ lines: [9],
245
+ });
246
+ assert.deepEqual(match.related_nodes, [
247
+ { kind: 'member', name: 'fat interface: PumukiIspAndroidCanarySessionPort', lines: [2] },
248
+ { kind: 'call', name: 'used member: restoreSession', lines: [13] },
249
+ { kind: 'member', name: 'unused contract member: persistSessionID', lines: [4] },
250
+ { kind: 'member', name: 'unused contract member: clearSession', lines: [5] },
251
+ ]);
252
+ assert.match(match.why, /ISP/i);
253
+ assert.match(match.impact, /contrato demasiado ancho|cambios ajenos/i);
254
+ assert.match(match.expected_fix, /interfaces pequeñas|puerto mínimo/i);
255
+ });
256
+
257
+ test('findKotlinLiskovSubstitutionMatch devuelve payload semantico para LSP-Android en application', () => {
258
+ const source = `
259
+ interface PumukiLspAndroidCanaryDiscountPolicy {
260
+ fun apply(amount: Double): Double
261
+ }
262
+
263
+ class PumukiLspAndroidCanaryStandardDiscountPolicy : PumukiLspAndroidCanaryDiscountPolicy {
264
+ override fun apply(amount: Double): Double {
265
+ return amount * 0.9
266
+ }
267
+ }
268
+
269
+ class PumukiLspAndroidCanaryPremiumDiscountPolicy : PumukiLspAndroidCanaryDiscountPolicy {
270
+ override fun apply(amount: Double): Double {
271
+ require(amount >= 100.0)
272
+ error("premium-only")
273
+ }
274
+ }
275
+ `;
276
+
277
+ const match = findKotlinLiskovSubstitutionMatch(source);
278
+
279
+ assert.ok(match);
280
+ assert.deepEqual(match.primary_node, {
281
+ kind: 'class',
282
+ name: 'PumukiLspAndroidCanaryPremiumDiscountPolicy',
283
+ lines: [12],
284
+ });
285
+ assert.deepEqual(match.related_nodes, [
286
+ { kind: 'member', name: 'base contract: PumukiLspAndroidCanaryDiscountPolicy', lines: [2] },
287
+ { kind: 'member', name: 'safe substitute: PumukiLspAndroidCanaryStandardDiscountPolicy', lines: [6] },
288
+ { kind: 'member', name: 'narrowed precondition: apply', lines: [14] },
289
+ { kind: 'call', name: 'error', lines: [15] },
290
+ ]);
291
+ assert.match(match.why, /LSP/i);
292
+ assert.match(match.impact, /sustituci|regresion|crash/i);
293
+ assert.match(match.expected_fix, /contrato base|estrategia|subtipo/i);
294
+ });