priorityframeworks

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 1 Imported by: 0

README

Priority Frameworks

Go CI Go Lint Go SAST Go Report Card Docs Visualization License

Pluggable prioritization systems for Go applications.

Installation

go get github.com/grokify/priority-frameworks

Overview

This package provides a unified interface for working with different prioritization frameworks. Instead of hardcoding a single priority system, applications can allow users to choose the framework that fits their organization's practices.

Built-in Frameworks

Levels are ordered by implementation priority (index 0 = highest). This ordering is designed to drive code actions - items to implement come before items to avoid.

Framework Levels (highest → lowest) Use Case
Severity Critical, High, Medium, Low, Informational Security, incidents, bugs
Priority (P#) P0, P1, P2, P3, P4 Engineering work prioritization
IETF RFC 2119 MUST, SHOULD, MAY Requirements - what to implement
IETF Prohibitions MUST NOT, SHOULD NOT Compliance - constraints to validate
MoSCoW Must have, Should have, Could have, Won't have Agile, product management
General Required, Recommended, Optional, Avoid General-purpose requirement levels

Usage

import pf "github.com/grokify/priority-frameworks"

// Get a built-in framework (returns nil if not found)
framework := pf.Get("severity")
if framework == nil {
    log.Fatal("unknown framework")
}

// Parse a level (returns nil if not found)
level := framework.Parse("Critical")
if level == nil {
    log.Fatal("unknown level")
}
fmt.Println(level.Name)       // "Critical"
fmt.Println(level.Actionable) // true
fmt.Println(level.Color)      // "#7f1d1d"

// Compare levels within a framework
result := framework.Compare("critical", "low") // 1 (critical > low)

// Get highest/lowest priority levels
highest := framework.Highest() // Critical
lowest := framework.Lowest()   // Informational

// Get only actionable levels
actionable := framework.ActionableLevels()

// List all built-in frameworks
ids := pf.AllBuiltinIDs()    // ["severity", "priority", "ietf", "moscow", "general"]
frameworks := pf.All()       // []*Framework

Cross-Framework Normalization

Compare and map levels across different frameworks:

severity := pf.Severity()
moscow := pf.MoSCoW()

// Normalize to a common scale (1-4)
norm := pf.Normalize(severity, "critical") // NormalizedCritical (4)

// Compare across frameworks
result := pf.CompareAcross(severity, "critical", moscow, "must") // 0 (equal)

// Map a level to another framework
mapped := pf.MapTo(severity, "critical", moscow)
fmt.Println(mapped.Name) // "Must have"

Score Ranges

Map numeric scores to priority levels (e.g., CVSS scores to severity):

// Built-in CVSS score range
sr := pf.CVSSScoreRange()
level, err := sr.LevelFromScore(7.5)
if err != nil {
    log.Fatal(err)
}
fmt.Println(level.Name) // "High"

// CVSS thresholds: Critical (9.0+), High (7.0+), Medium (4.0+), Low (0.1+), Info (0)

// Custom percentage-based range
sr := pf.PercentageScoreRange(pf.Severity())
level, _ := sr.LevelFromScore(85.0)  // "Critical" (75%+)

Level Counts

Track counts of items at each priority level:

counts := pf.NewLevelCounts(pf.Severity())

// Add counts
counts.Increment("critical")
counts.Add("high", 5)
counts.Add("medium", 10)

// Query counts
fmt.Println(counts.Total())           // 16
fmt.Println(counts.ActionableTotal()) // 16 (excludes Informational)
fmt.Println(counts.HigherThan("medium"))      // 6 (Critical + High)
fmt.Println(counts.HigherThanOrEqual("high")) // 6 (Critical + High)

// Merge from another source
otherCounts := pf.NewLevelCounts(pf.Severity())
otherCounts.Add("critical", 3)
counts.Merge(otherCounts)

// Get counts in framework order
slice := counts.Slice() // [4, 5, 10, 0, 0] (Critical to Informational)

Custom Frameworks

Create your own framework:

custom := &pf.Framework{
    ID:          "custom",
    Name:        "Custom Framework",
    Description: "My organization's priority system",
    Levels: []pf.Level{
        {ID: "urgent", Name: "Urgent", Actionable: true, Color: "#dc2626"},
        {ID: "normal", Name: "Normal", Actionable: true, Color: "#ca8a04"},
        {ID: "backlog", Name: "Backlog", Actionable: false, Color: "#6b7280"},
    },
}

Design

  • Position = Priority: Level position in the Levels slice determines priority (index 0 = highest)
  • Action-oriented ordering: Levels are ordered to drive code actions - things to implement before things to avoid (e.g., IETF: MUST before MUST NOT)
  • Simple data types: Frameworks are plain structs, easily serializable to JSON/YAML
  • Actionable flag: Distinguishes between levels that require action vs. informational
  • Aliases: Multiple names can map to the same level (e.g., "CRITICAL", "Crit", "S1")

Contributing

Contributions are welcome. Please see the CHANGELOG for recent changes.

License

MIT - see LICENSE for details.

Documentation

Overview

Package priorityframeworks provides pluggable prioritization systems.

Built-in frameworks include Severity, Priority (P#), IETF RFC 2119, MoSCoW, and a General requirement framework. Users can choose which framework fits their organization's practices.

The position in the Levels slice implies priority order (index 0 = highest).

Index

Constants

View Source
const (
	IDSeverity         = "severity"
	IDPriority         = "priority"
	IDIETF             = "ietf"
	IDIETFProhibitions = "ietf-prohibitions"
	IDMoSCoW           = "moscow"
	IDGeneral          = "general"
)

FrameworkID constants for built-in frameworks.

Variables

View Source
var ErrScoreOutOfRange = errors.New("score out of range")

ErrScoreOutOfRange is returned when a score is outside the defined ranges.

Functions

func AllBuiltinIDs

func AllBuiltinIDs() []string

AllBuiltinIDs returns all built-in framework IDs.

func CompareAcross

func CompareAcross(fA *Framework, levelA string, fB *Framework, levelB string) int

CompareAcross compares levels from potentially different frameworks. Returns: 1 if a > b (higher priority), -1 if a < b, 0 if equal.

Types

type Framework

type Framework struct {
	// ID is the unique identifier (e.g., "severity", "moscow").
	ID string `json:"id" yaml:"id"`

	// Name is the display name (e.g., "Severity", "MoSCoW").
	Name string `json:"name" yaml:"name"`

	// Description explains when to use this framework.
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// Levels are ordered from highest to lowest priority.
	// Index 0 is the highest priority level.
	Levels []Level `json:"levels" yaml:"levels"`
}

Framework represents a prioritization system with ordered levels.

func All

func All() []*Framework

All returns all built-in frameworks.

func General

func General() *Framework

General returns a general-purpose requirement framework. Simple Required/Recommended/Optional/Avoid levels.

func Get

func Get(id string) *Framework

Get returns a built-in framework by ID. Returns nil if not found.

func IETF

func IETF() *Framework

IETF returns the IETF RFC 2119 requirements framework (MUST/SHOULD/MAY). Use this for prioritizing requirements - what to implement. For prohibitions (MUST NOT/SHOULD NOT), use IETFProhibitions().

func IETFProhibitions added in v0.2.0

func IETFProhibitions() *Framework

IETFProhibitions returns the IETF RFC 2119 prohibitions framework (MUST NOT/SHOULD NOT). Use this for compliance checking - constraints to validate against. For requirements (MUST/SHOULD/MAY), use IETF().

func MoSCoW

func MoSCoW() *Framework

MoSCoW returns the MoSCoW framework (Must/Should/Could/Won't). Common in agile and product management.

func Priority

func Priority() *Framework

Priority returns the Priority framework (P0/P1/P2/P3/P4). Common in engineering teams for work prioritization.

func Severity

func Severity() *Framework

Severity returns the Severity framework (Critical/High/Medium/Low/Informational). Common in security, incident response, and bug tracking.

func (*Framework) ActionableLevels

func (f *Framework) ActionableLevels() []Level

ActionableLevels returns only levels where Actionable is true.

func (*Framework) Compare

func (f *Framework) Compare(a, b string) int

Compare compares two level identifiers within this framework. Returns: 1 if a > b (higher priority), -1 if a < b, 0 if equal. Returns 0 if either level is not found.

func (*Framework) Default

func (f *Framework) Default() *Level

Default returns the default level (middle of the range).

func (*Framework) Highest

func (f *Framework) Highest() *Level

Highest returns the highest priority level (index 0).

func (*Framework) IndexOf

func (f *Framework) IndexOf(idOrName string) int

IndexOf returns the index of the level with the given ID or name. Returns -1 if not found.

func (*Framework) Lowest

func (f *Framework) Lowest() *Level

Lowest returns the lowest priority level (last index).

func (*Framework) Parse

func (f *Framework) Parse(s string) *Level

Parse returns the Level matching the given string (ID, Name, or Alias). Returns nil if not found.

type Level

type Level struct {
	// ID is the canonical identifier (e.g., "critical", "must", "p0").
	ID string `json:"id" yaml:"id"`

	// Name is the display name (e.g., "Critical", "MUST", "P0").
	Name string `json:"name" yaml:"name"`

	// Aliases are alternative names that parse to this level.
	Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`

	// Actionable indicates whether items at this level require action.
	// For example, "Critical" and "Must have" are actionable; "Informational" is not.
	Actionable bool `json:"actionable" yaml:"actionable"`

	// Color is the suggested display color (hex code).
	Color string `json:"color,omitempty" yaml:"color,omitempty"`
}

Level represents a single priority level within a framework.

func MapTo

func MapTo(src *Framework, srcLevel string, dst *Framework) *Level

MapTo maps a level from one framework to the closest equivalent in another. Returns nil if the source level is not found.

type LevelCounts added in v0.2.0

type LevelCounts struct {
	// Framework is the associated framework (optional, for validation).
	Framework *Framework

	// Counts maps level IDs to their count.
	Counts map[string]int
}

LevelCounts tracks counts of items at each priority level. This is useful for dashboards, reports, and aggregations.

func NewLevelCounts added in v0.2.0

func NewLevelCounts(f *Framework) *LevelCounts

NewLevelCounts creates a new LevelCounts for the given framework. If framework is provided, initializes all levels to zero.

func (*LevelCounts) ActionableTotal added in v0.2.0

func (lc *LevelCounts) ActionableTotal() int

ActionableTotal returns the sum of counts for actionable levels only. Requires Framework to be set; returns 0 if Framework is nil.

func (*LevelCounts) Add added in v0.2.0

func (lc *LevelCounts) Add(levelID string, count int)

Add increments the count for the given level ID. If the level doesn't exist in the map, it's created with count 1.

func (*LevelCounts) Clone added in v0.2.0

func (lc *LevelCounts) Clone() *LevelCounts

Clone returns a deep copy of the LevelCounts.

func (*LevelCounts) Get added in v0.2.0

func (lc *LevelCounts) Get(levelID string) int

Get returns the count for the given level ID. Returns 0 if the level is not found.

func (*LevelCounts) HigherThan added in v0.2.0

func (lc *LevelCounts) HigherThan(levelID string) int

HigherThan returns the sum of counts for levels higher than the given level. Requires Framework to be set; returns 0 if Framework is nil.

func (*LevelCounts) HigherThanOrEqual added in v0.2.0

func (lc *LevelCounts) HigherThanOrEqual(levelID string) int

HigherThanOrEqual returns the sum of counts for levels >= the given level. Requires Framework to be set; returns 0 if Framework is nil.

func (*LevelCounts) Increment added in v0.2.0

func (lc *LevelCounts) Increment(levelID string)

Increment adds 1 to the count for the given level ID.

func (*LevelCounts) IsEmpty added in v0.2.0

func (lc *LevelCounts) IsEmpty() bool

IsEmpty returns true if all counts are zero.

func (*LevelCounts) LowerThan added in v0.2.0

func (lc *LevelCounts) LowerThan(levelID string) int

LowerThan returns the sum of counts for levels lower than the given level. Requires Framework to be set; returns 0 if Framework is nil.

func (*LevelCounts) Merge added in v0.2.0

func (lc *LevelCounts) Merge(other *LevelCounts)

Merge adds counts from another LevelCounts.

func (*LevelCounts) Reset added in v0.2.0

func (lc *LevelCounts) Reset()

Reset sets all counts to zero.

func (*LevelCounts) Slice added in v0.2.0

func (lc *LevelCounts) Slice() []int

Slice returns counts in framework level order. Requires Framework to be set; returns nil if Framework is nil.

func (*LevelCounts) Total added in v0.2.0

func (lc *LevelCounts) Total() int

Total returns the sum of all counts.

type NormalizedPriority

type NormalizedPriority int

NormalizedPriority represents a normalized priority bucket (1-4). This allows comparison across different frameworks.

const (
	NormalizedCritical NormalizedPriority = 4 // Highest
	NormalizedHigh     NormalizedPriority = 3
	NormalizedMedium   NormalizedPriority = 2
	NormalizedLow      NormalizedPriority = 1 // Lowest
)

func Normalize

func Normalize(f *Framework, levelID string) NormalizedPriority

Normalize converts a level index to a normalized priority (1-4). This enables sorting and comparison across different frameworks.

The normalization maps the level's position in the framework to one of four buckets: Critical (4), High (3), Medium (2), Low (1).

func NormalizeIndex

func NormalizeIndex(index, total int) NormalizedPriority

NormalizeIndex converts a level index and total count to normalized priority.

func (NormalizedPriority) String

func (p NormalizedPriority) String() string

String returns the display name for the normalized priority.

type RangeEntry added in v0.2.0

type RangeEntry struct {
	// LevelID is the framework level this range maps to.
	LevelID string

	// MinScore is the minimum score (inclusive) for this level.
	MinScore float64
}

RangeEntry defines a minimum score threshold for a level.

type ScoreRange added in v0.2.0

type ScoreRange struct {
	// Framework is the target framework for level lookups.
	Framework *Framework

	// Ranges defines the score thresholds for each level.
	// Each entry maps a level ID to its minimum score (inclusive).
	// Levels are evaluated from highest to lowest score.
	Ranges []RangeEntry

	// Min is the minimum valid score (inclusive).
	Min float64

	// Max is the maximum valid score (inclusive).
	Max float64
}

ScoreRange maps numeric score ranges to framework levels. This enables conversion from scoring systems (like CVSS) to priority levels.

func CVSSScoreRange added in v0.2.0

func CVSSScoreRange() *ScoreRange

CVSSScoreRange returns a ScoreRange for CVSS v3 scores mapped to Severity levels. CVSS ranges: None (0), Low (0.1-3.9), Medium (4.0-6.9), High (7.0-8.9), Critical (9.0-10.0)

func PercentageScoreRange added in v0.2.0

func PercentageScoreRange(f *Framework) *ScoreRange

PercentageScoreRange returns a ScoreRange for percentage scores (0-100) mapped to a 4-level framework using quartiles.

func (*ScoreRange) LevelFromScore added in v0.2.0

func (sr *ScoreRange) LevelFromScore(score float64) (*Level, error)

LevelFromScore returns the level for the given score. Returns nil and ErrScoreOutOfRange if score is outside Min/Max bounds. Returns nil if no matching range is found.

func (*ScoreRange) MustLevelFromScore added in v0.2.0

func (sr *ScoreRange) MustLevelFromScore(score float64) *Level

MustLevelFromScore returns the level for the given score. Panics if score is out of range. Returns nil if no match found.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL