Files
16gagent/research/pr-37/pr-37-delivery-planning/index.mjs
T
2026-06-06 10:40:48 +08:00

196 lines
6.8 KiB
JavaScript

/**
* PR-37 Delivery Planning — Entry Point
*
* Parts F, G, H, I:
* - F: Sprint Planner
* - G: Release Planner
* - H: Batch Planner
* - I: Capacity Planner
*
* Consumes SF-02 Requirement Package output and generates delivery
* planning artifacts. Compatible with PR-36 Factory Registry.
*
* @module pr-37-delivery-planning
* @since PR-37
*/
import { generateSprintPlan, defaultSprintConfig } from "./sprint-planner.mjs";
import { generateReleasePlan } from "./release-planner.mjs";
import { generateBatchPlan } from "./batch-planner.mjs";
import { generateCapacityPlan, defaultCapacityConfig } from "./capacity-planner.mjs";
import { alignRoadmapWithPlans } from "./roadmap-aligner.mjs";
// ═══════════════════════════════════════════════════════
// PR-37 Artifact Constants
// ═══════════════════════════════════════════════════════
export const PR37_ARTIFACTS = Object.freeze({
SPRINT_PLAN: "sprint-plan",
RELEASE_PLAN: "release-plan",
BATCH_PLAN: "batch-plan",
CAPACITY_PLAN: "capacity-plan",
ALIGNMENT_REPORT: "alignment-report",
});
// ═══════════════════════════════════════════════════════
// Factory Integration
// ═══════════════════════════════════════════════════════
/**
* Create a delivery planning factory that consumes SF-02 upstream artifacts
* and produces all 4 delivery plans.
*
* The factory accepts a PR-36 FactoryInput object (or a simplified upstream
* artifacts object) and returns all plans bundled as a FactoryOutput.
*
* @param {object} upstreamArtifacts — SF-02 output containing:
* - epics: object[]
* - features: object[]
* - userStories: object[]
* - dependencies / graph: dependency graph
* - priorities: priority matrix entries
* - mvpScope: MVP scope definition
* @param {object} [config] — Optional config overrides
* @param {object} [config.sprint] — Sprint planner config
* @param {object} [config.capacity] — Capacity planner config
* @returns {object} FactoryOutput with all delivery plans
*
* @example
* ```js
* const factory = createDeliveryPlanningFactory();
* const output = factory(sf02Output, {
* sprint: { teamVelocity: 20, maxStoryPointsPerSprint: 25 },
* capacity: { teamSize: 5, availabilityFactor: 0.8 },
* });
* // output.sprintPlan, output.releasePlan, output.batchPlan, output.capacityPlan
* ```
*/
export function createDeliveryPlanningFactory(upstreamArtifacts, config = {}) {
if (!upstreamArtifacts) {
return {
factoryId: "PR-37",
status: "failed",
error: "No upstream artifacts provided. Provide SF-02 output.",
};
}
const warnings = [];
// ── 1. Extract SF-02 artifacts ──
const stories = upstreamArtifacts.userStories || upstreamArtifacts.stories || [];
const epics = upstreamArtifacts.epics || [];
const features = upstreamArtifacts.features || [];
// Support both { graph: { nodes, edges } } and flat { nodes, edges }
const dependencies = upstreamArtifacts.dependencies
|| upstreamArtifacts.graph
|| { nodes: [], edges: [] };
const priorities = upstreamArtifacts.priorities || [];
const mvpScope = upstreamArtifacts.mvpScope || null;
// ── 2. Validate data ──
if (stories.length === 0) {
warnings.push("No user stories found in upstream artifacts");
}
// ── 3. Generate Sprint Plan (Part F) ──
const sprintConfig = defaultSprintConfig(config.sprint || {});
const sprintPlan = generateSprintPlan({
stories,
dependencies,
priorities,
config: sprintConfig,
});
if (sprintPlan.warnings && sprintPlan.warnings.length > 0) {
warnings.push(...sprintPlan.warnings.map(w => `[Sprint] ${w}`));
}
// ── 4. Generate Release Plan (Part G) ──
const releasePlan = generateReleasePlan({
mvpScope,
priorities,
dependencies,
stories,
epics,
features,
});
if (releasePlan.warnings && releasePlan.warnings.length > 0) {
warnings.push(...releasePlan.warnings.map(w => `[Release] ${w}`));
}
// ── 5. Generate Batch Plan (Part H) ──
const batchPlan = generateBatchPlan({
stories,
dependencies,
priorities,
sprints: sprintPlan,
releases: releasePlan,
});
if (batchPlan.warnings && batchPlan.warnings.length > 0) {
warnings.push(...batchPlan.warnings.map(w => `[Batch] ${w}`));
}
// ── 6. Generate Capacity Plan (Part I) ──
const capacityConfig = defaultCapacityConfig(config.capacity || {});
const capacityPlan = generateCapacityPlan({
sprints: sprintPlan,
releases: releasePlan,
config: capacityConfig,
});
if (capacityPlan.warnings && capacityPlan.warnings.length > 0) {
warnings.push(...capacityPlan.warnings.map(w => `[Capacity] ${w}`));
}
// ── 7. Align with Roadmap (Part J) ──
const roadmap = upstreamArtifacts.roadmap || mvpScope?.phases;
const alignmentReport = roadmap
? alignRoadmapWithPlans({
roadmap: { phases: Array.isArray(roadmap) ? roadmap : (roadmap.phases || []) },
sprintPlan,
releasePlan,
batchPlan,
mvpScope,
})
: null;
// ── 8. Assemble output ──
const output = {
factoryId: "PR-37",
status: warnings.length > 0 && stories.length === 0 ? "blocked" : "passed",
sprintPlan,
releasePlan,
batchPlan,
capacityPlan,
alignmentReport,
warnings: warnings.length > 0 ? warnings : undefined,
metadata: {
factoryId: "PR-37",
upstreamArtifactId: upstreamArtifacts.id || "SF-02",
generatedAt: new Date().toISOString(),
totalStories: stories.length,
totalEpics: epics.length,
totalFeatures: features.length,
totalSprints: sprintPlan.metrics.totalSprints,
totalReleases: releasePlan.releases ? releasePlan.releases.length : 0,
},
};
return output;
}
// ═══════════════════════════════════════════════════════
// Barrel Re-exports
// ═══════════════════════════════════════════════════════
export { generateSprintPlan, defaultSprintConfig } from "./sprint-planner.mjs";
export { generateReleasePlan } from "./release-planner.mjs";
export { generateBatchPlan } from "./batch-planner.mjs";
export { generateCapacityPlan, defaultCapacityConfig } from "./capacity-planner.mjs";
export { alignRoadmapWithPlans } from "./roadmap-aligner.mjs";