pumuki 6.3.49 → 6.3.51

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 (45) hide show
  1. package/README.md +19 -19
  2. package/core/facts/detectors/text/ios.test.ts +13 -0
  3. package/core/rules/presets/iosEnterpriseRuleSet.test.ts +46 -0
  4. package/core/rules/presets/iosEnterpriseRuleSet.ts +4 -2
  5. package/docs/README.md +42 -63
  6. package/docs/validation/README.md +25 -31
  7. package/integrations/git/gitAtomicity.ts +32 -7
  8. package/integrations/git/runPlatformGate.ts +6 -4
  9. package/integrations/git/runPlatformGateOutput.ts +2 -2
  10. package/integrations/git/stageRunners.ts +156 -8
  11. package/integrations/lifecycle/watch.ts +5 -4
  12. package/integrations/sdd/evidenceScaffold.ts +6 -2
  13. package/integrations/sdd/policy.ts +6 -5
  14. package/package.json +1 -1
  15. package/scripts/adapter-readiness-markdown-next-actions-lib.ts +1 -1
  16. package/scripts/build-phase8-ready-handoff-summary.sh +1 -1
  17. package/scripts/check-refactor-progress-single-active.sh +1 -1
  18. package/scripts/check-tracking-single-active.sh +19 -2
  19. package/scripts/close-phase5-escalation-submission.sh +1 -1
  20. package/scripts/phase5-blockers-markdown-next-actions-blocked-lib.ts +1 -1
  21. package/docs/API_REFERENCE.md +0 -338
  22. package/docs/ARCHITECTURE.md +0 -190
  23. package/docs/BRANCH_PROTECTION_GUIDE.md +0 -50
  24. package/docs/CODE_STANDARDS.md +0 -73
  25. package/docs/CONFIGURATION.md +0 -366
  26. package/docs/CONTRIBUTING.md +0 -92
  27. package/docs/DEPENDENCIES.md +0 -54
  28. package/docs/HOW_IT_WORKS.md +0 -160
  29. package/docs/INSTALLATION.md +0 -270
  30. package/docs/MCP_AGENT_CONTEXT_CONSUMPTION.md +0 -188
  31. package/docs/MCP_EVIDENCE_CONTEXT_SERVER.md +0 -244
  32. package/docs/MCP_SERVERS.md +0 -280
  33. package/docs/OPERATIONS.md +0 -74
  34. package/docs/README_MENU_WALKTHROUGH.md +0 -65
  35. package/docs/RELEASE_NOTES.md +0 -562
  36. package/docs/TESTING.md +0 -114
  37. package/docs/USAGE.md +0 -749
  38. package/docs/evidence-v2.1.md +0 -98
  39. package/docs/registro-maestro-de-seguimiento.md +0 -20
  40. package/docs/seguimiento-activo-pumuki-saas-supermercados.md +0 -2591
  41. package/docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md +0 -2507
  42. package/docs/validation/c022-phase-acceptance-contract.md +0 -172
  43. /package/docs/validation/{adapter-hook-runtime-validation.md → adapter-hook-runtime-runbook.md} +0 -0
  44. /package/docs/validation/{skills-rollout-consumer-repositories.md → consumer-repositories-skills-rollout-validation.md} +0 -0
  45. /package/docs/validation/{detection-audit-baseline.md → full-repo-detection-audit-baseline.md} +0 -0
@@ -22,8 +22,11 @@ import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
22
22
  import { join } from 'node:path';
23
23
  import { readEvidence, readEvidenceResult } from '../evidence/readEvidence';
24
24
  import type { EvidenceReadResult } from '../evidence/readEvidence';
25
+ import type { SnapshotFinding } from '../evidence/schema';
25
26
  import { ensureRuntimeArtifactsIgnored } from '../lifecycle/artifacts';
26
27
  import { runPolicyReconcile } from '../lifecycle/policyReconcile';
28
+ import { isSeverityAtLeast } from '../../core/rules/Severity';
29
+ import type { SddDecision } from '../sdd';
27
30
 
28
31
  const PRE_PUSH_UPSTREAM_REQUIRED_MESSAGE =
