pumuki 6.3.97 → 6.3.99

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 (96) hide show
  1. package/AGENTS.md +269 -0
  2. package/CHANGELOG.md +697 -0
  3. package/README.md +4 -2
  4. package/VERSION +1 -1
  5. package/docs/README.md +13 -9
  6. package/docs/operations/RELEASE_NOTES.md +12 -76
  7. package/docs/product/HOW_IT_WORKS.md +6 -0
  8. package/docs/product/INSTALLATION.md +1 -1
  9. package/docs/product/USAGE.md +41 -4
  10. package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +118 -0
  11. package/docs/validation/README.md +6 -3
  12. package/integrations/config/skillsCustomRules.ts +18 -99
  13. package/integrations/evidence/buildEvidence.ts +0 -24
  14. package/integrations/evidence/repoState.ts +0 -3
  15. package/integrations/evidence/schema.ts +0 -18
  16. package/integrations/evidence/writeEvidence.ts +0 -24
  17. package/integrations/gate/evaluateAiGate.ts +15 -232
  18. package/integrations/gate/remediationCatalog.ts +0 -8
  19. package/integrations/git/GitService.ts +44 -5
  20. package/integrations/git/aiGateRepoPolicyFindings.ts +0 -4
  21. package/integrations/git/runPlatformGate.ts +1 -9
  22. package/integrations/git/runPlatformGateFacts.ts +19 -1
  23. package/integrations/git/runPlatformGateOutput.ts +27 -36
  24. package/integrations/lifecycle/adapter.templates.json +7 -13
  25. package/integrations/lifecycle/adapter.ts +0 -24
  26. package/integrations/lifecycle/artifacts.ts +1 -6
  27. package/integrations/lifecycle/audit.ts +101 -0
  28. package/integrations/lifecycle/cli.ts +110 -70
  29. package/integrations/lifecycle/cliSdd.ts +13 -8
  30. package/integrations/lifecycle/doctor.ts +16 -48
  31. package/integrations/lifecycle/hookManager.ts +0 -77
  32. package/integrations/lifecycle/index.ts +2 -0
  33. package/integrations/lifecycle/install.ts +0 -21
  34. package/integrations/lifecycle/npmService.ts +3 -155
  35. package/integrations/lifecycle/policyValidationSnapshot.ts +8 -2
  36. package/integrations/lifecycle/preWriteAutomation.ts +7 -77
  37. package/integrations/lifecycle/state.ts +1 -8
  38. package/integrations/lifecycle/status.ts +2 -29
  39. package/integrations/mcp/aiGateCheck.ts +26 -206
  40. package/integrations/mcp/autoExecuteAiStart.ts +87 -94
  41. package/integrations/mcp/enterpriseServer.ts +7 -23
  42. package/integrations/mcp/enterpriseStdioServer.cli.ts +4 -31
  43. package/integrations/mcp/preFlightCheck.ts +5 -51
  44. package/integrations/platform/detectPlatforms.ts +37 -0
  45. package/integrations/policy/experimentalFeatures.ts +1 -1
  46. package/integrations/sdd/evidenceScaffold.ts +2 -109
  47. package/package.json +10 -2
  48. package/scripts/check-tracking-single-active.sh +1 -1
  49. package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
  50. package/scripts/consumer-postinstall-resolve-args.cjs +44 -0
  51. package/scripts/consumer-postinstall.cjs +76 -21
  52. package/scripts/framework-menu-advanced-view-lib.ts +0 -15
  53. package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
  54. package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
  55. package/scripts/framework-menu-consumer-preflight-render.ts +0 -10
  56. package/scripts/framework-menu-consumer-preflight-run.ts +0 -23
  57. package/scripts/framework-menu-consumer-preflight-types.ts +0 -12
  58. package/scripts/framework-menu-consumer-runtime-actions.ts +87 -17
  59. package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
  60. package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
  61. package/scripts/framework-menu-consumer-runtime-lib.ts +2 -10
  62. package/scripts/framework-menu-consumer-runtime-menu.ts +4 -18
  63. package/scripts/framework-menu-consumer-runtime-types.ts +3 -3
  64. package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
  65. package/scripts/framework-menu-evidence-summary-read.ts +57 -5
  66. package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
  67. package/scripts/framework-menu-evidence-summary-types.ts +7 -0
  68. package/scripts/framework-menu-gate-lib.ts +9 -0
  69. package/scripts/framework-menu-layout-data.ts +5 -0
  70. package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
  71. package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
  72. package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
  73. package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
  74. package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
  75. package/scripts/framework-menu-system-notifications-cause.ts +0 -24
  76. package/scripts/framework-menu-system-notifications-macos-swift-source.ts +24 -204
  77. package/scripts/framework-menu-system-notifications-macos.ts +4 -0
  78. package/scripts/framework-menu-system-notifications-payloads-blocked.ts +1 -1
  79. package/scripts/framework-menu-system-notifications-remediation.ts +13 -24
  80. package/scripts/framework-menu-system-notifications-text.ts +1 -7
  81. package/scripts/framework-menu.ts +3 -2
  82. package/scripts/package-install-smoke-consumer-git-repo-lib.ts +1 -10
  83. package/scripts/package-install-smoke-consumer-npm-lib.ts +9 -46
  84. package/scripts/pumuki-full-surface-smoke-lib.ts +37 -0
  85. package/scripts/pumuki-full-surface-smoke.ts +346 -0
  86. package/scripts/pumuki-smoke-installed-wrapper.cjs +31 -0
  87. package/integrations/evidence/trackingContract.ts +0 -150
  88. package/integrations/gate/governanceActionCatalog.ts +0 -275
  89. package/integrations/lifecycle/bootstrapManifest.ts +0 -248
  90. package/integrations/lifecycle/cliGovernanceConsole.ts +0 -69
  91. package/integrations/lifecycle/governanceNextAction.ts +0 -164
  92. package/integrations/lifecycle/governanceObservationSnapshot.ts +0 -613
  93. package/integrations/mcp/alignedPlatformGate.ts +0 -232
  94. package/integrations/mcp/readMcpPrePushStdin.ts +0 -7
  95. package/scripts/build-ruralgo-s1-evidence-pack.ts +0 -85
  96. package/scripts/ruralgo-s1-evidence-pack-lib.ts +0 -200
