Cascading Goals Framework TRD¶
Technical Requirements Document
Version: 1.0.0 Date: 2026-05-22 Author: PRISM Team Status: Draft
Overview¶
This document defines the technical architecture and implementation details for the cascading goals framework supporting both OKR and V2MOM methodologies.
Architecture¶
High-Level Design¶
┌─────────────────────────────────────────────────────────────┐
│ CLI Layer │
│ prism goals [cascade|align|import|suggest|plan] │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Goals Service Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Cascade │ │ Align │ │ Suggest/Plan │ │
│ │ Service │ │ Service │ │ Service │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Unified Framework Interface │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ goals.Framework │ │
│ │ - Type() string │ │
│ │ - GoalItems() []GoalItem │ │
│ │ - ResultItems() []ResultItem │ │
│ │ - Validate(opts) []ValidationError │ │
│ │ - Cascade(parent) (Framework, error) │ │
│ │ - AlignmentScore(parent) float64 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ OKR Implementation │ │ V2MOM Implementation │
│ goals/okr/ │ │ goals/v2mom/ │
│ │ │ │
│ - OKRDocument │ │ - V2MOM │
│ - Objective │ │ - Method │
│ - KeyResult │ │ - Measure │
└─────────────────────────┘ └─────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PRISM Maturity Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Goals │ │ SLIs │ │ State │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
Package Structure¶
prism-roadmap/
├── goals/
│ ├── framework.go # Unified Framework interface
│ ├── goal_item.go # GoalItem, ResultItem types
│ ├── cascade.go # Cascade service
│ ├── align.go # Alignment service
│ ├── suggest.go # Suggestion service
│ ├── okr/
│ │ ├── okr.go # OKR types (extended)
│ │ ├── cascade.go # OKR-specific cascading
│ │ ├── framework.go # Framework implementation
│ │ └── validate.go # OKR validation
│ └── v2mom/
│ ├── v2mom.go # V2MOM types (existing)
│ ├── cascade.go # V2MOM cascading (existing ParentID)
│ ├── framework.go # Framework implementation
│ └── validate.go # V2MOM validation
├── cli/
│ └── goals/
│ ├── cascade.go # cascade command
│ ├── align.go # align command
│ ├── import.go # import command
│ ├── suggest.go # suggest command
│ └── plan.go # plan command
Data Model¶
OKR Extensions¶
// File: goals/okr/okr.go
package okr
// Objective represents a qualitative goal with cascading support.
type Objective struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
Rationale string `json:"rationale,omitempty"`
Category string `json:"category,omitempty"`
Owner string `json:"owner,omitempty"`
Status string `json:"status,omitempty"`
Progress float64 `json:"progress,omitempty"`
KeyResults []KeyResult `json:"keyResults,omitempty"`
Risks []Risk `json:"risks,omitempty"`
// Cascading support (NEW)
ParentObjectiveID string `json:"parentObjectiveId,omitempty"`
CompanyOKRIDs []string `json:"companyOkrIds,omitempty"`
ChildObjectiveIDs []string `json:"childObjectiveIds,omitempty"`
// Alignment metadata (NEW)
AlignmentScore float64 `json:"alignmentScore,omitempty"`
AlignmentStatus string `json:"alignmentStatus,omitempty"` // aligned, partial, unaligned
}
// KeyResult represents a measurable outcome with alignment tracking.
type KeyResult struct {
ID string `json:"id"`
Title string `json:"title"`
Baseline string `json:"baseline,omitempty"`
Target string `json:"target"`
Current string `json:"current,omitempty"`
Score float64 `json:"score,omitempty"`
Confidence string `json:"confidence,omitempty"`
Status string `json:"status,omitempty"`
// Alignment tracking (NEW)
SupportsObjectiveIDs []string `json:"supportsObjectiveIds,omitempty"`
SLIIDs []string `json:"sliIds,omitempty"` // Link to PRISM SLIs
// Phase targets (existing)
PhaseTargets []PhaseTarget `json:"phaseTargets,omitempty"`
}
Unified Framework Interface¶
// File: goals/framework.go
package goals
import "time"
// Framework abstracts over OKR and V2MOM goal-setting methodologies.
type Framework interface {
// Type returns "okr" or "v2mom"
Type() string
// Metadata returns document-level information
Metadata() FrameworkMetadata
// GoalItems returns all goals (Objectives or Methods) in unified format
GoalItems() []GoalItem
// ResultItems returns all results (Key Results or Measures) in unified format
ResultItems() []ResultItem
// Validate checks document structure and relationships
Validate(opts ValidationOptions) []ValidationError
// Cascade generates a child framework from this parent
Cascade(opts CascadeOptions) (Framework, error)
// AlignmentScore calculates alignment with parent framework (0.0-1.0)
AlignmentScore(parent Framework) float64
// Import converts to PRISM goals format
ToPRISMGoals() ([]PRISMGoal, error)
}
// FrameworkMetadata contains document-level information.
type FrameworkMetadata struct {
ID string `json:"id"`
Name string `json:"name"`
Owner string `json:"owner,omitempty"`
Team string `json:"team,omitempty"`
Period string `json:"period,omitempty"`
Status string `json:"status,omitempty"`
ParentID string `json:"parentId,omitempty"`
CreatedAt time.Time `json:"createdAt,omitempty"`
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}
// GoalItem represents a goal in framework-agnostic format.
type GoalItem struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Owner string `json:"owner,omitempty"`
Status string `json:"status,omitempty"`
Progress float64 `json:"progress,omitempty"`
Priority int `json:"priority,omitempty"`
ParentID string `json:"parentId,omitempty"`
ChildIDs []string `json:"childIds,omitempty"`
Results []ResultItem `json:"results,omitempty"`
// Source tracking
SourceType string `json:"sourceType"` // "objective" or "method"
SourceID string `json:"sourceId"`
}
// ResultItem represents a measurable result in framework-agnostic format.
type ResultItem struct {
ID string `json:"id"`
Name string `json:"name"`
Baseline string `json:"baseline,omitempty"`
Target string `json:"target"`
Current string `json:"current,omitempty"`
Score float64 `json:"score,omitempty"`
Status string `json:"status,omitempty"`
GoalID string `json:"goalId"`
// PRISM integration
SLIIDs []string `json:"sliIds,omitempty"`
// Source tracking
SourceType string `json:"sourceType"` // "keyResult" or "measure"
SourceID string `json:"sourceId"`
}
// CascadeOptions configures child framework generation.
type CascadeOptions struct {
Team string `json:"team"`
Owner string `json:"owner,omitempty"`
Period string `json:"period,omitempty"`
IncludeGoalIDs []string `json:"includeGoalIds,omitempty"` // Filter to specific goals
ExcludeGoalIDs []string `json:"excludeGoalIds,omitempty"` // Exclude specific goals
ResultsPerGoal int `json:"resultsPerGoal,omitempty"` // Max results per goal (0=all)
InheritResults bool `json:"inheritResults,omitempty"` // Copy parent results as templates
}
// ValidationOptions configures validation behavior.
type ValidationOptions struct {
RequireParentAlignment bool `json:"requireParentAlignment,omitempty"`
MaxResultsPerGoal int `json:"maxResultsPerGoal,omitempty"`
RequireSLILinks bool `json:"requireSliLinks,omitempty"`
}
// ValidationError represents a validation issue.
type ValidationError struct {
Code string `json:"code"`
Message string `json:"message"`
Path string `json:"path,omitempty"`
Severity string `json:"severity"` // error, warning, info
}
Cascade Service¶
// File: goals/cascade.go
package goals
// CascadeService generates child frameworks from parents.
type CascadeService struct {
// Optional: template customization
GoalNameTemplate string // e.g., "[{Team}] {ParentGoalName}"
ResultNameTemplate string // e.g., "Support: {ParentResultName}"
}
// Cascade creates a child framework from parent.
func (s *CascadeService) Cascade(parent Framework, opts CascadeOptions) (Framework, error) {
switch parent.Type() {
case "okr":
return s.cascadeOKR(parent, opts)
case "v2mom":
return s.cascadeV2MOM(parent, opts)
default:
return nil, fmt.Errorf("unknown framework type: %s", parent.Type())
}
}
// cascadeOKR creates child OKR from parent OKR.
func (s *CascadeService) cascadeOKR(parent Framework, opts CascadeOptions) (Framework, error) {
parentOKR := parent.(*okr.OKRDocument)
child := &okr.OKRDocument{
Metadata: okr.Metadata{
ID: generateID(),
Name: fmt.Sprintf("%s OKRs", opts.Team),
Team: opts.Team,
Owner: opts.Owner,
Period: opts.Period,
ParentID: parentOKR.Metadata.ID,
Status: "draft",
},
}
// Generate child objectives from parent
for _, parentObj := range parentOKR.Objectives {
if !s.shouldInclude(parentObj.ID, opts) {
continue
}
childObj := okr.Objective{
ID: generateID(),
Title: s.formatGoalName(parentObj.Title, opts),
ParentObjectiveID: parentObj.ID,
Status: "draft",
}
// Optionally inherit key results as templates
if opts.InheritResults {
for _, parentKR := range parentObj.KeyResults {
childKR := okr.KeyResult{
ID: generateID(),
Title: s.formatResultName(parentKR.Title, opts),
Target: parentKR.Target,
SupportsObjectiveIDs: []string{parentObj.ID},
}
childObj.KeyResults = append(childObj.KeyResults, childKR)
}
}
child.Objectives = append(child.Objectives, childObj)
}
return child, nil
}
Alignment Service¶
// File: goals/align.go
package goals
// AlignmentService validates and scores goal alignment.
type AlignmentService struct{}
// AlignmentResult contains alignment analysis.
type AlignmentResult struct {
OverallScore float64 `json:"overallScore"` // 0.0-1.0
Status string `json:"status"` // aligned, partial, unaligned
GoalAlignments []GoalAlignment `json:"goalAlignments"`
MissingSupport []string `json:"missingSupport"` // Parent goals without child support
UnalignedGoals []string `json:"unalignedGoals"` // Child goals without parent link
Recommendations []string `json:"recommendations"`
}
// GoalAlignment represents alignment between child and parent goal.
type GoalAlignment struct {
ChildGoalID string `json:"childGoalId"`
ChildGoalName string `json:"childGoalName"`
ParentGoalID string `json:"parentGoalId,omitempty"`
ParentGoalName string `json:"parentGoalName,omitempty"`
Score float64 `json:"score"`
Status string `json:"status"`
Issues []string `json:"issues,omitempty"`
}
// Align validates child framework alignment with parent.
func (s *AlignmentService) Align(child, parent Framework) (*AlignmentResult, error) {
result := &AlignmentResult{
Status: "aligned",
}
parentGoals := parent.GoalItems()
childGoals := child.GoalItems()
// Build parent goal lookup
parentMap := make(map[string]GoalItem)
for _, g := range parentGoals {
parentMap[g.ID] = g
}
// Track which parent goals are supported
supported := make(map[string]bool)
// Analyze each child goal
for _, childGoal := range childGoals {
alignment := GoalAlignment{
ChildGoalID: childGoal.ID,
ChildGoalName: childGoal.Name,
Score: 1.0,
Status: "aligned",
}
if childGoal.ParentID == "" {
alignment.Score = 0.0
alignment.Status = "unaligned"
alignment.Issues = append(alignment.Issues, "No parent goal linked")
result.UnalignedGoals = append(result.UnalignedGoals, childGoal.ID)
} else if parentGoal, ok := parentMap[childGoal.ParentID]; ok {
alignment.ParentGoalID = parentGoal.ID
alignment.ParentGoalName = parentGoal.Name
supported[parentGoal.ID] = true
// Check result alignment
if !s.hasAlignedResults(childGoal, parentGoal) {
alignment.Score = 0.5
alignment.Status = "partial"
alignment.Issues = append(alignment.Issues,
"Results don't explicitly support parent objectives")
}
} else {
alignment.Score = 0.0
alignment.Status = "unaligned"
alignment.Issues = append(alignment.Issues,
fmt.Sprintf("Parent goal %s not found", childGoal.ParentID))
}
result.GoalAlignments = append(result.GoalAlignments, alignment)
}
// Check for unsupported parent goals
for _, parentGoal := range parentGoals {
if !supported[parentGoal.ID] {
result.MissingSupport = append(result.MissingSupport, parentGoal.ID)
result.Recommendations = append(result.Recommendations,
fmt.Sprintf("Consider adding goals to support '%s'", parentGoal.Name))
}
}
// Calculate overall score
result.OverallScore = s.calculateOverallScore(result)
if result.OverallScore < 0.5 {
result.Status = "unaligned"
} else if result.OverallScore < 0.9 {
result.Status = "partial"
}
return result, nil
}
Suggestion Service¶
// File: goals/suggest.go
package goals
import (
prism "github.com/grokify/prism-maturity"
"github.com/grokify/prism-maturity/maturity"
)
// SuggestionService generates goal suggestions from SLI gaps.
type SuggestionService struct{}
// Suggestion represents a suggested goal for maturity improvement.
type Suggestion struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
Priority string `json:"priority"` // P0, P1, P2, P3
Domain string `json:"domain"`
Layer string `json:"layer,omitempty"`
CurrentLevel float64 `json:"currentLevel"`
TargetLevel float64 `json:"targetLevel"`
SLIGaps []SLIGap `json:"sliGaps"`
SuggestedKRs []SuggestedKR `json:"suggestedKRs"`
EstimatedEffort string `json:"estimatedEffort"` // S, M, L, XL
Impact string `json:"impact"` // low, medium, high
}
// SLIGap represents a gap between current and target SLI value.
type SLIGap struct {
SLIID string `json:"sliId"`
SLIName string `json:"sliName"`
CurrentValue float64 `json:"currentValue"`
TargetValue float64 `json:"targetValue"`
GapPercent float64 `json:"gapPercent"`
Threshold string `json:"threshold"` // The threshold to meet
}
// SuggestedKR represents a suggested Key Result.
type SuggestedKR struct {
Title string `json:"title"`
Baseline string `json:"baseline"`
Target string `json:"target"`
SLIID string `json:"sliId"`
}
// SuggestOptions configures suggestion generation.
type SuggestOptions struct {
TargetLevel int `json:"targetLevel,omitempty"` // M1-M5 (0 = next level)
Domains []string `json:"domains,omitempty"` // Filter by domain
Layers []string `json:"layers,omitempty"` // Filter by layer
MaxSuggestions int `json:"maxSuggestions,omitempty"` // Limit results
MinGapPercent float64 `json:"minGapPercent,omitempty"` // Min gap to include
}
// Suggest generates goal suggestions from maturity gaps.
func (s *SuggestionService) Suggest(
model *maturity.Spec,
state *prism.PRISMDocument,
opts SuggestOptions,
) ([]Suggestion, error) {
var suggestions []Suggestion
// Analyze each SLI
for _, sli := range model.AllSLIs() {
// Apply filters
if !s.matchesFilters(sli, opts) {
continue
}
// Get current value from state
currentValue := s.getCurrentValue(state, sli.ID)
currentLevel := s.calculateLevel(model, sli.ID, currentValue)
// Determine target level
targetLevel := opts.TargetLevel
if targetLevel == 0 {
targetLevel = int(currentLevel) + 1
if targetLevel > 5 {
continue // Already at max
}
}
// Find gaps to reach target level
gaps := s.findGaps(model, sli.ID, currentValue, targetLevel)
if len(gaps) == 0 {
continue // No gaps
}
// Check gap threshold
maxGap := s.maxGapPercent(gaps)
if opts.MinGapPercent > 0 && maxGap < opts.MinGapPercent {
continue
}
// Generate suggestion
suggestion := Suggestion{
ID: fmt.Sprintf("suggestion-%s", sli.ID),
Title: fmt.Sprintf("Improve %s to M%d", sli.Name, targetLevel),
Description: s.generateDescription(sli, gaps, targetLevel),
Priority: s.calculatePriority(gaps, sli),
Domain: sli.Category,
Layer: sli.Layer,
CurrentLevel: currentLevel,
TargetLevel: float64(targetLevel),
SLIGaps: gaps,
SuggestedKRs: s.generateKRs(sli, gaps),
EstimatedEffort: s.estimateEffort(gaps),
Impact: s.assessImpact(sli, gaps),
}
suggestions = append(suggestions, suggestion)
}
// Sort by priority
sort.Slice(suggestions, func(i, j int) bool {
return suggestions[i].Priority < suggestions[j].Priority
})
// Apply limit
if opts.MaxSuggestions > 0 && len(suggestions) > opts.MaxSuggestions {
suggestions = suggestions[:opts.MaxSuggestions]
}
return suggestions, nil
}
CLI Commands¶
Goals Command Group¶
// File: cli/goals/root.go
var goalsCmd = &cobra.Command{
Use: "goals",
Short: "Goal framework management (OKR and V2MOM)",
Long: `Unified commands for managing OKR and V2MOM goal frameworks.`,
}
func init() {
goalsCmd.AddCommand(cascadeCmd)
goalsCmd.AddCommand(alignCmd)
goalsCmd.AddCommand(importCmd)
goalsCmd.AddCommand(suggestCmd)
goalsCmd.AddCommand(planCmd)
}
Cascade Command¶
// File: cli/goals/cascade.go
var cascadeCmd = &cobra.Command{
Use: "cascade <parent-file>",
Short: "Generate child goals from parent framework",
Long: `Generate a child OKR or V2MOM document from a parent document.
The child document will have goals linked to parent goals via ParentID fields.
Examples:
# Cascade company OKRs to team
prism goals cascade company-okrs.json --team "Platform Team" -o team-okrs.json
# Cascade V2MOM with specific goals only
prism goals cascade company-v2mom.json --team "SRE" --include-goals "reliability,performance"
# Inherit parent KRs as templates
prism goals cascade parent.json --team "DevOps" --inherit-results`,
RunE: runCascade,
}
var (
cascadeTeam string
cascadeOwner string
cascadePeriod string
cascadeOutput string
cascadeIncludeGoals []string
cascadeExcludeGoals []string
cascadeInheritResult bool
)
func init() {
cascadeCmd.Flags().StringVar(&cascadeTeam, "team", "", "Team name for child document (required)")
cascadeCmd.Flags().StringVar(&cascadeOwner, "owner", "", "Owner for child document")
cascadeCmd.Flags().StringVar(&cascadePeriod, "period", "", "Period (e.g., Q2 2026)")
cascadeCmd.Flags().StringVarP(&cascadeOutput, "output", "o", "", "Output file (default: stdout)")
cascadeCmd.Flags().StringSliceVar(&cascadeIncludeGoals, "include-goals", nil, "Goal IDs to include")
cascadeCmd.Flags().StringSliceVar(&cascadeExcludeGoals, "exclude-goals", nil, "Goal IDs to exclude")
cascadeCmd.Flags().BoolVar(&cascadeInheritResult, "inherit-results", false, "Copy parent results as templates")
cascadeCmd.MarkFlagRequired("team")
}
Suggest Command¶
// File: cli/goals/suggest.go
var suggestCmd = &cobra.Command{
Use: "suggest",
Short: "Suggest goals from SLI maturity gaps",
Long: `Analyze current SLI state against maturity thresholds and suggest goals.
Examples:
# Suggest goals to reach next maturity level
prism goals suggest --model model.json --state state.json
# Suggest goals to reach M4
prism goals suggest --model model.json --state state.json --target-level 4
# Filter by domain
prism goals suggest --model model.json --state state.json --domain reliability
# Output as OKR format
prism goals suggest --model model.json --state state.json --format okr -o suggested-okrs.json`,
RunE: runSuggest,
}
var (
suggestModel string
suggestState string
suggestTargetLevel int
suggestDomains []string
suggestLayers []string
suggestMaxResults int
suggestMinGap float64
suggestFormat string
suggestOutput string
)
func init() {
suggestCmd.Flags().StringVar(&suggestModel, "model", "", "Maturity model file (required)")
suggestCmd.Flags().StringVar(&suggestState, "state", "", "State file (required)")
suggestCmd.Flags().IntVar(&suggestTargetLevel, "target-level", 0, "Target maturity level (1-5, 0=next)")
suggestCmd.Flags().StringSliceVar(&suggestDomains, "domain", nil, "Filter by domain")
suggestCmd.Flags().StringSliceVar(&suggestLayers, "layer", nil, "Filter by layer")
suggestCmd.Flags().IntVar(&suggestMaxResults, "max", 10, "Maximum suggestions")
suggestCmd.Flags().Float64Var(&suggestMinGap, "min-gap", 0, "Minimum gap percent to include")
suggestCmd.Flags().StringVarP(&suggestFormat, "format", "f", "json", "Output format: json, okr, v2mom, markdown")
suggestCmd.Flags().StringVarP(&suggestOutput, "output", "o", "", "Output file (default: stdout)")
suggestCmd.MarkFlagRequired("model")
suggestCmd.MarkFlagRequired("state")
}
Testing Strategy¶
Unit Tests¶
// File: goals/cascade_test.go
func TestCascadeOKR(t *testing.T) {
parent := &okr.OKRDocument{
Metadata: okr.Metadata{ID: "parent-1", Name: "Company OKRs"},
Objectives: []okr.Objective{
{ID: "obj-1", Title: "Improve Reliability", KeyResults: []okr.KeyResult{
{ID: "kr-1", Title: "99.9% Availability", Target: "99.9%"},
}},
},
}
svc := &CascadeService{}
child, err := svc.Cascade(parent, CascadeOptions{
Team: "Platform Team",
InheritResults: true,
})
require.NoError(t, err)
require.Equal(t, "okr", child.Type())
goals := child.GoalItems()
require.Len(t, goals, 1)
require.Equal(t, "obj-1", goals[0].ParentID)
require.Len(t, goals[0].Results, 1)
}
func TestAlignmentScore(t *testing.T) {
tests := []struct {
name string
child Framework
parent Framework
expected float64
}{
{"fully aligned", fullyAlignedChild, parent, 1.0},
{"partial alignment", partialChild, parent, 0.5},
{"no alignment", unalignedChild, parent, 0.0},
}
svc := &AlignmentService{}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
result, err := svc.Align(tc.child, tc.parent)
require.NoError(t, err)
require.InDelta(t, tc.expected, result.OverallScore, 0.1)
})
}
}
Integration Tests¶
// File: goals/suggest_integration_test.go
func TestSuggestFromRealModel(t *testing.T) {
model, err := maturity.ReadSpecFile("testdata/model.json")
require.NoError(t, err)
state, err := prism.ReadFile("testdata/state.json")
require.NoError(t, err)
svc := &SuggestionService{}
suggestions, err := svc.Suggest(model, state, SuggestOptions{
TargetLevel: 4,
MaxSuggestions: 5,
})
require.NoError(t, err)
require.LessOrEqual(t, len(suggestions), 5)
for _, s := range suggestions {
require.NotEmpty(t, s.Title)
require.GreaterOrEqual(t, s.TargetLevel, s.CurrentLevel)
require.NotEmpty(t, s.SLIGaps)
}
}
Performance Considerations¶
| Operation | Target | Approach |
|---|---|---|
| Cascade 50 goals | <100ms | Single pass, no I/O |
| Align 1000 goals | <1s | Index parent goals, single pass |
| Suggest 100 SLIs | <500ms | Parallel gap calculation |
Security Considerations¶
- Input validation on all file paths
- JSON schema validation before processing
- No external network calls
- Sanitize user-provided strings in templates
Migration Path¶
Existing OKR Documents¶
Add optional fields without breaking:
{
"objectives": [{
"id": "obj-1",
"title": "Existing Objective",
"parentObjectiveId": null, // Optional, backward compatible
"keyResults": [...]
}]
}
Existing V2MOM Documents¶
No changes required - ParentID already exists.
Dependencies¶
| Package | Version | Purpose |
|---|---|---|
| github.com/grokify/prism-maturity | latest | SLI/maturity access |
| github.com/spf13/cobra | v1.8+ | CLI framework |
| github.com/stretchr/testify | v1.8+ | Testing |
Related Documents¶
- PRD.md - Product Requirements Document
- ROADMAP.md - Implementation Roadmap