pumuki 6.3.72 → 6.3.75

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 (64) hide show
  1. package/docs/README.md +9 -7
  2. package/docs/operations/RELEASE_NOTES.md +0 -7
  3. package/docs/product/USAGE.md +2 -5
  4. package/docs/validation/README.md +3 -1
  5. package/integrations/evidence/buildEvidence.ts +14 -0
  6. package/integrations/evidence/repoState.ts +3 -0
  7. package/integrations/evidence/schema.ts +18 -0
  8. package/integrations/evidence/trackingContract.ts +146 -0
  9. package/integrations/evidence/writeEvidence.ts +14 -0
  10. package/integrations/gate/evaluateAiGate.ts +166 -3
  11. package/integrations/gate/governanceActionCatalog.ts +275 -0
  12. package/integrations/gate/remediationCatalog.ts +8 -0
  13. package/integrations/git/GitService.ts +0 -25
  14. package/integrations/git/aiGateRepoPolicyFindings.ts +4 -0
  15. package/integrations/git/runPlatformGate.ts +9 -1
  16. package/integrations/git/runPlatformGateFacts.ts +0 -7
  17. package/integrations/git/runPlatformGateOutput.ts +36 -27
  18. package/integrations/lifecycle/adapter.ts +24 -0
  19. package/integrations/lifecycle/bootstrapManifest.ts +248 -0
  20. package/integrations/lifecycle/cli.ts +45 -11
  21. package/integrations/lifecycle/cliSdd.ts +4 -3
  22. package/integrations/lifecycle/doctor.ts +49 -1
  23. package/integrations/lifecycle/governanceNextAction.ts +164 -0
  24. package/integrations/lifecycle/governanceObservationSnapshot.ts +315 -0
  25. package/integrations/lifecycle/install.ts +21 -0
  26. package/integrations/lifecycle/state.ts +8 -1
  27. package/integrations/lifecycle/status.ts +29 -2
  28. package/integrations/mcp/aiGateCheck.ts +140 -10
  29. package/integrations/mcp/alignedPlatformGate.ts +232 -0
  30. package/integrations/mcp/autoExecuteAiStart.ts +92 -85
  31. package/integrations/mcp/enterpriseServer.ts +6 -6
  32. package/integrations/mcp/preFlightCheck.ts +51 -5
  33. package/integrations/mcp/readMcpPrePushStdin.ts +7 -0
  34. package/integrations/policy/experimentalFeatures.ts +1 -1
  35. package/package.json +2 -4
  36. package/scripts/build-ruralgo-s1-evidence-pack.ts +85 -0
  37. package/scripts/consumer-menu-matrix-baseline-report-lib.ts +38 -13
  38. package/scripts/framework-menu-consumer-actions-lib.ts +4 -28
  39. package/scripts/framework-menu-consumer-preflight-hints.ts +2 -5
  40. package/scripts/framework-menu-consumer-preflight-render.ts +6 -0
  41. package/scripts/framework-menu-consumer-preflight-run.ts +19 -0
  42. package/scripts/framework-menu-consumer-preflight-types.ts +8 -0
  43. package/scripts/framework-menu-consumer-runtime-actions.ts +6 -86
  44. package/scripts/framework-menu-consumer-runtime-audit.ts +2 -36
  45. package/scripts/framework-menu-consumer-runtime-lib.ts +0 -2
  46. package/scripts/framework-menu-consumer-runtime-types.ts +1 -3
  47. package/scripts/framework-menu-evidence-summary-lib.ts +0 -1
  48. package/scripts/framework-menu-evidence-summary-read.ts +5 -57
  49. package/scripts/framework-menu-evidence-summary-severity.ts +1 -3
  50. package/scripts/framework-menu-evidence-summary-types.ts +0 -7
  51. package/scripts/framework-menu-gate-lib.ts +0 -9
  52. package/scripts/framework-menu-layout-data.ts +0 -5
  53. package/scripts/framework-menu-matrix-baseline-lib.ts +14 -15
  54. package/scripts/framework-menu-matrix-canary-lib.ts +1 -22
  55. package/scripts/framework-menu-matrix-evidence-lib.ts +0 -1
  56. package/scripts/framework-menu-matrix-evidence-types.ts +1 -13
  57. package/scripts/framework-menu-matrix-runner-lib.ts +0 -35
  58. package/scripts/framework-menu-system-notifications-macos.ts +0 -4
  59. package/scripts/framework-menu.ts +0 -3
  60. package/scripts/ruralgo-s1-evidence-pack-lib.ts +200 -0
  61. package/AGENTS.md +0 -269
  62. package/CHANGELOG.md +0 -666
  63. package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +0 -111
  64. package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +0 -140
