pumuki 6.3.36 → 6.3.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.36
1
+ v6.3.37
@@ -229,7 +229,7 @@ Expected JSONL keys for enterprise audit ingestion:
229
229
  - `schema=telemetry_event_v1` with `schema_version=1.0`
230
230
  - `stage`, `gate_outcome`, `severity_counts`
231
231
  - `policy.bundle`, `policy.hash`, `policy.version`, `policy.signature`, `policy.policy_source`
232
- - `policy.validation_status`, `policy.validation_code` (when policy-as-code validation is available)
232
+ - `policy.validation_status`, `policy.validation_code` (when policy-as-code validation is available; status can be `valid|invalid|expired|unknown-source|unsigned`)
233
233
 
234
234
  ## Heuristic pilot flag
235
235
 
@@ -5,6 +5,24 @@ Detailed commit history remains available through Git history (`git log` / `git
5
5
 
6
6
  ## 2026-03 (enterprise hardening updates)
7
7
 
8
+ ### 2026-03-04 (v6.3.37)
9
+
10
+ - Policy-as-code enterprise hardening shipped:
11
+ - strict mode now blocks unsigned runtime policy metadata with deterministic code `POLICY_AS_CODE_UNSIGNED`.
12
+ - lifecycle outputs now expose policy validation metadata in `status --json`, `doctor --json`, and `sdd validate --json`.
13
+ - telemetry/evidence contract now supports policy validation status `unsigned`.
14
+ - Traceability:
15
+ - implementation issue: `#606`
16
+ - implementation PR: `#608`
17
+ - tracking sync PR: `#609`
18
+ - Consumer quick verification:
19
+ - `npx --yes --package pumuki@latest pumuki status --json`
20
+ - `npx --yes --package pumuki@latest pumuki doctor --json`
21
+ - `PUMUKI_POLICY_STRICT=1 npx --yes --package pumuki@latest pumuki-pre-commit`
22
+ - expected signal:
23
+ - JSON includes `policyValidation.stages.*.validationCode`.
24
+ - strict mode blocks unsigned contracts with `POLICY_AS_CODE_UNSIGNED`.
25
+
8
26
  ### 2026-03-04 (v6.3.36)
9
27
 
10
28
  - SDD orchestration hardening shipped:
@@ -7,8 +7,8 @@
7
7
  ## Estado actual
8
8
  - Plan activo: `docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md`
9
9
  - Estado del plan: EN CURSO
10
- - Última task cerrada (`✅`): `P12.F2.T70` (comando orquestador `pumuki sdd auto-sync`, issue `#600`, PR `#602`, commit `2be34c5`).
11
- - Task activa (`🚧`): `P12.F2.T71` (publicar release `6.3.36` con `auto-sync`, issue `#603`).
10
+ - Última task cerrada (`✅`): `P12.F2.T72` (hardening `policy-as-code` completado: issue `#606` cerrada con PR `#608`).
11
+ - Task activa (`🚧`): `P12.F2.T73` (preparar/publicar release incremental con el hardening de `#606`).
12
12
 
13
13
  ## Historial resumido
14
14
  - No se mantienen MDs históricos de seguimiento en este repositorio.
@@ -1968,11 +1968,36 @@ Criterio de salida F5:
1968
1968
  - `npx --yes tsx@4.21.0 --test integrations/sdd/__tests__/syncDocs.test.ts integrations/sdd/__tests__/index.test.ts integrations/lifecycle/__tests__/cli.test.ts` => `44 passed, 0 failed`.
1969
1969
  - `npm run -s typecheck` => `exit 0`.
1970
1970
 
1971
- - 🚧 `P12.F2.T71` Publicar release `6.3.36` con `pumuki sdd auto-sync` (`#603`).
1972
- - salida esperada:
1971
+ - `P12.F2.T71` Publicar release `6.3.36` con `pumuki sdd auto-sync` (`#603`).
1972
+ - cierre ejecutado:
1973
1973
  - versionado a `6.3.36` en `package.json`, `package-lock.json` y `VERSION`.
1974
- - release notes actualizadas con entrada `v6.3.36`.
1975
- - publicación npm validada (`latest=6.3.36`) + smoke de `--help` mostrando `auto-sync`.
1974
+ - release notes actualizadas con entrada `2026-03-04 (v6.3.36)` en `docs/RELEASE_NOTES.md`.
1975
+ - publicación npm ejecutada con éxito (`npm publish --access public`).
1976
+ - propagación validada:
1977
+ - `npm view pumuki dist-tags --json` => `"latest": "6.3.36"`.
1978
+ - smoke `@latest` con `--help` mostrando `pumuki sdd auto-sync ...`.
1979
+ - evidencia:
1980
+ - `npx --yes tsx@4.21.0 --test integrations/sdd/__tests__/syncDocs.test.ts integrations/sdd/__tests__/index.test.ts integrations/lifecycle/__tests__/cli.test.ts` => `44 passed, 0 failed`.
1981
+ - `npm run -s typecheck` => `exit 0`.
1982
+ - `npm publish --access public` => `+ pumuki@6.3.36`.
1983
+ - `npm view pumuki@6.3.36 version` => `6.3.36`.
1984
+
1985
+ - ✅ `P12.F2.T72` Hardening enterprise policy-as-code firmada/versionada (`#606`).
1986
+ - cierre ejecutado:
1987
+ - modo estricto bloquea política no firmada con código determinista `POLICY_AS_CODE_UNSIGNED`.
1988
+ - `status`, `doctor` y `sdd validate --json` exponen metadatos de validación de policy (`source/bundle/hash/version/signature/status/code/strict`).
1989
+ - telemetría/evidence alineadas con estado adicional `unsigned`.
1990
+ - cobertura de regresión añadida para strict unsigned + metadatos lifecycle.
1991
+ - issue cerrada: `#606`.
1992
+ - PR mergeada: `#608` (`commit 881eac8`).
1993
+ - evidencia:
1994
+ - `npx --yes tsx@4.21.0 --test integrations/gate/__tests__/stagePolicies.test.ts integrations/git/__tests__/runPlatformGate.test.ts integrations/lifecycle/__tests__/status.test.ts integrations/lifecycle/__tests__/doctor.test.ts integrations/lifecycle/__tests__/cli.test.ts` => `81 passed, 0 failed`.
1995
+ - `npm run -s typecheck` => `exit 0`.
1996
+
1997
+ - 🚧 `P12.F2.T73` Preparar y publicar release con el hardening de `#606`.
1998
+ - salida esperada:
1999
+ - versionar release incremental y notas de publicación.
2000
+ - publicar en npm y verificar propagación `dist-tags`.
1976
2001
 
1977
2002
  Criterio de salida F6:
1978
2003
  - veredicto final trazable y cierre administrativo completo.
@@ -89,7 +89,7 @@ export type RulesetState = {
89
89
  version?: string;
90
90
  signature?: string;
91
91
  source?: string;
92
- validation_status?: 'valid' | 'invalid' | 'expired' | 'unknown-source';
92
+ validation_status?: 'valid' | 'invalid' | 'expired' | 'unknown-source' | 'unsigned';
93
93
  validation_code?: string;
94
94
  degraded_mode_enabled?: boolean;
95
95
  degraded_mode_action?: 'allow' | 'block';
@@ -49,9 +49,10 @@ export type ResolvedStagePolicy = {
49
49
  signature?: string;
50
50
  policySource?: string;
51
51
  validation?: {
52
- status: 'valid' | 'invalid' | 'expired' | 'unknown-source';
52
+ status: 'valid' | 'invalid' | 'expired' | 'unknown-source' | 'unsigned';
53
53
  code:
54
54
  | 'POLICY_AS_CODE_VALID'
55
+ | 'POLICY_AS_CODE_UNSIGNED'
55
56
  | 'POLICY_AS_CODE_CONTRACT_INVALID'
56
57
  | 'POLICY_AS_CODE_CONTRACT_EXPIRED'
57
58
  | 'POLICY_AS_CODE_SIGNATURE_MISMATCH'
@@ -307,6 +308,21 @@ const resolvePolicyAsCodeTraceMetadata = (params: {
307
308
  const contractPath = join(params.repoRoot, POLICY_AS_CODE_CONTRACT_PATH);
308
309
 
309
310
  if (!existsSync(contractPath)) {
311
+ if (strict) {
312
+ return {
313
+ version: computedVersion,
314
+ signature: computedSignature,
315
+ policySource: 'computed-local',
316
+ validation: {
317
+ status: 'unsigned',
318
+ code: 'POLICY_AS_CODE_UNSIGNED',
319
+ message:
320
+ 'Policy-as-code contract is missing; runtime policy metadata is unsigned.',
321
+ strict,
322
+ },
323
+ };
324
+ }
325
+
310
326
  return {
311
327
  version: computedVersion,
312
328
  signature: computedSignature,
@@ -10,6 +10,10 @@ import {
10
10
  import { runLifecycleInstall } from './install';
11
11
  import { runLifecycleRemove } from './remove';
12
12
  import { readLifecycleStatus } from './status';
13
+ import {
14
+ readLifecyclePolicyValidationSnapshot,
15
+ type LifecyclePolicyValidationSnapshot,
16
+ } from './policyValidationSnapshot';
13
17
  import { runLifecycleUninstall } from './uninstall';
14
18
  import { runLifecycleUpdate } from './update';
15
19
  import { runOpenSpecBootstrap } from './openSpecBootstrap';
@@ -977,6 +981,11 @@ const printDoctorReport = (
977
981
  writeInfo(
978
982
  `[pumuki] hook pre-push: ${report.hookStatus['pre-push'].managedBlockPresent ? 'managed' : 'missing'}`
979
983
  );
984
+ writeInfo(
985
+ `[pumuki] policy-as-code: PRE_COMMIT=${report.policyValidation.stages.PRE_COMMIT.validationCode ?? 'n/a'} strict=${report.policyValidation.stages.PRE_COMMIT.strict ? 'yes' : 'no'} ` +
986
+ `PRE_PUSH=${report.policyValidation.stages.PRE_PUSH.validationCode ?? 'n/a'} strict=${report.policyValidation.stages.PRE_PUSH.strict ? 'yes' : 'no'} ` +
987
+ `CI=${report.policyValidation.stages.CI.validationCode ?? 'n/a'} strict=${report.policyValidation.stages.CI.strict ? 'yes' : 'no'}`
988
+ );
980
989
 
981
990
  for (const issue of report.issues) {
982
991
  writeInfo(`[pumuki] ${issue.severity.toUpperCase()}: ${issue.message}`);
@@ -1016,6 +1025,7 @@ const PRE_WRITE_INSTALL_REMEDIATION_COMMAND =
1016
1025
  type PreWriteValidationEnvelope = {
1017
1026
  sdd: ReturnType<typeof evaluateSddPolicy>;
1018
1027
  ai_gate: ReturnType<typeof evaluateAiGate>;
1028
+ policy_validation: LifecyclePolicyValidationSnapshot;
1019
1029
  automation: PreWriteAutomationTrace;
1020
1030
  bootstrap: {
1021
1031
  enabled: boolean;
@@ -1229,12 +1239,14 @@ const resolveAiGateViolationLocation = (code: string) => {
1229
1239
  const buildPreWriteValidationEnvelope = (
1230
1240
  result: ReturnType<typeof evaluateSddPolicy>,
1231
1241
  aiGate: ReturnType<typeof evaluateAiGate>,
1242
+ policyValidation: LifecyclePolicyValidationSnapshot,
1232
1243
  automation: PreWriteAutomationTrace,
1233
1244
  bootstrap: PreWriteOpenSpecBootstrapTrace,
1234
1245
  nextAction: PreWriteValidationEnvelope['next_action']
1235
1246
  ): PreWriteValidationEnvelope => ({
1236
1247
  sdd: result,
1237
1248
  ai_gate: aiGate,
1249
+ policy_validation: policyValidation,
1238
1250
  automation: {
1239
1251
  attempted: automation.attempted,
1240
1252
  actions: [...automation.actions],
@@ -1398,6 +1410,11 @@ export const runLifecycleCli = async (
1398
1410
  writeInfo(
1399
1411
  `[pumuki] tracked node_modules paths: ${status.trackedNodeModulesCount}`
1400
1412
  );
1413
+ writeInfo(
1414
+ `[pumuki] policy-as-code: PRE_COMMIT=${status.policyValidation.stages.PRE_COMMIT.validationCode ?? 'n/a'} strict=${status.policyValidation.stages.PRE_COMMIT.strict ? 'yes' : 'no'} ` +
1415
+ `PRE_PUSH=${status.policyValidation.stages.PRE_PUSH.validationCode ?? 'n/a'} strict=${status.policyValidation.stages.PRE_PUSH.strict ? 'yes' : 'no'} ` +
1416
+ `CI=${status.policyValidation.stages.CI.validationCode ?? 'n/a'} strict=${status.policyValidation.stages.CI.strict ? 'yes' : 'no'}`
1417
+ );
1401
1418
  if (remoteCiDiagnostics) {
1402
1419
  printRemoteCiDiagnostics(remoteCiDiagnostics);
1403
1420
  }
@@ -1656,6 +1673,7 @@ export const runLifecycleCli = async (
1656
1673
  let result = evaluateSddPolicy({
1657
1674
  stage: parsed.sddStage ?? 'PRE_COMMIT',
1658
1675
  });
1676
+ const policyValidation = readLifecyclePolicyValidationSnapshot(process.cwd());
1659
1677
  const preWriteAutoBootstrapEnabled = process.env.PUMUKI_PREWRITE_AUTO_BOOTSTRAP !== '0';
1660
1678
  const preWriteBootstrapTrace: PreWriteOpenSpecBootstrapTrace = {
1661
1679
  enabled: preWriteAutoBootstrapEnabled,
@@ -1727,11 +1745,15 @@ export const runLifecycleCli = async (
1727
1745
  ? buildPreWriteValidationEnvelope(
1728
1746
  result,
1729
1747
  aiGate,
1748
+ policyValidation,
1730
1749
  automationTrace,
1731
1750
  preWriteBootstrapTrace,
1732
1751
  nextAction
1733
1752
  )
1734
- : result,
1753
+ : {
1754
+ ...result,
1755
+ policy_validation: policyValidation,
1756
+ },
1735
1757
  null,
1736
1758
  2
1737
1759
  )
@@ -1740,6 +1762,11 @@ export const runLifecycleCli = async (
1740
1762
  writeInfo(
1741
1763
  `[pumuki][sdd] stage=${result.stage} allowed=${result.decision.allowed ? 'yes' : 'no'} code=${result.decision.code}`
1742
1764
  );
1765
+ writeInfo(
1766
+ `[pumuki][sdd] policy-as-code: PRE_COMMIT=${policyValidation.stages.PRE_COMMIT.validationCode ?? 'n/a'} strict=${policyValidation.stages.PRE_COMMIT.strict ? 'yes' : 'no'} ` +
1767
+ `PRE_PUSH=${policyValidation.stages.PRE_PUSH.validationCode ?? 'n/a'} strict=${policyValidation.stages.PRE_PUSH.strict ? 'yes' : 'no'} ` +
1768
+ `CI=${policyValidation.stages.CI.validationCode ?? 'n/a'} strict=${policyValidation.stages.CI.strict ? 'yes' : 'no'}`
1769
+ );
1743
1770
  writeInfo(
1744
1771
  withOptionalLocation(
1745
1772
  `[pumuki][sdd] ${result.decision.message}`,
@@ -5,6 +5,10 @@ import { resolvePolicyForStage } from '../gate/stagePolicies';
5
5
  import { getPumukiHooksStatus } from './hookManager';
6
6
  import { LifecycleGitService, type ILifecycleGitService } from './gitService';
7
7
  import { getCurrentPumukiVersion } from './packageInfo';
8
+ import {
9
+ readLifecyclePolicyValidationSnapshot,
10
+ type LifecyclePolicyValidationSnapshot,
11
+ } from './policyValidationSnapshot';
8
12
  import { readLifecycleState, type LifecycleState } from './state';
9
13
  import {
10
14
  detectOpenSpecInstallation,
@@ -71,6 +75,7 @@ export type LifecycleDoctorReport = {
71
75
  lifecycleState: LifecycleState;
72
76
  trackedNodeModulesPaths: ReadonlyArray<string>;
73
77
  hookStatus: ReturnType<typeof getPumukiHooksStatus>;
78
+ policyValidation: LifecyclePolicyValidationSnapshot;
74
79
  issues: ReadonlyArray<DoctorIssue>;
75
80
  deep?: DoctorDeepReport;
76
81
  };
@@ -653,6 +658,7 @@ export const runLifecycleDoctor = (params?: {
653
658
  lifecycleState,
654
659
  trackedNodeModulesPaths,
655
660
  hookStatus,
661
+ policyValidation: readLifecyclePolicyValidationSnapshot(repoRoot),
656
662
  issues,
657
663
  deep,
658
664
  };
@@ -0,0 +1,51 @@
1
+ import type { SkillsStage } from '../config/skillsLock';
2
+ import {
3
+ resolvePolicyForStage,
4
+ type ResolvedStagePolicy,
5
+ } from '../gate/stagePolicies';
6
+
7
+ export type LifecyclePolicyValidationStageSnapshot = {
8
+ source: ResolvedStagePolicy['trace']['source'];
9
+ bundle: string;
10
+ hash: string;
11
+ version: string | null;
12
+ signature: string | null;
13
+ policySource: string | null;
14
+ validationStatus: NonNullable<ResolvedStagePolicy['trace']['validation']>['status'] | null;
15
+ validationCode: NonNullable<ResolvedStagePolicy['trace']['validation']>['code'] | null;
16
+ strict: boolean;
17
+ };
18
+
19
+ export type LifecyclePolicyValidationSnapshot = {
20
+ stages: Record<SkillsStage, LifecyclePolicyValidationStageSnapshot>;
21
+ };
22
+
23
+ const POLICY_STAGES: ReadonlyArray<SkillsStage> = ['PRE_COMMIT', 'PRE_PUSH', 'CI'];
24
+
25
+ const toStageSnapshot = (
26
+ resolved: ResolvedStagePolicy
27
+ ): LifecyclePolicyValidationStageSnapshot => {
28
+ return {
29
+ source: resolved.trace.source,
30
+ bundle: resolved.trace.bundle,
31
+ hash: resolved.trace.hash,
32
+ version: resolved.trace.version ?? null,
33
+ signature: resolved.trace.signature ?? null,
34
+ policySource: resolved.trace.policySource ?? null,
35
+ validationStatus: resolved.trace.validation?.status ?? null,
36
+ validationCode: resolved.trace.validation?.code ?? null,
37
+ strict: resolved.trace.validation?.strict ?? false,
38
+ };
39
+ };
40
+
41
+ export const readLifecyclePolicyValidationSnapshot = (
42
+ repoRoot: string
43
+ ): LifecyclePolicyValidationSnapshot => {
44
+ const resolvedByStage = Object.fromEntries(
45
+ POLICY_STAGES.map((stage) => [stage, toStageSnapshot(resolvePolicyForStage(stage, repoRoot))])
46
+ ) as Record<SkillsStage, LifecyclePolicyValidationStageSnapshot>;
47
+
48
+ return {
49
+ stages: resolvedByStage,
50
+ };
51
+ };
@@ -1,6 +1,10 @@
1
1
  import { getPumukiHooksStatus } from './hookManager';
2
2
  import { LifecycleGitService, type ILifecycleGitService } from './gitService';
3
3
  import { getCurrentPumukiVersion } from './packageInfo';
4
+ import {
5
+ readLifecyclePolicyValidationSnapshot,
6
+ type LifecyclePolicyValidationSnapshot,
7
+ } from './policyValidationSnapshot';
4
8
  import { readLifecycleState, type LifecycleState } from './state';
5
9
 
6
10
  export type LifecycleStatus = {
@@ -9,6 +13,7 @@ export type LifecycleStatus = {
9
13
  lifecycleState: LifecycleState;
10
14
  hookStatus: ReturnType<typeof getPumukiHooksStatus>;
11
15
  trackedNodeModulesCount: number;
16
+ policyValidation: LifecyclePolicyValidationSnapshot;
12
17
  };
13
18
 
14
19
  export const readLifecycleStatus = (params?: {
@@ -26,5 +31,6 @@ export const readLifecycleStatus = (params?: {
26
31
  lifecycleState: readLifecycleState(git, repoRoot),
27
32
  hookStatus: getPumukiHooksStatus(repoRoot),
28
33
  trackedNodeModulesCount,
34
+ policyValidation: readLifecyclePolicyValidationSnapshot(repoRoot),
29
35
  };
30
36
  };
@@ -25,7 +25,7 @@ type PolicyTrace = ResolvedStagePolicy['trace'] & {
25
25
  signature?: string;
26
26
  policySource?: string;
27
27
  validation?: {
28
- status: 'valid' | 'invalid' | 'expired' | 'unknown-source';
28
+ status: 'valid' | 'invalid' | 'expired' | 'unknown-source' | 'unsigned';
29
29
  code: string;
30
30
  };
31
31
  degraded?: {
@@ -189,7 +189,7 @@ export type GateTelemetryEventV1 = {
189
189
  version?: string;
190
190
  signature?: string;
191
191
  policy_source?: string;
192
- validation_status?: 'valid' | 'invalid' | 'expired' | 'unknown-source';
192
+ validation_status?: 'valid' | 'invalid' | 'expired' | 'unknown-source' | 'unsigned';
193
193
  validation_code?: string;
194
194
  degraded_mode_enabled?: boolean;
195
195
  degraded_mode_action?: 'allow' | 'block';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.36",
3
+ "version": "6.3.37",
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": {