@lumenflow/initiatives 1.0.0

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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Centralized path constants for Initiative management scripts.
3
+ *
4
+ * Mirrors wu-paths.mjs pattern. Single source of truth for all
5
+ * initiative-related file paths.
6
+ *
7
+ * @example
8
+ * import { INIT_PATHS } from './lib/initiative-paths.js';
9
+ * const initPath = INIT_PATHS.INITIATIVE('INIT-001'); // 'docs/04-operations/tasks/initiatives/INIT-001.yaml'
10
+ */
11
+ export declare const INIT_PATHS: {
12
+ /**
13
+ * Get path to Initiative YAML file
14
+ * @param {string} id - Initiative ID (e.g., 'INIT-001')
15
+ * @returns {string} Path to Initiative YAML file
16
+ */
17
+ INITIATIVE: (id: string) => string;
18
+ /**
19
+ * Get path to initiatives directory
20
+ * @returns {string} Path to initiatives directory
21
+ */
22
+ INITIATIVES_DIR: () => string;
23
+ /**
24
+ * Get path to WU directory (for scanning WUs by initiative)
25
+ * @returns {string} Path to WU directory
26
+ */
27
+ WU_DIR: () => string;
28
+ };
@@ -0,0 +1,29 @@
1
+ import path from 'node:path';
2
+ /**
3
+ * Centralized path constants for Initiative management scripts.
4
+ *
5
+ * Mirrors wu-paths.mjs pattern. Single source of truth for all
6
+ * initiative-related file paths.
7
+ *
8
+ * @example
9
+ * import { INIT_PATHS } from './lib/initiative-paths.js';
10
+ * const initPath = INIT_PATHS.INITIATIVE('INIT-001'); // 'docs/04-operations/tasks/initiatives/INIT-001.yaml'
11
+ */
12
+ export const INIT_PATHS = {
13
+ /**
14
+ * Get path to Initiative YAML file
15
+ * @param {string} id - Initiative ID (e.g., 'INIT-001')
16
+ * @returns {string} Path to Initiative YAML file
17
+ */
18
+ INITIATIVE: (id) => path.join('docs', '04-operations', 'tasks', 'initiatives', `${id}.yaml`),
19
+ /**
20
+ * Get path to initiatives directory
21
+ * @returns {string} Path to initiatives directory
22
+ */
23
+ INITIATIVES_DIR: () => path.join('docs', '04-operations', 'tasks', 'initiatives'),
24
+ /**
25
+ * Get path to WU directory (for scanning WUs by initiative)
26
+ * @returns {string} Path to WU directory
27
+ */
28
+ WU_DIR: () => path.join('docs', '04-operations', 'tasks', 'wu'),
29
+ };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Initiative YAML Schema (WU-1246)
3
+ *
4
+ * Zod schema for runtime validation of Initiative YAML structure.
5
+ * Part of the Initiative System Phase 1 - Schema & Validation Foundation.
6
+ *
7
+ * @see {@link tools/validate.mjs} - Consumer (CI validation)
8
+ * @see {@link tools/lib/initiative-validator.mjs} - Consumer (dependency graph validation)
9
+ * @see {@link docs/04-operations/tasks/initiatives/} - Initiative YAML files
10
+ */
11
+ import { z } from 'zod';
12
+ /**
13
+ * Zod schema for Initiative Phase
14
+ *
15
+ * Phases are optional subdivisions within an initiative.
16
+ * Sequence matters - phases are ordered by id.
17
+ */
18
+ export declare const InitiativePhaseSchema: z.ZodObject<{
19
+ id: z.ZodNumber;
20
+ title: z.ZodString;
21
+ status: z.ZodEnum<{
22
+ in_progress: "in_progress";
23
+ done: "done";
24
+ pending: "pending";
25
+ blocked: "blocked";
26
+ }>;
27
+ }, z.core.$strip>;
28
+ /**
29
+ * Zod schema for Initiative YAML structure
30
+ *
31
+ * Initiatives group related WUs for visualization, progress tracking,
32
+ * and dependency management.
33
+ */
34
+ export declare const InitiativeSchema: z.ZodObject<{
35
+ id: z.ZodString;
36
+ slug: z.ZodString;
37
+ title: z.ZodString;
38
+ description: z.ZodOptional<z.ZodString>;
39
+ status: z.ZodEnum<{
40
+ draft: "draft";
41
+ open: "open";
42
+ in_progress: "in_progress";
43
+ done: "done";
44
+ archived: "archived";
45
+ }>;
46
+ priority: z.ZodOptional<z.ZodEnum<{
47
+ P0: "P0";
48
+ P1: "P1";
49
+ P2: "P2";
50
+ P3: "P3";
51
+ }>>;
52
+ owner: z.ZodOptional<z.ZodString>;
53
+ created: z.ZodString;
54
+ target_date: z.ZodOptional<z.ZodString>;
55
+ phases: z.ZodOptional<z.ZodArray<z.ZodObject<{
56
+ id: z.ZodNumber;
57
+ title: z.ZodString;
58
+ status: z.ZodEnum<{
59
+ in_progress: "in_progress";
60
+ done: "done";
61
+ pending: "pending";
62
+ blocked: "blocked";
63
+ }>;
64
+ }, z.core.$strip>>>;
65
+ success_metrics: z.ZodOptional<z.ZodArray<z.ZodString>>;
66
+ labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
67
+ wus: z.ZodOptional<z.ZodArray<z.ZodString>>;
68
+ }, z.core.$strip>;
69
+ /**
70
+ * TypeScript type inferred from schema
71
+ *
72
+ * @typedef {import('zod').z.infer<typeof InitiativeSchema>} Initiative
73
+ * @typedef {import('zod').z.infer<typeof InitiativePhaseSchema>} InitiativePhase
74
+ */
75
+ /**
76
+ * Validates Initiative data against schema
77
+ *
78
+ * @param {unknown} data - Parsed YAML data to validate
79
+ * @returns {z.SafeParseReturnType<Initiative, Initiative>} Validation result
80
+ *
81
+ * @example
82
+ * const result = validateInitiative(yamlData);
83
+ * if (!result.success) {
84
+ * result.error.issues.forEach(issue => {
85
+ * console.error(`${issue.path.join('.')}: ${issue.message}`);
86
+ * });
87
+ * }
88
+ */
89
+ export declare function validateInitiative(data: unknown): z.ZodSafeParseResult<{
90
+ id: string;
91
+ slug: string;
92
+ title: string;
93
+ status: "draft" | "open" | "in_progress" | "done" | "archived";
94
+ created: string;
95
+ description?: string;
96
+ priority?: "P0" | "P1" | "P2" | "P3";
97
+ owner?: string;
98
+ target_date?: string;
99
+ phases?: {
100
+ id: number;
101
+ title: string;
102
+ status: "in_progress" | "done" | "pending" | "blocked";
103
+ }[];
104
+ success_metrics?: string[];
105
+ labels?: string[];
106
+ wus?: string[];
107
+ }>;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Initiative YAML Schema (WU-1246)
3
+ *
4
+ * Zod schema for runtime validation of Initiative YAML structure.
5
+ * Part of the Initiative System Phase 1 - Schema & Validation Foundation.
6
+ *
7
+ * @see {@link tools/validate.mjs} - Consumer (CI validation)
8
+ * @see {@link tools/lib/initiative-validator.mjs} - Consumer (dependency graph validation)
9
+ * @see {@link docs/04-operations/tasks/initiatives/} - Initiative YAML files
10
+ */
11
+ import { z } from 'zod';
12
+ import { INIT_STATUSES, PHASE_STATUSES, PRIORITIES, INIT_PATTERNS, } from './initiative-constants.js';
13
+ /**
14
+ * Date format pattern (YYYY-MM-DD)
15
+ * Note: Kept local as it's only used in schema validation, not elsewhere
16
+ */
17
+ const DATE_PATTERN = INIT_PATTERNS.DATE;
18
+ /**
19
+ * Zod schema for Initiative Phase
20
+ *
21
+ * Phases are optional subdivisions within an initiative.
22
+ * Sequence matters - phases are ordered by id.
23
+ */
24
+ export const InitiativePhaseSchema = z.object({
25
+ /** Phase number (non-negative integer, determines sequence; 0 valid for foundation phases) */
26
+ id: z.number().int().nonnegative({ message: 'Phase id must be a non-negative integer' }),
27
+ /** Phase title */
28
+ title: z.string().min(1, { message: 'Phase title is required' }),
29
+ /** Phase status */
30
+ status: z.enum(PHASE_STATUSES, {
31
+ error: `Status must be one of: ${PHASE_STATUSES.join(', ')}`,
32
+ }),
33
+ });
34
+ /**
35
+ * Zod schema for Initiative YAML structure
36
+ *
37
+ * Initiatives group related WUs for visualization, progress tracking,
38
+ * and dependency management.
39
+ */
40
+ export const InitiativeSchema = z.object({
41
+ /** Initiative identifier (INIT-NNN or INIT-NAME format) */
42
+ id: z
43
+ .string()
44
+ .regex(INIT_PATTERNS.INIT_ID, { message: 'ID must match pattern INIT-NNN or INIT-NAME' }),
45
+ /** Kebab-case unique identifier for URLs and references */
46
+ slug: z
47
+ .string()
48
+ .regex(INIT_PATTERNS.SLUG, { message: 'Slug must be kebab-case (e.g., shock-protocol)' }),
49
+ /** Initiative title */
50
+ title: z.string().min(1, { message: 'Title is required' }),
51
+ /** Detailed description (optional) */
52
+ description: z.string().optional(),
53
+ /** Initiative lifecycle status */
54
+ status: z.enum(INIT_STATUSES, {
55
+ error: `Status must be one of: ${INIT_STATUSES.join(', ')}`,
56
+ }),
57
+ /** Priority level (optional) */
58
+ priority: z
59
+ .enum(PRIORITIES, {
60
+ error: `Priority must be one of: ${PRIORITIES.join(', ')}`,
61
+ })
62
+ .optional(),
63
+ /** Owner (team or individual, optional) */
64
+ owner: z.string().optional(),
65
+ /** Creation date (YYYY-MM-DD) */
66
+ created: z.string().regex(DATE_PATTERN, { message: 'Created must be YYYY-MM-DD format' }),
67
+ /** Target completion date (optional, YYYY-MM-DD) */
68
+ target_date: z
69
+ .string()
70
+ .regex(DATE_PATTERN, { message: 'Target date must be YYYY-MM-DD format' })
71
+ .optional(),
72
+ /** Ordered phases within the initiative (optional) */
73
+ phases: z.array(InitiativePhaseSchema).optional(),
74
+ /** Success metrics for completion (optional) */
75
+ success_metrics: z.array(z.string()).optional(),
76
+ /** Labels for cross-cutting concerns (optional) */
77
+ labels: z.array(z.string()).optional(),
78
+ /** Linked WU IDs (optional, bidirectional link with WU.initiative field) */
79
+ wus: z.array(z.string()).optional(),
80
+ });
81
+ /**
82
+ * TypeScript type inferred from schema
83
+ *
84
+ * @typedef {import('zod').z.infer<typeof InitiativeSchema>} Initiative
85
+ * @typedef {import('zod').z.infer<typeof InitiativePhaseSchema>} InitiativePhase
86
+ */
87
+ /**
88
+ * Validates Initiative data against schema
89
+ *
90
+ * @param {unknown} data - Parsed YAML data to validate
91
+ * @returns {z.SafeParseReturnType<Initiative, Initiative>} Validation result
92
+ *
93
+ * @example
94
+ * const result = validateInitiative(yamlData);
95
+ * if (!result.success) {
96
+ * result.error.issues.forEach(issue => {
97
+ * console.error(`${issue.path.join('.')}: ${issue.message}`);
98
+ * });
99
+ * }
100
+ */
101
+ export function validateInitiative(data) {
102
+ return InitiativeSchema.safeParse(data);
103
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Initiative Validator (WU-1246, WU-2319)
3
+ *
4
+ * Validates WU dependency graphs for cycles, orphan references,
5
+ * initiative consistency, and bidirectional WU-Initiative references.
6
+ *
7
+ * Part of the Initiative System Phase 1 - Schema & Validation Foundation.
8
+ * WU-2319: Added bidirectional validation for WU<->Initiative references.
9
+ *
10
+ * @see {@link tools/validate.mjs} - Consumer (CI validation)
11
+ * @see {@link tools/lib/initiative-schema.mjs} - Initiative schema
12
+ */
13
+ /**
14
+ * WU object interface for validation
15
+ */
16
+ interface WUObject {
17
+ id?: string;
18
+ blocks?: string[];
19
+ blocked_by?: string[];
20
+ initiative?: string;
21
+ phase?: number;
22
+ [key: string]: unknown;
23
+ }
24
+ /**
25
+ * Initiative object interface for validation
26
+ */
27
+ interface InitiativeObject {
28
+ id?: string;
29
+ slug?: string;
30
+ wus?: string[];
31
+ phases?: Array<{
32
+ id: number;
33
+ }>;
34
+ [key: string]: unknown;
35
+ }
36
+ /**
37
+ * Orphan reference result
38
+ */
39
+ interface OrphanRef {
40
+ wuId: string;
41
+ field: string;
42
+ ref: string;
43
+ }
44
+ /**
45
+ * Detects circular dependencies in WU dependency graph using DFS
46
+ *
47
+ * Uses standard cycle detection: tracks visited nodes and nodes in current
48
+ * recursion stack. If we encounter a node already in the recursion stack,
49
+ * we've found a cycle.
50
+ *
51
+ * @param {Map<string, Object>} wuMap - Map of WU ID to WU object
52
+ * @returns {{hasCycle: boolean, cycles: string[][]}} Cycle detection result
53
+ *
54
+ * @example
55
+ * const wuMap = new Map([
56
+ * ['WU-001', { id: 'WU-001', blocks: ['WU-002'] }],
57
+ * ['WU-002', { id: 'WU-002', blocks: ['WU-001'] }],
58
+ * ]);
59
+ * const result = detectCycles(wuMap);
60
+ * // result.hasCycle === true
61
+ * // result.cycles contains the cycle path
62
+ */
63
+ export declare function detectCycles(wuMap: Map<string, WUObject>): {
64
+ hasCycle: boolean;
65
+ cycles: string[][];
66
+ };
67
+ export declare function detectOrphanRefs(wuMap: Map<string, WUObject>, allWuIds: Set<string>): {
68
+ orphans: OrphanRef[];
69
+ };
70
+ /**
71
+ * Validates initiative references in WUs
72
+ *
73
+ * Checks that:
74
+ * - Initiative field references exist (by ID or slug)
75
+ * - Phase numbers are defined in parent initiative
76
+ *
77
+ * Returns warnings (not errors) for soft enforcement.
78
+ *
79
+ * @param {Map<string, Object>} wuMap - Map of WU ID to WU object
80
+ * @param {Map<string, Object>} initiatives - Map of Initiative ID to Initiative object
81
+ * @returns {{warnings: string[]}} Validation warnings
82
+ *
83
+ * @example
84
+ * const wuMap = new Map([['WU-001', { id: 'WU-001', initiative: 'INIT-999' }]]);
85
+ * const initiatives = new Map();
86
+ * const result = validateInitiativeRefs(wuMap, initiatives);
87
+ * // result.warnings contains warning about missing initiative
88
+ */
89
+ export declare function validateInitiativeRefs(wuMap: Map<string, WUObject>, initiatives: Map<string, InitiativeObject>): {
90
+ warnings: string[];
91
+ };
92
+ /**
93
+ * Validates bidirectional references between WUs and Initiatives (WU-2319)
94
+ *
95
+ * Checks two directions:
96
+ * 1. WU->Initiative: If WU has initiative: INIT-XXX, the initiative.wus must list the WU
97
+ * 2. Initiative->WU: If initiative.wus lists a WU, the WU should have initiative: field
98
+ *
99
+ * Also delegates to validateInitiativeRefs for phase mismatch detection.
100
+ *
101
+ * Note: All bidirectional mismatches are returned as ERRORS (not warnings).
102
+ * The caller (validateDependencyGraph) may choose to treat these as warnings
103
+ * for backward compatibility with pre-existing data inconsistencies.
104
+ *
105
+ * @param {Map<string, Object>} wuMap - Map of WU ID to WU object
106
+ * @param {Map<string, Object>} initiatives - Map of Initiative ID to Initiative object
107
+ * @returns {{errors: string[], warnings: string[]}} Validation results
108
+ *
109
+ * @example
110
+ * const wuMap = new Map([['WU-001', { id: 'WU-001', initiative: 'INIT-001' }]]);
111
+ * const initiatives = new Map([['INIT-001', { id: 'INIT-001', wus: ['WU-001'] }]]);
112
+ * const result = validateBidirectionalRefs(wuMap, initiatives);
113
+ * // result.errors === [] (all refs match)
114
+ */
115
+ export declare function validateBidirectionalRefs(wuMap: Map<string, WUObject>, initiatives: Map<string, InitiativeObject>): {
116
+ errors: string[];
117
+ warnings: string[];
118
+ };
119
+ /**
120
+ * Validates the complete WU dependency graph
121
+ *
122
+ * Orchestrates all validation checks:
123
+ * 1. Cycle detection (error)
124
+ * 2. Orphan reference detection (error)
125
+ * 3. Initiative reference validation (warning)
126
+ * 4. Bidirectional WU-Initiative validation (error) [WU-2319]
127
+ *
128
+ * @param {Map<string, Object>} wuMap - Map of WU ID to WU object
129
+ * @param {Set<string>} allWuIds - Set of all known WU IDs
130
+ * @param {Map<string, Object>} initiatives - Map of Initiative ID to Initiative object
131
+ * @returns {{errors: string[], warnings: string[]}} Validation results
132
+ *
133
+ * @example
134
+ * const result = validateDependencyGraph(wuMap, allWuIds, initiatives);
135
+ * if (result.errors.length > 0) {
136
+ * console.error('Validation failed:', result.errors);
137
+ * }
138
+ */
139
+ export declare function validateDependencyGraph(wuMap: Map<string, WUObject>, allWuIds: Set<string>, initiatives: Map<string, InitiativeObject>): {
140
+ errors: string[];
141
+ warnings: string[];
142
+ };
143
+ export {};