@@ -1,11 +1,14 @@
1
+ import {
2
+ resolveGovernanceCatalogAction,
3
+ type GovernanceCatalogNextAction,
4
+ } from '../gate/governanceActionCatalog';
1
5
  import { evaluateAiGate, type AiGateStage, type AiGateViolation } from '../gate/evaluateAiGate';
2
6
  import { collectWorktreeAtomicSlices } from '../git/worktreeAtomicSlices';
3
7
  import { resolveLearningContextExperimentalFeature } from '../policy/experimentalFeatures';
4
8
  import { readSddLearningContext, type SddLearningContext } from '../sdd/learningInsights';
5
9
 
6
10
  const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
7
- EVIDENCE_MISSING:
8
- 'Ejecuta una auditoría (1/2/3/4 u opciones de motor 11–14) para regenerar .ai_evidence.json.',
11
+ EVIDENCE_MISSING: 'Ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.',
9
12
  EVIDENCE_INVALID: 'Regenera .ai_evidence.json desde una opción de auditoría.',
10
13
  EVIDENCE_INTEGRITY_MISSING: 'Refresca evidencia para regenerar metadatos de integridad.',
11
14
  EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES:
@@ -39,6 +42,28 @@ const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
39
42
  'Mapea todas las reglas AUTO a detectores AST antes de continuar.',
40
43
  EVIDENCE_TIMESTAMP_FUTURE: 'Corrige la hora del sistema y regenera evidencia.',
41
44
  GITFLOW_PROTECTED_BRANCH: 'Evita trabajo directo en ramas protegidas (usa feature/*).',
45
+ GITFLOW_BRANCH_NAMING_INVALID:
46
+ 'La rama actual no cumple GitFlow. Usa feature/*, bugfix/*, hotfix/*, release/*, chore/*, refactor/* o docs/*.',
47
+ TRACKING_CANONICAL_SOURCE_CONFLICT:
48
+ 'AGENTS.md y los README del repo no apuntan a la misma fuente canónica de tracking.',
49
+ TRACKING_CANONICAL_FILE_MISSING:
50
+ 'El repo declara un MD de tracking canónico que ahora mismo no existe.',
51
+ TRACKING_CANONICAL_IN_PROGRESS_INVALID:
52
+ 'El MD canónico de tracking debe dejar exactamente una task o fase en construcción.',
53
+ };
54
+
55
+ const normalizeGovernanceCatalogCode = (code: string): string => {
56
+ switch (code) {
57
+ case 'EVIDENCE_INVALID':
58
+ case 'EVIDENCE_CHAIN_INVALID':
59
+ return 'EVIDENCE_INVALID_OR_CHAIN';
60
+ case 'GITFLOW_PROTECTED_BRANCH':
61
+ return 'GITFLOW_PROTECTED_BRANCH_CONTEXT';
62
+ case 'GITFLOW_BRANCH_NAMING_INVALID':
63
+ return 'GITFLOW_BRANCH_NAMING_INVALID_CONTEXT';
64
+ default:
65
+ return code;
66
+ }
42
67
  };
43
68
 