29
32
  'pumuki pre-push blocked: branch has no upstream tracking reference. Configure upstream first (for example: git push --set-upstream origin <branch>) and retry.';
@@ -36,11 +39,14 @@ const PRE_PUSH_UPSTREAM_MISALIGNED_AHEAD_THRESHOLD = 5;
36
39
  const PRE_COMMIT_EVIDENCE_MAX_AGE_SECONDS = 900;
37
40
  const PRE_PUSH_EVIDENCE_MAX_AGE_SECONDS = 1800;
38
41
  const DEFAULT_BLOCKED_REMEDIATION = 'Corrige la causa del bloqueo y vuelve a ejecutar el gate.';
42
+ const EVIDENCE_FILE_PATH = '.ai_evidence.json';
39
43
 
40
44
  const BLOCKED_REMEDIATION_BY_CODE: Readonly<Record<string, string>> = {
41
45
  EVIDENCE_MISSING: 'Regenera .ai_evidence.json ejecutando una auditoría.',
42
46
  EVIDENCE_INVALID: 'Corrige/regenera .ai_evidence.json y vuelve a ejecutar el gate.',
43
47
  EVIDENCE_CHAIN_INVALID: 'Regenera evidencia para restaurar la cadena criptográfica.',
48
+ EVIDENCE_STAGE_SYNC_FAILED:
49
+ 'Sincroniza la evidencia trackeada y reintenta: git add -- .ai_evidence.json && git commit --amend --no-edit',
44
50
  EVIDENCE_STALE: 'Refresca evidencia antes de continuar.',
45
51
  EVIDENCE_REPO_ROOT_MISMATCH: 'Regenera evidencia desde este mismo repositorio.',
46
52
  EVIDENCE_BRANCH_MISMATCH: 'Regenera evidencia en la rama actual y reintenta.',
@@ -102,6 +108,9 @@ type StageRunnerDependencies = {
102
108
  isQuietMode: () => boolean;
103
109
  ensureRuntimeArtifactsIgnored: (repoRoot: string) => void;
104
110
  runPolicyReconcile: typeof runPolicyReconcile;
111
+ isPathTracked: (repoRoot: string, relativePath: string) => boolean;
112
+ stagePath: (repoRoot: string, relativePath: string) => void;
113
+ resolveHeadOid: (repoRoot: string) => string | null;
105
114
  };
106
115
 
107
116
  const defaultDependencies: StageRunnerDependencies = {
@@ -158,6 +167,24 @@ const defaultDependencies: StageRunnerDependencies = {
158
167
  }
159
168
  },
160
169
  runPolicyReconcile,
170
+ isPathTracked: (repoRoot, relativePath) => {
171
+ try {
172
+ new GitService().runGit(['ls-files', '--error-unmatch', '--', relativePath], repoRoot);
173
+ return true;
174
+ } catch {
175
+ return false;
176
+ }
177
+ },
178
+ stagePath: (repoRoot, relativePath) => {
179
+ new GitService().runGit(['add', '--', relativePath], repoRoot);
180
+ },
181
+ resolveHeadOid: (repoRoot) => {
182
+ try {
183
+ return new GitService().runGit(['rev-parse', 'HEAD'], repoRoot).trim();
184
+ } catch {
185
+ return null;
186
+ }
187
+ },
161
188
  };
162
189
 
163
190
  const getDependencies = (
@@ -177,6 +204,14 @@ const notifyAuditSummaryForStage = (
177
204
  });
178
205
  };
179
206
 