@@ -19,6 +19,11 @@ export type GateScope =
19
19
  kind: 'workingTree';
20
20
  extensions?: string[];
21
21
  }
22
+ | {
23
+ kind: 'unstaged';
24
+ extensions?: string[];
25
+ includeUntracked?: boolean;
26
+ }
22
27
  | {
23
28
  kind: 'range';
24
29
  fromRef: string;
@@ -26,7 +31,17 @@ export type GateScope =
26
31
  extensions?: string[];
27
32
  };
28
33
 
29
- const DEFAULT_EXTENSIONS = ['.swift', '.ts', '.tsx', '.js', '.jsx', '.kt', '.kts'];
34
+ export const DEFAULT_FACT_FILE_EXTENSIONS: ReadonlyArray<string> = [
35
+ '.swift',
36
+ '.ts',
37
+ '.tsx',
38
+ '.js',
39
+ '.jsx',
40
+ '.kt',
41
+ '.kts',
42
+ ];
43
+
44
+ const DEFAULT_EXTENSIONS = DEFAULT_FACT_FILE_EXTENSIONS;
30
45
 
31
46
  export const countScannedFilesFromFacts = (facts: ReadonlyArray<Fact>): number => {
32
47
  const contentPaths = new Set<string>();
@@ -66,6 +81,9 @@ export const resolveFactsForGateScope = async (params: {
66
81
  if (params.scope.kind === 'workingTree') {
67
82
  return params.git.getStagedAndUnstagedFacts(extensions);
68
83
  }
84
+ if (params.scope.kind === 'unstaged') {
85
+ return params.git.getUnstagedFacts(extensions, params.scope.includeUntracked);
86
+ }
69
87
 
70
88
  return getFactsForCommitRange({
71
89
  fromRef: params.scope.fromRef,
@@ -1,5 +1,27 @@
1
1
  import type { Finding } from '../../core/gate/Finding';
2
- import { resolveGovernanceCatalogAction } from '../gate/governanceActionCatalog';
2
+
3
+ const BLOCK_NEXT_ACTION_BY_CODE: Readonly<Record<string, string>> = {
4
+ SDD_SESSION_MISSING:
5
+ 'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>',
6
+ SDD_SESSION_INVALID:
7
+ 'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90',
8
+ PRE_PUSH_UPSTREAM_MISSING:
9
+ 'git push --set-upstream origin <branch>',
10
+ PRE_PUSH_UPSTREAM_MISALIGNED:
11
+ 'git branch --unset-upstream && git push --set-upstream origin <branch>',
12
+ EVIDENCE_STALE:
13
+ 'npx --yes --package pumuki@latest pumuki-pre-commit',
14
+ EVIDENCE_BRANCH_MISMATCH:
15
+ 'npx --yes --package pumuki@latest pumuki-pre-commit',
16
+ GIT_ATOMICITY_TOO_MANY_FILES:
17
+ 'git restore --staged . && separa cambios en commits más pequeños',
18
+ GIT_ATOMICITY_TOO_MANY_SCOPES:
19
+ 'Revisa scope_files del bloqueo y aplica: git restore --staged . && git add <scope>/ && git commit -m "<tipo>: <scope>"',
20
+ ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES_HIGH:
21
+ 'Reconcilia policy/skills y reintenta PRE_COMMIT: npx --yes --package pumuki@latest pumuki policy reconcile --strict --json && npx --yes --package pumuki@latest pumuki-pre-commit',
22
+ SKILLS_SKILLS_FRONTEND_NO_SOLID_VIOLATIONS:
23
+ 'Aplica refactor incremental: extrae 1 componente/hook por commit y vuelve a ejecutar PRE_COMMIT.',
24
+ };
3
25
 
4
26
  const severityWeight = (severity: string): number => {
5
27
  switch (severity.toUpperCase()) {
@@ -72,49 +94,18 @@ const formatFinding = (finding: Finding): string => {
72
94
  return `[${severity}] ${finding.ruleId}: ${finding.message} -> ${location}`;
73
95
  };
74
96
 
75
- const resolveAtomicityFallback = (code: string): string | null => {
76
- switch (code) {
77
- case 'GIT_ATOMICITY_TOO_MANY_FILES':
78
- return 'git restore --staged . && separa cambios en commits más pequeños';
79
- case 'GIT_ATOMICITY_TOO_MANY_SCOPES':
80
- return 'Revisa scope_files del bloqueo y aplica: git restore --staged . && git add <scope>/ && git commit -m "<tipo>: <scope>"';
81
- default:
82
- return null;
83
- }
84
- };
85
-
86
- export const printGateFindings = (
87
- findings: ReadonlyArray<Finding>,
88
- params?: { stage?: 'PRE_COMMIT' | 'PRE_PUSH' | 'CI' }
89
- ): void => {
97
+ export const printGateFindings = (findings: ReadonlyArray<Finding>): void => {
90
98
  if (findings.length === 0) {
91
99
  return;
92
100
  }
93
101
  const primary = resolvePrimaryFinding(findings);
94
- const action = resolveGovernanceCatalogAction({
95
- code: primary.code,
96
- stage: params?.stage ?? 'PRE_COMMIT',
97
- fallback: {
98
- reason_code: primary.code,
99
- instruction: 'Corrige el bloqueante primario y vuelve a ejecutar la validación del stage actual.',
100
- next_action: {
101
- kind: 'info',
102
- message:
103
- resolveAtomicityFallback(primary.code)
104
- ?? 'Corrige el bloqueante primario y vuelve a ejecutar el mismo comando.',
105
- },
106
- },
107
- });
108
- const nextAction = action.next_action.command ?? action.next_action.message;
102
+ const nextAction =
103
+ BLOCK_NEXT_ACTION_BY_CODE[primary.code]
104
+ ?? 'Corrige el bloqueante primario y vuelve a ejecutar el mismo comando.';
109
105
  process.stdout.write(
110
106
  `[pumuki][block-summary] primary=${primary.code} severity=${primary.severity.toUpperCase()} rule=${primary.ruleId}\n`
111
107
  );
112
- process.stdout.write(`[pumuki][block-summary] reason_code=${action.reason_code}\n`);
113
- process.stdout.write(`[pumuki][block-summary] instruction=${action.instruction}\n`);
114
108
  process.stdout.write(`[pumuki][block-summary] next_action=${nextAction}\n`);
115
- if (action.next_action.command) {
116
- process.stdout.write(`[pumuki][block-summary] command=${action.next_action.command}\n`);
117
- }
118
109
  for (const finding of findings) {
119
110
  process.stdout.write(`${formatFinding(finding)}\n`);
120
111
  }
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "mcp": {
21
21
  "enterprise": {
22
- "command": "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE=advisory npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
22
+ "command": "npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
23
23
  },
24
24
  "evidence": {
25
25
  "command": "npx --yes --package pumuki@latest pumuki-mcp-evidence-stdio"
@@ -31,6 +31,7 @@
31
31
  "repo": [
32
32
  {
33
33
  "path": ".pumuki/adapter.json",
34
+ "mode": "json-merge",
34
35
  "payload": {
35
36
  "hooks": {
36
37
  "pre_write": {
@@ -48,7 +49,7 @@
48
49
  },
49
50
  "mcp": {
50
51
  "enterprise": {
51
- "command": "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE=advisory npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
52
+ "command": "npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
52
53
  },
53
54
  "evidence": {
54
55
  "command": "npx --yes --package pumuki@latest pumuki-mcp-evidence-stdio"
@@ -85,10 +86,7 @@
85
86
  "--package",
86
87
  "pumuki@latest",
87
88
  "pumuki-mcp-enterprise-stdio"
88
- ],
89
- "env": {
90
- "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE": "advisory"
91
- }
89
+ ]
92
90
  },
93
91
  "pumuki-evidence": {
94
92
  "command": "npx",
@@ -116,10 +114,7 @@
116
114
  "--package",
117
115
  "pumuki@latest",
118
116
  "pumuki-mcp-enterprise-stdio"
119
- ],
120
- "env": {
121
- "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE": "advisory"
122
- }
117
+ ]
123
118
  },
124
119
  "pumuki-evidence": {
125
120
  "command": "npx",
@@ -183,7 +178,7 @@
183
178
  "postCommand": "npx --yes --package pumuki@latest pumuki-pre-commit",
184
179
  "pushCommand": "npx --yes --package pumuki@latest pumuki-pre-push",
185
180
  "ciCommand": "npx --yes --package pumuki@latest pumuki-ci",
186
- "mcpCommand": "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE=advisory npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
181
+ "mcpCommand": "npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
187
182
  }
188
183
  },
189
184
  {
@@ -201,7 +196,6 @@
201
196
  ],
202
197
  "disabledTools": [],
203
198
  "env": {
204
- "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE": "advisory",
205
199
  "PUMUKI_ENTERPRISE_MCP_PORT": "0",
206
200
  "PUMUKI_ENTERPRISE_MCP_HOST": "127.0.0.1"
207
201
  },
@@ -247,7 +241,7 @@
247
241
  },
248
242
  "mcp": {
249
243
  "enterprise": {
250
- "command": "PUMUKI_EXPERIMENTAL_MCP_ENTERPRISE=advisory npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
244
+ "command": "npx --yes --package pumuki@latest pumuki-mcp-enterprise-stdio"
251
245
  },
252
246
  "evidence": {
253
247
  "command": "npx --yes --package pumuki@latest pumuki-mcp-evidence-stdio"
@@ -2,7 +2,6 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { dirname, isAbsolute, join, resolve } from 'node:path';
4
4
  import { LifecycleGitService, type ILifecycleGitService } from './gitService';
5
- import { writeLifecycleBootstrapManifest } from './bootstrapManifest';
6
5
 
7
6
  export type AdapterAgent = string;
8
7
 
@@ -12,10 +11,6 @@ export type LifecycleAdapterInstallResult = {
12
11
  dryRun: boolean;
13
12
  written: boolean;
14
13
  changedFiles: ReadonlyArray<string>;
15
- bootstrapManifest: {
16
- path: string;
17
- changed: boolean;
18
- };
19
14
  };
20
15
 
21
16
  type AdapterTemplate = {
@@ -159,30 +154,11 @@ export const runLifecycleAdapterInstall = (params: {
159
154
  writeFileSync(absolutePath, nextContents, 'utf8');
160
155
  }
161
156
 
162
- let bootstrapManifest = {
163
- path: join(repoRoot, '.pumuki', 'bootstrap-manifest.json'),
164
- changed: false,
165
- };
166
- if (!dryRun) {
167
- const manifestWrite = writeLifecycleBootstrapManifest({
168
- git,
169
- repoRoot,
170
- });
171
- bootstrapManifest = {
172
- path: manifestWrite.path,
173
- changed: manifestWrite.changed,
174
- };
175
- if (manifestWrite.changed) {
176
- changedFiles.push('.pumuki/bootstrap-manifest.json');
177
- }
178
- }
179
-
180
157
  return {
181
158
  repoRoot,
182
159
  agent: params.agent,
183
160
  dryRun,
184
161
  written: !dryRun,
185
162
  changedFiles,
186
- bootstrapManifest,
187
163
  };
188
164
  };
@@ -11,12 +11,7 @@ import {
11
11
  import { dirname, isAbsolute, join, resolve } from 'node:path';
12
12
  import type { ILifecycleGitService } from './gitService';
13
13
 
14
- const PUMUKI_ARTIFACTS = [
15
- '.ai_evidence.json',
16
- '.AI_EVIDENCE.json',
17
- '.pumuki/adapter.json',
18
- '.pumuki/bootstrap-manifest.json',
19
- ] as const;
14
+ const PUMUKI_ARTIFACTS = ['.ai_evidence.json', '.AI_EVIDENCE.json'] as const;
20
15
  const RUNTIME_ARTIFACT_IGNORE_ENTRIES = [...PUMUKI_ARTIFACTS, '.pumuki/'] as const;
21
16
  const RUNTIME_ARTIFACT_IGNORE_BEGIN = '# >>> pumuki-runtime-artifacts >>>';
22
17
  const RUNTIME_ARTIFACT_IGNORE_END = '# <<< pumuki-runtime-artifacts <<<';
@@ -0,0 +1,101 @@
1
+ import { readEvidence } from '../evidence/readEvidence';
2
+ import { GitService } from '../git/GitService';
3
+ import { hasAllowedExtension } from '../git/gitDiffUtils';
4
+ import { runPlatformGate } from '../git/runPlatformGate';
5
+ import { evaluatePlatformGateFindings } from '../git/runPlatformGateEvaluation';
6
+ import { DEFAULT_FACT_FILE_EXTENSIONS } from '../git/runPlatformGateFacts';
7
+ import { resolvePolicyForStage } from '../gate/stagePolicies';
8
+
9
+ export type LifecycleAuditStage = 'PRE_COMMIT' | 'PRE_PUSH' | 'CI';
10
+
11
+ export type LifecycleAuditResult = {
12
+ command: 'pumuki audit';
13
+ repo_root: string;
14
+ stage: LifecycleAuditStage;
15
+ scope: { kind: 'repo' };
16
+ audit_mode: 'gate' | 'engine';
17
+ gate_exit_code: number;
18
+ files_scanned: number | null;
19
+ untracked_matching_extensions_count: number;
20
+ snapshot_outcome: string | null;
21
+ policy_reconcile_hint: string;
22
+ };
23
+
24
+ const POLICY_RECONCILE_HINT =
25
+ 'If .pumuki/policy-as-code.json signatures drift after a pumuki upgrade, run: pumuki policy reconcile --apply';
26
+
27
+ const countUntrackedMatchingExtensions = (
28
+ git: GitService,
29
+ extensions: ReadonlyArray<string>
30
+ ): number => {
31
+ const repoRoot = git.resolveRepoRoot();
32
+ const raw = git.runGit(['ls-files', '--others', '--exclude-standard'], repoRoot);
33
+ return raw
34
+ .split('\n')
35
+ .map((line) => line.trim())
36
+ .filter((line) => line.length > 0)
37
+ .filter((path) => hasAllowedExtension(path, extensions)).length;
38
+ };
39
+
40
+ export const runLifecycleAudit = async (params: {
41
+ stage: LifecycleAuditStage;
42
+ auditMode: 'gate' | 'engine';
43
+ }): Promise<LifecycleAuditResult> => {
44
+ const git = new GitService();
45
+ const repoRoot = git.resolveRepoRoot();
46
+ const resolved = resolvePolicyForStage(params.stage, repoRoot);
47
+ const extensions = DEFAULT_FACT_FILE_EXTENSIONS;
48
+ const untrackedMatchingExtensionsCount = countUntrackedMatchingExtensions(git, extensions);
49
+
50
+ const gateParams =
51
+ params.auditMode === 'engine'
52
+ ? {
53
+ policy: resolved.policy,
54
+ policyTrace: resolved.trace,
55
+ scope: { kind: 'repo' as const },
56
+ silent: true,
57
+ auditMode: 'engine' as const,
58
+ dependencies: {
59
+ evaluatePlatformGateFindings: (
60
+ evalParams: Parameters<typeof evaluatePlatformGateFindings>[0]
61
+ ) =>
62
+ evaluatePlatformGateFindings(evalParams, {
63
+ loadHeuristicsConfig: () => ({
64
+ astSemanticEnabled: true,
65
+ typeScriptScope: 'all',
66
+ }),
67
+ }),
68
+ printGateFindings: () => {},
69
+ },
70
+ }
71
+ : {
72
+ policy: resolved.policy,
73
+ policyTrace: resolved.trace,
74
+ scope: { kind: 'repo' as const },
75
+ silent: true,
76
+ auditMode: 'gate' as const,
77
+ };
78
+
79
+ const gateExitCode = await runPlatformGate(gateParams);
80
+ const evidence = readEvidence(repoRoot);
81
+ const filesScanned =
82
+ typeof evidence?.snapshot.files_scanned === 'number' &&
83
+ Number.isFinite(evidence.snapshot.files_scanned)
84
+ ? evidence.snapshot.files_scanned
85
+ : null;
86
+ const snapshotOutcome =
87
+ typeof evidence?.snapshot.outcome === 'string' ? evidence.snapshot.outcome : null;
88
+
89
+ return {
90
+ command: 'pumuki audit',
91
+ repo_root: repoRoot,
92
+ stage: params.stage,
93
+ scope: { kind: 'repo' },
94
+ audit_mode: params.auditMode,
95
+ gate_exit_code: gateExitCode,
96
+ files_scanned: filesScanned,
97
+ untracked_matching_extensions_count: untrackedMatchingExtensionsCount,
98
+ snapshot_outcome: snapshotOutcome,
99
+ policy_reconcile_hint: POLICY_RECONCILE_HINT,
100
+ };
101
+ };