44
69
  const buildPreFlightHints = (params: {
@@ -115,6 +140,8 @@ export type EnterprisePreFlightCheckResult = {
115
140
  phase: 'GREEN' | 'RED';
116
141
  message: string;
117
142
  instruction: string;
143
+ reason_code: string;
144
+ next_action: GovernanceCatalogNextAction;
118
145
  stage: ReturnType<typeof evaluateAiGate>['stage'];
119
146
  policy: ReturnType<typeof evaluateAiGate>['policy'];
120
147
  violations: ReturnType<typeof evaluateAiGate>['violations'];
@@ -154,13 +181,30 @@ export const runEnterprisePreFlightCheck = (params: {
154
181
  upstream: evaluation.repo_state.git.upstream,
155
182
  learningContext,
156
183
  });
184
+ const firstViolation = evaluation.violations[0];
185
+ const reasonCode = firstViolation?.code ?? 'READY';
186
+ const governanceAction = firstViolation
187
+ ? resolveGovernanceCatalogAction({
188
+ code: normalizeGovernanceCatalogCode(firstViolation.code),
189
+ stage: evaluation.stage,
190
+ })
191
+ : resolveGovernanceCatalogAction({
192
+ code: 'READY',
193
+ stage: evaluation.stage,
194
+ });
157
195
  const phase: 'GREEN' | 'RED' = evaluation.allowed ? 'GREEN' : 'RED';
158
196
  const message = evaluation.allowed
159
197
  ? '✅ Pre-flight aprobado: puedes continuar con la implementación.'
160
- : `🔴 Pre-flight bloqueado: corrige ${evaluation.violations[0]?.code ?? 'la causa'} y vuelve a ejecutar.`;
161
- const instruction = evaluation.allowed
198
+ : `🔴 Pre-flight bloqueado: corrige ${reasonCode} y vuelve a ejecutar.`;
199
+ const instruction = !firstViolation && evaluation.allowed
162
200
  ? 'Implementa el cambio mínimo para pasar en verde y vuelve a validar.'
163
- : hints[0] ?? 'Corrige la causa bloqueante y vuelve a ejecutar el pre-flight.';
201
+ : governanceAction.instruction;
202
+ const nextAction: GovernanceCatalogNextAction = evaluation.allowed
203
+ ? {
204
+ kind: 'info',
205
+ message: governanceAction.next_action.message,
206
+ }
207
+ : governanceAction.next_action;
164
208
 
165
209
  return {
166
210
  tool: 'pre_flight_check',
@@ -173,6 +217,8 @@ export const runEnterprisePreFlightCheck = (params: {
173
217
  phase,
174
218
  message,
175
219
  instruction,
220
+ reason_code: reasonCode,
221
+ next_action: nextAction,
176
222
  stage: evaluation.stage,
177
223
  policy: evaluation.policy,
178
224
  violations: evaluation.violations,
@@ -0,0 +1,7 @@
1
+ export const readMcpPrePushStdin = (): string => {
2
+ const envInput = process.env.PUMUKI_PRE_PUSH_STDIN;
3
+ if (typeof envInput === 'string' && envInput.trim().length > 0) {
4
+ return envInput;
5
+ }
6
+ return '';
7
+ };
@@ -40,7 +40,7 @@ type ExperimentalFeatureConfig = {
40
40
 
41
41
  const EXPERIMENTAL_FEATURES: Record<ExperimentalFeatureId, ExperimentalFeatureConfig> = {
42
42
  pre_write: {
43
- defaultMode: 'off',
43
+ defaultMode: 'strict',
44
44
  activationVariable: 'PUMUKI_EXPERIMENTAL_PRE_WRITE',
45
45
  legacyActivationVariable: 'PUMUKI_PREWRITE_ENFORCEMENT',
46
46
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.72",
3
+ "version": "6.3.75",
4
4
  "description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -149,6 +149,7 @@
149
149
  "validation:lifecycle-smoke": "node --import tsx scripts/package-install-smoke.ts --mode=minimal",
150
150
  "validation:contract-suite:enterprise": "node --import tsx scripts/run-enterprise-contract-suite.ts",
151
151
  "validation:consumer-matrix-baseline": "node --import tsx scripts/build-consumer-menu-matrix-baseline.ts",
152
+ "validation:ruralgo-s1-evidence-pack": "npx --yes tsx@4.21.0 scripts/build-ruralgo-s1-evidence-pack.ts",
152
153
  "validation:c020-benchmark": "node --import tsx scripts/run-c020-benchmark.ts",
153
154
  "validation:clean-artifacts": "npx --yes tsx@4.21.0 scripts/clean-validation-artifacts.ts",
154
155
  "skills:compile": "npx --yes tsx@4.21.0 scripts/compile-skills-lock.ts",
@@ -259,13 +260,10 @@
259
260
  "docs/product/*.md",
260
261
  "docs/rule-packs/*.md",
261
262
  "docs/validation/*.md",
262
- "docs/tracking/plan-curso-pumuki-stack-my-architecture.md",
263
263
  "assets/**/*",
264
264
  "vendor/skills/**/*",
265
265
  "index.js",
266
266
  "README.md",
267
- "AGENTS.md",
268
- "CHANGELOG.md",
269
267
  "LICENSE",
270
268
  "VERSION",
271
269
  "tsconfig.json",
@@ -0,0 +1,85 @@
1
+ import {
2
+ buildRuralGoS1EvidencePackMarkdown,
3
+ writeRuralGoS1EvidencePack,
4
+ } from './ruralgo-s1-evidence-pack-lib';
5
+
6
+ type CliOptions = {
7
+ consumerRoot: string;
8
+ outFile: string;
9
+ packageVersion: string;
10
+ generatedAt: string;
11
+ };
12
+
13
+ const parseArgs = (argv: ReadonlyArray<string>): CliOptions => {
14
+ const options: CliOptions = {
15
+ consumerRoot: '<RURALGO_REPO_ROOT>',
16
+ outFile: '.audit-reports/ruralgo-s1/ruralgo-s1-evidence-pack.md',
17
+ packageVersion: 'unknown',
18
+ generatedAt: new Date().toISOString(),
19
+ };
20
+
21
+ for (let index = 0; index < argv.length; index += 1) {
22
+ const token = argv[index];
23
+ const next = argv[index + 1];
24
+ switch (token) {
25
+ case '--consumer-root':
26
+ if (!next) {
27
+ throw new Error('missing value for --consumer-root');
28
+ }
29
+ options.consumerRoot = next;
30
+ index += 1;
31
+ break;
32
+ case '--out':
33
+ if (!next) {
34
+ throw new Error('missing value for --out');
35
+ }
36
+ options.outFile = next;
37
+ index += 1;
38
+ break;
39
+ case '--package-version':
40
+ if (!next) {
41
+ throw new Error('missing value for --package-version');
42
+ }
43
+ options.packageVersion = next;
44
+ index += 1;
45
+ break;
46
+ case '--generated-at':
47
+ if (!next) {
48
+ throw new Error('missing value for --generated-at');
49
+ }
50
+ options.generatedAt = next;
51
+ index += 1;
52
+ break;
53
+ default:
54
+ throw new Error(`unknown argument: ${token}`);
55
+ }
56
+ }
57
+
58
+ return options;
59
+ };
60
+
61
+ const main = (): number => {
62
+ const cwd = process.cwd();
63
+ const options = parseArgs(process.argv.slice(2));
64
+ const markdown = buildRuralGoS1EvidencePackMarkdown({
65
+ cwd,
66
+ consumerRoot: options.consumerRoot,
67
+ packageVersion: options.packageVersion,
68
+ generatedAt: options.generatedAt,
69
+ });
70
+ const outputPath = writeRuralGoS1EvidencePack({
71
+ cwd,
72
+ outFile: options.outFile,
73
+ markdown,
74
+ });
75
+ process.stdout.write(`ruralgo s1 evidence pack generated at ${outputPath}\n`);
76
+ return 0;
77
+ };
78
+
79
+ try {
80
+ process.exitCode = main();
81
+ } catch (error) {
82
+ const message = error instanceof Error ? error.message : 'unknown error';
83
+ process.stderr.write(`ruralgo s1 evidence pack failed: ${message}\n`);
84
+ process.exitCode = 1;
85
+ }
@@ -4,11 +4,10 @@ import type {
4
4
  ConsumerMenuMatrixReport,
5
5
  MatrixOptionId,
6
6
  } from './framework-menu-matrix-baseline-lib';
7
- import { MATRIX_MENU_OPTION_IDS } from './framework-menu-matrix-evidence-lib';
8
7
  import type { DoctorDeepCheckLayer, LifecycleDoctorReport } from '../integrations/lifecycle/doctor';
9
8
  import type { LifecycleStatus } from '../integrations/lifecycle/status';
10
9
 
11
- const OPTION_IDS: ReadonlyArray<MatrixOptionId> = [...MATRIX_MENU_OPTION_IDS];
10
+ const OPTION_IDS: ReadonlyArray<MatrixOptionId> = ['1', '2', '3', '4', '9'];
12
11
  const DOCTOR_LAYERS: ReadonlyArray<DoctorDeepCheckLayer> = [
13
12
  'core',
14
13
  'operational',
@@ -52,19 +51,45 @@ export type ConsumerMenuMatrixBaselineSnapshot = {
52
51
  };
53
52
  };
54
53
 
55
- const UNKNOWN_OPTION_REPORT = {
56
- stage: 'UNKNOWN',
57
- outcome: 'UNKNOWN',
58
- filesScanned: 0,
59
- totalViolations: 0,
60
- diagnosis: 'unknown' as const,
61
- };
62
-
63
54
  const buildEmptyRound = (): ConsumerMenuMatrixReport => {
64
55
  return {
65
- byOption: Object.fromEntries(
66
- MATRIX_MENU_OPTION_IDS.map((id) => [id, { ...UNKNOWN_OPTION_REPORT }])
67
- ) as ConsumerMenuMatrixReport['byOption'],
56
+ byOption: {
57
+ '1': {
58
+ stage: 'UNKNOWN',
59
+ outcome: 'UNKNOWN',
60
+ filesScanned: 0,
61
+ totalViolations: 0,
62
+ diagnosis: 'unknown',
63
+ },
64
+ '2': {
65
+ stage: 'UNKNOWN',
66
+ outcome: 'UNKNOWN',
67
+ filesScanned: 0,
68
+ totalViolations: 0,
69
+ diagnosis: 'unknown',
70
+ },
71
+ '3': {
72
+ stage: 'UNKNOWN',
73
+ outcome: 'UNKNOWN',
74
+ filesScanned: 0,
75
+ totalViolations: 0,
76
+ diagnosis: 'unknown',
77
+ },
78
+ '4': {
79
+ stage: 'UNKNOWN',
80
+ outcome: 'UNKNOWN',
81
+ filesScanned: 0,
82
+ totalViolations: 0,
83
+ diagnosis: 'unknown',
84
+ },
85
+ '9': {
86
+ stage: 'UNKNOWN',
87
+ outcome: 'UNKNOWN',
88
+ filesScanned: 0,
89
+ totalViolations: 0,
90
+ diagnosis: 'unknown',
91
+ },
92
+ },
68
93
  };
69
94
  };
70
95
 
@@ -9,10 +9,6 @@ export type ConsumerLegacyMenuContext = {
9
9
  runStrictRepoAndStaged: () => Promise<void>;
10
10
  runStrictStagedOnly: () => Promise<void>;
11
11
  runStandardCriticalHigh: () => Promise<void>;
12
- runEngineStagedNoPreflight: () => Promise<void>;
13
- runEngineUnstagedNoPreflight: () => Promise<void>;
14
- runEngineStagedAndUnstagedNoPreflight: () => Promise<void>;
15
- runEngineFullRepoNoPreflight: () => Promise<void>;
16
12
  runPatternChecks: () => Promise<void>;
17
13
  runEslintAudit: () => Promise<void>;
18
14
  runAstIntelligence: () => Promise<void>;
@@ -26,44 +22,24 @@ export const createConsumerLegacyMenuActions = (
26
22
  return [
27
23
  {
28
24
  id: '1',
29
- label: 'Consumer preflight + gate: ALL tracked files (PRE_COMMIT · writes evidence)',
25
+ label: 'Read-only full audit (repo analysis · PRE_COMMIT)',
30
26
  execute: params.runFullAudit,
31
27
  },
32
28
  {
33
29
  id: '2',
34
- label: 'Consumer preflight + gate: REPO+index contract (PRE_PUSH · disk skip risk if evidence tracked)',
30
+ label: 'Read-only strict REPO+STAGING (CI/CD · PRE_PUSH)',
35
31
  execute: params.runStrictRepoAndStaged,
36
32
  },
37
33
  {
38
34
  id: '3',
39
- label: 'Consumer preflight + gate: STAGED only (PRE_COMMIT)',
35
+ label: 'Read-only strict STAGING only (dev · PRE_COMMIT)',
40
36
  execute: params.runStrictStagedOnly,
41
37
  },
42
38
  {
43
39
  id: '4',
44
- label: 'Consumer preflight + gate: working tree (PRE_PUSH policy · disk skip risk if evidence tracked)',
40
+ label: 'Read-only audit of STAGED+UNSTAGED working tree (PRE_PUSH policy)',
45
41
  execute: params.runStandardCriticalHigh,
46
42
  },
47
- {
48
- id: '11',
49
- label: 'Engine audit · STAGED only (no preflight · PRE_COMMIT)',
50
- execute: params.runEngineStagedNoPreflight,
51
- },
52
- {
53
- id: '12',
54
- label: 'Engine audit · UNSTAGED only (no preflight · PRE_COMMIT)',
55
- execute: params.runEngineUnstagedNoPreflight,
56
- },
57
- {
58
- id: '13',
59
- label: 'Engine audit · STAGED + UNSTAGED (no preflight · PRE_COMMIT)',
60
- execute: params.runEngineStagedAndUnstagedNoPreflight,
61
- },
62
- {
63
- id: '14',
64
- label: 'Engine audit · FULL tracked repo (no preflight · PRE_COMMIT)',
65
- execute: params.runEngineFullRepoNoPreflight,
66
- },
67
43
  {
68
44
  id: '5',
69
45
  label: 'Legacy read-only pattern checks snapshot',
@@ -7,8 +7,7 @@ import type {
7
7
  } from './framework-menu-consumer-preflight-types';
8
8
 
9
9
  export const ACTIONABLE_HINTS_BY_CODE: Readonly<Record<string, string>> = {
10
- EVIDENCE_MISSING:
11
- 'ejecuta una auditoría (1/2/3/4 o motor 11–14) para regenerar .ai_evidence.json.',
10
+ EVIDENCE_MISSING: 'ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.',
12
11
  EVIDENCE_INVALID: 'regenera .ai_evidence.json desde una opción de auditoría.',
13
12
  EVIDENCE_STALE: 'refresca evidencia antes de continuar con commit/push.',
14
13
  EVIDENCE_TIMESTAMP_INVALID: 'regenera evidencia para obtener un timestamp válido.',
@@ -55,9 +54,7 @@ export const buildConsumerPreflightHints = (
55
54
  const actionableHintsByCode = resolveActionableHintsByCode(dependencies);
56
55
 
57
56
  if (hasViolationCode(violations, 'EVIDENCE_MISSING')) {
58
- hints.push(
59
- 'Evidence missing: ejecuta una auditoría (1/2/3/4 o motor 11–14) para regenerar .ai_evidence.json.'
60
- );
57
+ hints.push('Evidence missing: ejecuta una auditoría (1/2/3/4) para regenerar .ai_evidence.json.');
61
58
  handledCodes.add('EVIDENCE_MISSING');
62
59
  }
63
60
  if (hasViolationCode(violations, 'EVIDENCE_INVALID')) {
@@ -1,5 +1,7 @@
1
1
  import { renderLegacyPanel, resolveLegacyPanelOuterWidth } from './framework-menu-legacy-audit-lib';
2
2
  import { buildConsumerPreflightBlockingCauseLines } from './framework-menu-consumer-preflight-hints';
3
+ import { buildGovernanceNextActionSummaryLines } from '../integrations/lifecycle/governanceNextAction';
4
+ import { buildGovernanceObservationSummaryLines } from '../integrations/lifecycle/governanceObservationSnapshot';
3
5
  import type {
4
6
  ConsumerPreflightRenderOptions,
5
7
  ConsumerPreflightResult,
@@ -19,6 +21,10 @@ const buildConsumerPreflightPanelLines = (
19
21
  `Evidence source: source=${evidence.source.source} path=${evidence.source.path} digest=${evidence.source.digest ?? 'null'} generated_at=${evidence.source.generated_at ?? 'null'}`,
20
22
  `Gate: ${preflight.status} (${preflight.result.violations.length} violations)`,
21
23
  ];
24
+ lines.push('', 'Governance truth:');
25
+ lines.push(...buildGovernanceObservationSummaryLines(preflight.governanceObservation));
26
+ lines.push('', 'Governance next action:');
27
+ lines.push(...buildGovernanceNextActionSummaryLines(preflight.governanceNextAction));
22
28
  lines.push(...buildConsumerPreflightBlockingCauseLines(preflight));
23
29
 
24
30
  if (preflight.hints.length > 0) {
@@ -2,6 +2,11 @@ import {
2
2
  evaluateAiGate,
3
3
  type AiGateCheckResult,
4
4
  } from '../integrations/gate/evaluateAiGate';
5
+ import { readLifecycleExperimentalFeaturesSnapshot } from '../integrations/lifecycle/experimentalFeaturesSnapshot';
6
+ import { LifecycleGitService } from '../integrations/lifecycle/gitService';
7
+ import { readGovernanceObservationSnapshot } from '../integrations/lifecycle/governanceObservationSnapshot';
8
+ import { readGovernanceNextAction } from '../integrations/lifecycle/governanceNextAction';
9
+ import { readLifecyclePolicyValidationSnapshot } from '../integrations/lifecycle/policyValidationSnapshot';
5
10
  import {
6
11
  emitSystemNotification,
7
12
  type PumukiCriticalNotificationEvent,
@@ -28,6 +33,7 @@ const defaultDependencies: ConsumerPreflightDependencies = {
28
33
  event: params.event,
29
34
  repoRoot: params.repoRoot,
30
35
  }),
36
+ readGovernanceNextAction,
31
37
  };
32
38
 
33
39
  const buildNotificationEvents = (
@@ -86,6 +92,17 @@ export const runConsumerPreflight = (
86
92
  repoRoot,
87
93
  stage: params.stage,
88
94
  });
95
+ const governanceObservation = readGovernanceObservationSnapshot({
96
+ repoRoot,
97
+ experimentalFeatures: readLifecycleExperimentalFeaturesSnapshot(),
98
+ policyValidation: readLifecyclePolicyValidationSnapshot(repoRoot),
99
+ git: new LifecycleGitService(),
100
+ });
101
+ const governanceNextAction = activeDependencies.readGovernanceNextAction({
102
+ repoRoot,
103
+ stage: params.stage,
104
+ governanceObservation,
105
+ });
89
106
  const hints = buildConsumerPreflightHints(result, params.stage);
90
107
  const notificationEvents = buildNotificationEvents(result);
91
108
  const notificationResults = notificationEvents.map((event) =>
@@ -99,6 +116,8 @@ export const runConsumerPreflight = (
99
116
  stage: params.stage,
100
117
  status: result.status,
101
118
  result,
119
+ governanceObservation,
120
+ governanceNextAction,
102
121
  hints,
103
122
  notificationResults,
104
123
  };
@@ -2,6 +2,11 @@ import type {
2
2
  AiGateCheckResult,
3
3
  AiGateViolation,
4
4
  } from '../integrations/gate/evaluateAiGate';
5
+ import type {
6
+ GovernanceNextActionReader,
7
+ GovernanceNextActionSummary,
8
+ } from '../integrations/lifecycle/governanceNextAction';
9
+ import type { GovernanceObservationSnapshot } from '../integrations/lifecycle/governanceObservationSnapshot';
5
10
  import type {
6
11
  PumukiCriticalNotificationEvent,
7
12
  SystemNotificationEmitResult,
@@ -13,6 +18,8 @@ export type ConsumerPreflightResult = {
13
18
  stage: ConsumerPreflightStage;
14
19
  status: AiGateCheckResult['status'];
15
20
  result: AiGateCheckResult;
21
+ governanceObservation: GovernanceObservationSnapshot;
22
+ governanceNextAction: GovernanceNextActionSummary;
16
23
  hints: ReadonlyArray<string>;
17
24
  notificationResults: ReadonlyArray<SystemNotificationEmitResult>;
18
25
  };
@@ -26,6 +33,7 @@ export type ConsumerPreflightDependencies = {
26
33
  event: PumukiCriticalNotificationEvent;
27
34
  repoRoot: string;
28
35
  }) => SystemNotificationEmitResult;
36
+ readGovernanceNextAction: GovernanceNextActionReader;
29
37
  };
30
38
 
31
39
  export type ConsumerPreflightRenderOptions = {
@@ -5,7 +5,6 @@ import {
5
5
  exportConsumerRuntimeMarkdown,
6
6
  notifyConsumerRuntimeAuditSummary,
7
7
  printConsumerRuntimeEmptyScopeHint,
8
- printPrePushTrackedEvidenceDiskHint,
9
8
  renderConsumerRuntimeAstBreakdown,
10
9
  renderConsumerRuntimeEslintAudit,
11
10
  renderConsumerRuntimeFileDiagnostics,
@@ -21,9 +20,7 @@ type ConsumerRuntimeActionDependencies = {
21
20
  runRepoGate: () => Promise<ConsumerRuntimeGateResult | void>;
22
21
  runRepoAndStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
23
22
  runStagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
24
- runUnstagedGate: () => Promise<ConsumerRuntimeGateResult | void>;
25
23
  runWorkingTreeGate: () => Promise<ConsumerRuntimeGateResult | void>;
26
- runWorkingTreePreCommitGate: () => Promise<ConsumerRuntimeGateResult | void>;
27
24
  runPreflight?: (
28
25
  stage: 'PRE_COMMIT' | 'PRE_PUSH'
29
26
  ) => Promise<string | void> | string | void;
@@ -91,25 +88,18 @@ export const createConsumerRuntimeActions = (
91
88
  } else {
92
89
  dependencies.clearSummaryOverride();
93
90
  }
94
- const summary = renderConsumerRuntimeSummary({
95
- repoRoot: dependencies.repoRoot,
96
- write: dependencies.write,
97
- useColor: dependencies.useColor,
98
- summaryOverride: dependencies.getSummaryOverride(),
99
- });
100
91
  notifyConsumerRuntimeAuditSummary(
101
92
  {
102
93
  emitNotification: dependencies.emitNotification,
103
94
  repoRoot: dependencies.repoRoot,
104
95
  },
105
- summary
96
+ renderConsumerRuntimeSummary({
97
+ repoRoot: dependencies.repoRoot,
98
+ write: dependencies.write,
99
+ useColor: dependencies.useColor,
100
+ summaryOverride: dependencies.getSummaryOverride(),
101
+ })
106
102
  );
107
- if (
108
- !gateResult?.blocked
109
- && (summary.outcome === 'PASS' || summary.outcome === 'WARN')
110
- ) {
111
- printPrePushTrackedEvidenceDiskHint({ write: dependencies.write });
112
- }
113
103
  },
114
104
  runStrictStagedOnly: async () => {
115
105
  await runConsumerRuntimePreflight(dependencies, 'PRE_COMMIT');
@@ -145,78 +135,8 @@ export const createConsumerRuntimeActions = (
145
135
  },
146
136
  summary
147
137
  );
148
- if (summary.outcome === 'PASS' || summary.outcome === 'WARN') {
149
- printPrePushTrackedEvidenceDiskHint({ write: dependencies.write });
150
- }
151
138
  printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'workingTree');
152
139
  },
153
- runEngineStagedNoPreflight: async () => {
154
- await dependencies.runStagedGate();
155
- dependencies.clearSummaryOverride();
156
- const summary = renderConsumerRuntimeSummary({
157
- repoRoot: dependencies.repoRoot,
158
- write: dependencies.write,
159
- useColor: dependencies.useColor,
160
- });
161
- notifyConsumerRuntimeAuditSummary(
162
- {
163
- emitNotification: dependencies.emitNotification,
164
- repoRoot: dependencies.repoRoot,
165
- },
166
- summary
167
- );
168
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'staged');
169
- },
170
- runEngineUnstagedNoPreflight: async () => {
171
- await dependencies.runUnstagedGate();
172
- dependencies.clearSummaryOverride();
173
- const summary = renderConsumerRuntimeSummary({
174
- repoRoot: dependencies.repoRoot,
175
- write: dependencies.write,
176
- useColor: dependencies.useColor,
177
- });
178
- notifyConsumerRuntimeAuditSummary(
179
- {
180
- emitNotification: dependencies.emitNotification,
181
- repoRoot: dependencies.repoRoot,
182
- },
183
- summary
184
- );
185
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'unstaged');
186
- },
187
- runEngineStagedAndUnstagedNoPreflight: async () => {
188
- await dependencies.runWorkingTreePreCommitGate();
189
- dependencies.clearSummaryOverride();
190
- const summary = renderConsumerRuntimeSummary({
191
- repoRoot: dependencies.repoRoot,
192
- write: dependencies.write,
193
- useColor: dependencies.useColor,
194
- });
195
- notifyConsumerRuntimeAuditSummary(
196
- {
197
- emitNotification: dependencies.emitNotification,
198
- repoRoot: dependencies.repoRoot,
199
- },
200
- summary
201
- );
202
- printConsumerRuntimeEmptyScopeHint({ write: dependencies.write }, summary, 'workingTree');
203
- },
204
- runEngineFullRepoNoPreflight: async () => {
205
- await dependencies.runRepoGate();
206
- dependencies.clearSummaryOverride();
207
- const summary = renderConsumerRuntimeSummary({
208
- repoRoot: dependencies.repoRoot,
209
- write: dependencies.write,
210
- useColor: dependencies.useColor,
211
- });
212
- notifyConsumerRuntimeAuditSummary(
213
- {
214
- emitNotification: dependencies.emitNotification,
215
- repoRoot: dependencies.repoRoot,
216
- },
217
- summary
218
- );
219
- },
220
140
  runPatternChecks: async () => {
221
141
  dependencies.write(`\n${renderConsumerRuntimePatternChecks(dependencies.repoRoot)}\n`);
222
142
  },
@@ -14,7 +14,6 @@ import {
14
14
  readEvidenceSummaryForMenu,
15
15
  type FrameworkMenuEvidenceSummary,
16
16
  } from './framework-menu-evidence-summary-lib';
17
- import { renderVintageEvidenceReport } from './framework-menu-consumer-runtime-evidence-classic';
18
17
  import type {
19
18
  ConsumerRuntimeBlockedGate,
20
19
  ConsumerRuntimeNotificationDependencies,
@@ -57,36 +56,9 @@ export const renderConsumerRuntimeSummary = (
57
56
  width: resolveLegacyPanelOuterWidth(),
58
57
  color: dependencies.useColor(),
59
58
  })}\n`);
60
-
61
- const vintageSource =
62
- summary.status === 'ok' && !dependencies.summaryOverride
63
- ? readEvidenceSummaryForMenu(dependencies.repoRoot, {
64
- topFindingsLimit: 45,
65
- topFileLocationsLimit: 15,
66
- topFilesLimit: 10,
67
- })
68
- : summary;
69
- renderVintageEvidenceReport({
70
- write: dependencies.write,
71
- summary: vintageSource,
72
- useColor: dependencies.useColor,
73
- });
74
59
  return summary;
75
60
  };
76
61
 
77
- export const printPrePushTrackedEvidenceDiskHint = (params: {
78
- write: ConsumerRuntimeSummaryDependencies['write'];
79
- }): void => {
80
- params.write(
81
- '\n' +
82
- [
83
- 'ℹ PRE_PUSH + `.ai_evidence.json` tracked: on PASS/WARN the gate may skip rewriting the file on disk',
84
- ' (avoids dirty tracked evidence). Local dev: PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1 forces disk write.',
85
- ].join('\n') +
86
- '\n'
87
- );
88
- };
89
-
90
62
  export const buildConsumerRuntimeBlockedSummary = (
91
63
  blocked: ConsumerRuntimeBlockedGate
92
64
  ): FrameworkMenuEvidenceSummary => ({
@@ -144,18 +116,12 @@ export const printConsumerRuntimeEmptyScopeHint = (
144
116
  }
145
117
  if (scope === 'staged') {
146
118
  dependencies.write(
147
- '\nℹ Scope vacío (staged): no hay archivos soportados en staged para auditar. Resultado PASS por alcance vacío; usa 1, 2 o 14 (repo completo) según necesidad.\n'
148
- );
149
- return;
150
- }
151
- if (scope === 'unstaged') {
152
- dependencies.write(
153
- '\nℹ Scope vacío (unstaged): no hay cambios sin stage ni untracked auditable. Resultado PASS por alcance vacío; usa 1, 14 u opciones 11–13 según el alcance que necesites.\n'
119
+ '\nℹ Scope vacío (staged): no hay archivos soportados en staged para auditar. Resultado PASS por alcance vacío; usa 1 o 2 para validar repo completo.\n'
154
120
  );
155
121
  return;
156
122
  }
157
123
  dependencies.write(
158
- '\nℹ Scope vacío (working tree): no hay archivos soportados en staged/unstaged para auditar. Resultado PASS por alcance vacío; usa 1, 2, 13 o 14 según el alcance que necesites.\n'
124
+ '\nℹ Scope vacío (working tree): no hay archivos soportados en staged/unstaged para auditar. Resultado PASS por alcance vacío; usa 1 o 2 para validar repo completo.\n'
159
125
  );
160
126
  };
161
127