207
+ const resolvePrimaryBlockedStageFinding = (
208
+ findings: ReadonlyArray<SnapshotFinding>
209
+ ): SnapshotFinding | undefined => (
210
+ findings.find((finding) => {
211
+ return isSeverityAtLeast(finding.severity, 'ERROR');
212
+ }) ?? findings[0]
213
+ );
214
+
180
215
  const notifyGateBlockedForStage = (params: {
181
216
  dependencies: StageRunnerDependencies;
182
217
  stage: 'PRE_COMMIT' | 'PRE_PUSH' | 'CI';
@@ -190,10 +225,10 @@ const notifyGateBlockedForStage = (params: {
190
225
  evidence?.snapshot.stage === params.stage
191
226
  ? evidence.snapshot.findings
192
227
  : [];
193
- const firstStageFinding = stageFindings[0];
228
+ const primaryStageFinding = resolvePrimaryBlockedStageFinding(stageFindings);
194
229
  const firstViolation = evidence?.ai_gate.violations[0];
195
- const causeCode = firstStageFinding?.code ?? firstViolation?.code ?? params.fallbackCauseCode;
196
- const causeMessage = firstStageFinding?.message ?? firstViolation?.message ?? params.fallbackCauseMessage;
230
+ const causeCode = primaryStageFinding?.code ?? firstViolation?.code ?? params.fallbackCauseCode;
231
+ const causeMessage = primaryStageFinding?.message ?? firstViolation?.message ?? params.fallbackCauseMessage;
197
232
  const remediation =
198
233
  BLOCKED_REMEDIATION_BY_CODE[causeCode]
199
234
  ?? params.fallbackRemediation
@@ -327,12 +362,14 @@ const runHookGateAttempt = async (params: {
327
362
  dependencies: StageRunnerDependencies;
328
363
  stage: HookStage;
329
364
  scope: Parameters<typeof runPlatformGate>[0]['scope'];
365
+ sddDecisionOverride?: Pick<SddDecision, 'allowed' | 'code' | 'message'>;
330
366
  }): Promise<{ exitCode: number; policyTrace: HookPolicyTrace }> => {
331
367
  const resolved = params.dependencies.resolvePolicyForStage(params.stage);
332
368
  const exitCode = await params.dependencies.runPlatformGate({
333
369
  policy: resolved.policy,
334
370
  policyTrace: resolved.trace,
335
371
  scope: params.scope,
372
+ sddDecisionOverride: params.sddDecisionOverride,
336
373
  });
337
374
  return {
338
375
  exitCode,
@@ -345,11 +382,13 @@ const runHookGateWithPolicyRetry = async (params: {
345
382
  repoRoot: string;
346
383
  stage: HookStage;
347
384
  scope: Parameters<typeof runPlatformGate>[0]['scope'];
385
+ sddDecisionOverride?: Pick<SddDecision, 'allowed' | 'code' | 'message'>;
348
386
  }): Promise<{ exitCode: number; policyTrace: HookPolicyTrace }> => {
349
387
  const firstAttempt = await runHookGateAttempt({
350
388
  dependencies: params.dependencies,
351
389
  stage: params.stage,
352
390
  scope: params.scope,
391
+ sddDecisionOverride: params.sddDecisionOverride,
353
392
  });
354
393
  if (firstAttempt.exitCode === 0) {
355
394
  return firstAttempt;
@@ -375,9 +414,44 @@ const runHookGateWithPolicyRetry = async (params: {
375
414
  dependencies: params.dependencies,
376
415
  stage: params.stage,
377
416
  scope: params.scope,
417
+ sddDecisionOverride: params.sddDecisionOverride,
378
418
  });
379
419
  };
380
420
 
421
+ const syncTrackedEvidenceAfterSuccessfulPreCommit = (params: {
422
+ dependencies: StageRunnerDependencies;
423
+ repoRoot: string;
424
+ }): boolean => {
425
+ const evidenceAbsolutePath = join(params.repoRoot, EVIDENCE_FILE_PATH);
426
+ if (!existsSync(evidenceAbsolutePath)) {
427
+ return false;
428
+ }
429
+ if (!params.dependencies.isPathTracked(params.repoRoot, EVIDENCE_FILE_PATH)) {
430
+ return false;
431
+ }
432
+ try {
433
+ params.dependencies.stagePath(params.repoRoot, EVIDENCE_FILE_PATH);
434
+ return false;
435
+ } catch (error) {
436
+ const details = error instanceof Error ? error.message : String(error);
437
+ process.stderr.write(
438
+ `[pumuki][evidence-sync] unable to restage tracked ${EVIDENCE_FILE_PATH}: ${details}\n`
439
+ );
440
+ params.dependencies.notifyGateBlocked({
441
+ repoRoot: params.repoRoot,
442
+ stage: 'PRE_COMMIT',
443
+ totalViolations: 1,
444
+ causeCode: 'EVIDENCE_STAGE_SYNC_FAILED',
445
+ causeMessage:
446
+ `Unable to restage tracked ${EVIDENCE_FILE_PATH} after successful PRE_COMMIT gate.`,
447
+ remediation: BLOCKED_REMEDIATION_BY_CODE.EVIDENCE_STAGE_SYNC_FAILED
448
+ ?? DEFAULT_BLOCKED_REMEDIATION,
449
+ });
450
+ notifyAuditSummaryForStage(params.dependencies, 'PRE_COMMIT');
451
+ return true;
452
+ }
453
+ };
454
+
381
455
  const ZERO_HASH = /^0+$/;
382
456
 
383
457
  const toEvidenceAgeSeconds = (
@@ -450,6 +524,61 @@ const shouldAllowBootstrapPrePush = (rawInput: string): boolean => {
450
524
  return false;
451
525
  };
452
526
 
527
+ const resolveExplicitPrePushRange = (
528
+ rawInput: string
529
+ ): { fromRef: string; toRef: string } | undefined => {
530
+ const lines = rawInput
531
+ .split('\n')
532
+ .map((line) => line.trim())
533
+ .filter((line) => line.length > 0);
534
+
535
+ const eligibleRanges = lines
536
+ .map((line) => {
537
+ const [localRef, localOid, remoteRef, remoteOid] = line.split(/\s+/);
538
+ if (!localRef || !localOid || !remoteRef || !remoteOid) {
539
+ return undefined;
540
+ }
541
+ const localIsDeletion = ZERO_HASH.test(localOid);
542
+ const remoteIsNewBranch = ZERO_HASH.test(remoteOid);
543
+ if (localIsDeletion || remoteIsNewBranch) {
544
+ return undefined;
545
+ }
546
+ return {
547
+ fromRef: remoteOid,
548
+ toRef: localOid,
549
+ };
550
+ })
551
+ .filter((value): value is { fromRef: string; toRef: string } => Boolean(value));
552
+
553
+ if (eligibleRanges.length !== 1) {
554
+ return undefined;
555
+ }
556
+
557
+ return eligibleRanges[0];
558
+ };
559
+
560
+ const resolveHistoricalPrePushSddOverride = (params: {
561
+ dependencies: StageRunnerDependencies;
562
+ repoRoot: string;
563
+ explicitPrePushRange?: { fromRef: string; toRef: string };
564
+ }): Pick<SddDecision, 'allowed' | 'code' | 'message'> | undefined => {
565
+ const explicitRange = params.explicitPrePushRange;
566
+ if (!explicitRange) {
567
+ return undefined;
568
+ }
569
+ const headOid = params.dependencies.resolveHeadOid(params.repoRoot);
570
+ if (!headOid || explicitRange.toRef === headOid) {
571
+ return undefined;
572
+ }
573
+ return {
574
+ allowed: true,
575
+ code: 'ALLOWED',
576
+ message:
577
+ `SDD enforcement suspended for PRE_PUSH historical publish targeting ${explicitRange.toRef.slice(0, 12)} ` +
578
+ `instead of current HEAD ${headOid.slice(0, 12)}.`,
579
+ };
580
+ };
581
+
453
582
  const PRE_PUSH_TOPIC_BRANCH_PREFIXES = [
454
583
  'feature/',
455
584
  'bugfix/',
@@ -568,6 +697,15 @@ export async function runPreCommitStage(
568
697
  ) {
569
698
  return 1;
570
699
  }
700
+ if (
701
+ result.exitCode === 0 &&
702
+ syncTrackedEvidenceAfterSuccessfulPreCommit({
703
+ dependencies: activeDependencies,
704
+ repoRoot,
705
+ })
706
+ ) {
707
+ return 1;
708
+ }
571
709
  emitSuccessfulHookGateSummary({
572
710
  dependencies: activeDependencies,
573
711
  stage: 'PRE_COMMIT',
@@ -594,9 +732,9 @@ export async function runPrePushStage(
594
732
  const repoRoot = activeDependencies.resolveRepoRoot();
595
733
  const manifestSnapshot = captureManifestGuardSnapshot(repoRoot);
596
734
  activeDependencies.ensureRuntimeArtifactsIgnored(repoRoot);
735
+ const prePushInput = activeDependencies.readPrePushStdin();
597
736
  const upstreamRef = activeDependencies.resolveUpstreamRef();
598
737
  if (!upstreamRef) {
599
- const prePushInput = activeDependencies.readPrePushStdin();
600
738
  const bootstrapBaseRef = activeDependencies.resolvePrePushBootstrapBaseRef();
601
739
  const bootstrapByPrePushStdIn = shouldAllowBootstrapPrePush(prePushInput);
602
740
  const bootstrapByFallbackBase = !bootstrapByPrePushStdIn && bootstrapBaseRef !== 'HEAD';
@@ -691,6 +829,15 @@ export async function runPrePushStage(
691
829
  return 1;
692
830
  }
693
831
 
832
+ const explicitPrePushRange = resolveExplicitPrePushRange(prePushInput);
833
+ const prePushFromRef = explicitPrePushRange?.fromRef ?? upstreamRef;
834
+ const prePushToRef = explicitPrePushRange?.toRef ?? 'HEAD';
835
+ const historicalPrePushSddOverride = resolveHistoricalPrePushSddOverride({
836
+ dependencies: activeDependencies,
837
+ repoRoot,
838
+ explicitPrePushRange,
839
+ });
840
+
694
841
  const misalignedUpstream = detectPrePushUpstreamMisalignment({
695
842
  dependencies: activeDependencies,
696
843
  upstreamRef,
@@ -713,8 +860,8 @@ export async function runPrePushStage(
713
860
  dependencies: activeDependencies,
714
861
  repoRoot,
715
862
  stage: 'PRE_PUSH',
716
- fromRef: upstreamRef,
717
- toRef: 'HEAD',
863
+ fromRef: prePushFromRef,
864
+ toRef: prePushToRef,
718
865
  })
719
866
  ) {
720
867
  return 1;
@@ -726,9 +873,10 @@ export async function runPrePushStage(
726
873
  stage: 'PRE_PUSH',
727
874
  scope: {
728
875
  kind: 'range',
729
- fromRef: upstreamRef,
730
- toRef: 'HEAD',
876
+ fromRef: prePushFromRef,
877
+ toRef: prePushToRef,
731
878
  },
879
+ sddDecisionOverride: historicalPrePushSddOverride,
732
880
  });
733
881
  if (
734
882
  enforceManifestGuard({
@@ -365,7 +365,6 @@ export const runLifecycleWatch = async (
365
365
  params?.onTick?.(lastTick);
366
366
  } else {
367
367
  evaluations += 1;
368
- const resolvedPolicy = activeDependencies.resolvePolicyForStage(stage);
369
368
  const gateScope = toGateScope(scope);
370
369
  const facts = await activeDependencies.resolveFactsForGateScope({
371
370
  scope: gateScope,
@@ -374,7 +373,9 @@ export const runLifecycleWatch = async (
374
373
  const changedFiles = collectChangedFilesFromFacts(facts);
375
374
  const evaluatedFiles = collectEvaluatedFilesFromFacts(facts);
376
375
  const scopeHasFileDelta = changedFiles.length > 0 || evaluatedFiles.length > 0;
377
- const runEvaluation = async (): Promise<{
376
+ const runEvaluation = async (
377
+ resolvedPolicy: ResolvedStagePolicy
378
+ ): Promise<{
378
379
  gateExitCode: number;
379
380
  evidence: AiEvidenceV2_1 | undefined;
380
381
  allFindings: ReadonlyArray<SnapshotFinding>;
@@ -439,7 +440,7 @@ export const runLifecycleWatch = async (
439
440
  };
440
441
  };
441
442
 
442
- let evaluation = await runEvaluation();
443
+ let evaluation = await runEvaluation(activeDependencies.resolvePolicyForStage(stage));
443
444
  if (autoPolicyReconcileEnabled && evaluation.gateExitCode !== 0) {
444
445
  const findingCodes = new Set<string>([
445
446
  ...evaluation.allFindings.map((finding) => finding.code),
@@ -455,7 +456,7 @@ export const runLifecycleWatch = async (
455
456
  apply: true,
456
457
  });
457
458
  if (reconcile.autofix.status === 'APPLIED') {
458
- evaluation = await runEvaluation();
459
+ evaluation = await runEvaluation(activeDependencies.resolvePolicyForStage(stage));
459
460
  }
460
461
  }
461
462
  }
@@ -1,6 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { mkdirSync, writeFileSync } from 'node:fs';
3
- import { dirname, isAbsolute, relative, resolve } from 'node:path';
3
+ import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
4
4
  import { readEvidenceResult, type EvidenceReadResult } from '../evidence/readEvidence';
5
5
 
6
6
  export type SddEvidenceScaffoldTestStatus = 'passed' | 'failed';
@@ -80,8 +80,12 @@ const resolveRepoBoundPath = (params: {
80
80
  rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
81
81
  isAbsolute(rel)
82
82
  ) {
83
+ const remediation =
84
+ params.flagName === '--test-output'
85
+ ? ` Try "${params.flagName}=.pumuki/runtime/${basename(params.candidatePath) || 'test-output.log'}".`
86
+ : '';
83
87
  throw new Error(
84
- `[pumuki][sdd] ${params.flagName} must resolve inside repository root: ${params.candidatePath}`
88
+ `[pumuki][sdd] ${params.flagName} must resolve inside repository root: ${params.candidatePath}.${remediation}`
85
89
  );
86
90
  }
87
91
  return resolved;
@@ -24,6 +24,8 @@ const SDD_SESSION_REFRESH_COMMAND =
24
24
  'npx --yes --package pumuki@latest pumuki sdd session --refresh --ttl-minutes=90';
25
25
  const SDD_SESSION_OPEN_AUTO_COMMAND =
26
26
  'npx --yes --package pumuki@latest pumuki sdd session --open --change=auto';
27
+ const SDD_SESSION_OPEN_EXPLICIT_COMMAND =
28
+ 'npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>';
27
29
  const SDD_COMPLETENESS_CONTRACT_VERSION = '1.0';
28
30
 
29
31
  const resolveMissingSessionGuidance = (repoRoot: string): {
@@ -49,11 +51,10 @@ const resolveMissingSessionGuidance = (repoRoot: string): {
49
51
  if (availableChangeIds.length > 1) {
50
52
  return {
51
53
  message:
52
- `SDD session is not active. Run \`${SDD_SESSION_OPEN_AUTO_COMMAND}\` to auto-pick one change ` +
53
- `or \`npx --yes --package pumuki@latest pumuki sdd session --open --change=<id>\` ` +
54
- `for explicit selection. Active changes: ${availableChangeIds.join(', ')}.`,
55
- command: SDD_SESSION_OPEN_AUTO_COMMAND,
56
- fallbackCommand: SDD_SESSION_OPEN_AUTO_COMMAND,
54
+ `SDD session is not active. Run \`${SDD_SESSION_OPEN_EXPLICIT_COMMAND}\` ` +
55
+ `with one active change id. Active changes: ${availableChangeIds.join(', ')}.`,
56
+ command: SDD_SESSION_OPEN_EXPLICIT_COMMAND,
57
+ fallbackCommand: SDD_SESSION_OPEN_EXPLICIT_COMMAND,
57
58
  availableChangeIds,
58
59
  };
59
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.49",
3
+ "version": "6.3.51",
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": {
@@ -26,7 +26,7 @@ export const appendAdapterReadinessNextActionsSection = (params: {
26
26
  }
27
27
  if (hasAdapterRuntimeBlocker(params.source)) {
28
28
  params.lines.push(
29
- '- Execute `docs/validation/adapter-hook-runtime-validation.md`, then regenerate adapter readiness report.'
29
+ '- Execute `docs/validation/adapter-hook-runtime-runbook.md`, then regenerate adapter readiness report.'
30
30
  );
31
31
  }
32
32
  params.lines.push('');
@@ -41,7 +41,7 @@ GENERATED_AT="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
41
41
  echo
42
42
  echo "- [ ] Confirm reports are \`READY\`: blockers, closure-status, external-handoff, startup-unblock."
43
43
  echo "- [ ] Publish final external handoff artifacts/URLs."
44
- echo "- [ ] Update \`docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md\`: mark \`P8-3\` ✅ and set \`P8-4\` 🚧."
44
+ echo "- [ ] Update \`docs/tracking/historico-validacion-ruralgo-03-03-2026.md\`: mark \`P8-3\` ✅ and set \`P8-4\` 🚧."
45
45
  echo "- [ ] Close \`P8-4\` once URLs are attached and handoff is complete."
46
46
  echo
47
47
  echo "## Latest Run URLs"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- FILE="${1:-docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md}"
4
+ FILE="${1:-docs/tracking/historico-validacion-ruralgo-03-03-2026.md}"
5
5
 
6
6
  if [[ ! -f "${FILE}" ]]; then
7
7
  echo "[progress-single-active] missing file: ${FILE}" >&2
@@ -1,15 +1,32 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
+ MASTER_FILE="docs/tracking/maestro-de-seguimiento.md"
5
+
6
+ resolve_default_tracking_file() {
7
+ if [[ -f "${MASTER_FILE}" ]]; then
8
+ local active_file
9
+ active_file="$(
10
+ sed -n 's/^- Plan activo: `\([^`]*\)`.*/\1/p' "${MASTER_FILE}" | head -n 1
11
+ )"
12
+ if [[ -n "${active_file}" ]]; then
13
+ printf '%s\n' "${active_file}"
14
+ return 0
15
+ fi
16
+ fi
17
+
18
+ printf '%s\n' "docs/tracking/plan-activo-pumuki.md"
19
+ }
20
+
4
21
  if [[ "$#" -gt 0 ]]; then
5
22
  FILES=("$@")
6
23
  else
7
24
  FILES=(
8
- "docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md"
25
+ "$(resolve_default_tracking_file)"
9
26
  )
10
27
  fi
11
28
 
12
- ACTIVE_PATTERN='^- 🚧 `P[0-9A-Za-z.-]+` '
29
+ ACTIVE_PATTERN='^- 🚧 (`?P[0-9A-Za-z.-]+`?)'
13
30
  HAS_ERROR=0
14
31
 
15
32
  for FILE in "${FILES[@]}"; do
@@ -19,7 +19,7 @@ FOLLOW_UP_ETA="$3"
19
19
  SUBMITTED_AT_UTC="${4:-$(date -u +"%Y-%m-%dT%H:%M:%SZ")}"
20
20
 
21
21
  HANDOFF_FILE="docs/validation/consumer-startup-escalation-handoff-latest.md"
22
- PROGRESS_FILE="docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md"
22
+ PROGRESS_FILE="docs/tracking/historico-validacion-ruralgo-03-03-2026.md"
23
23
  TODO_FILE="docs/TODO.md"
24
24
 
25
25
  if [[ ! -f "${HANDOFF_FILE}" || ! -f "${PROGRESS_FILE}" || ! -f "${TODO_FILE}" ]]; then
@@ -29,7 +29,7 @@ export const appendPhase5BlockersBlockedNextActions = (params: {
29
29
  }
30
30
  if (hasAdapterRuntimeBlocker(params.summary)) {
31
31
  params.lines.push(
32
- '- Execute `docs/validation/adapter-hook-runtime-validation.md` in a real Adapter session and regenerate reports.'
32
+ '- Execute `docs/validation/adapter-hook-runtime-runbook.md` in a real Adapter session and regenerate reports.'
33
33
  );
34
34
  }
35
35
  if (hasConsumerTriageBlocker(params.summary)) {