mineproductivity.decision¶
Purpose¶
Decision-support and recommendation frameworks that translate analytics' statistical judgments (trends, benchmarks, confidence intervals) into recommended, ranked, explained, actionable decisions — the platform's prescriptive layer, sitting directly above analytics' descriptive layer.
Scope¶
What belongs here: - Decision/recommendation interfaces and contracts. - Decision provenance and explainability contracts.
What must never belong here:
- AI agent orchestration (see agents).
- Presentation/visualization logic (see visualization).
Responsibilities¶
- Implements the
decisionsubsystem as defined in the Reference Implementation Blueprint v1.0. - Phase 07.1 — Decision Intelligence Foundation is implemented: every component required before concrete decision models can exist, per
docs/architecture/07_Decision_Intelligence_Design_Specification.md.DecisionModel(ABC)/DecisionContext(§8) mirroranalytics.AnalyticsModel/AnalyticsContextone layer up —decide()is the non-overridden orchestration wrapper checking aDecisionContextcarries at least oneKPIResult/AnalyticsResult,_decide()is the abstract method every concrete strategy implements.DecisionMetadata/DecisionCategory(§30) are the minimal registration schema, as light asanalytics.AnalyticsMetadata. The fullDecisionResultfamily (§28) is implemented:Recommendation,RankedRecommendation,ActionPlan,Alert,RootCauseResult,WhatIfResult(envelope subclasses) andExplanation,DecisionScore,ConfidenceScore,ActionPriority,ThresholdBreach(plain, supporting value objects) — every type serializes viacore.serializationwith no bespoke per-type serializer.Threshold(normallythresholds.py's own later-phase module) is included ahead of schedule becauseThresholdBreachcannot be correctly typed without it.DecisionPipeline/PipelineStage/ModelStage(§9) compose ordered stages over oneDecisionContext, holding no strategy-specific branching, mirroringanalytics.AnalyticsPipelineone layer down.REGISTRY/register(§32) specializeregistry.Registryexactly asanalytics._registry/kpis._registrydo. The full exception hierarchy (§6) is implemented. - Phase 07.2 — Decision Rule Engine is implemented: rule composition/evaluation, policy governance, and the default, concrete decision strategy.
Rule(§10) is atypealias overcore.BaseSpecification[DecisionContext], reusing the same composition mechanismevents.EventFilteralready established — no bespoke rule language.RuleEngine.evaluate()/RuleEngineStage(§10) isolate one malformed rule's failure from the rest and attach triggered rule names toDecisionContext.triggered_rules— a necessary, minimal, disclosed extension of that Phase 07.1 class (Noneby default, meaning "not yet evaluated," deliberately distinct from(), "evaluated, nothing triggered" — collapsing the two was a real bug caught by this phase's own QA review and fixed before release).DecisionStatus/Policy(§12) are versioned, governed business artifacts, publishable viapolicy.publish_policy(an internal function — seepolicy.py's own module docstring for why it is not re-exported, and for a disclosed, inherent limitation of its "changed rules" detection when reusingcore.PredicateSpecification's lambda-identity equality);policy.policy_historyrecords every version a publish transitioned toSuperseded; publishing aPolicyasActivewhile itsstrategy_codenames no registeredDecisionModelraisesDecisionModelNotFoundErrorat activation time, never silently at first evaluation (§12's own activation gate).DecisionStrategy(ABC)/ThresholdDecisionStrategy(§14) is the default, concrete, rule/threshold-driven strategy — self-registered intoREGISTRYat import time exactly asanalytics.trend.LinearTrendModelself-registers one layer down; itscheck_thresholds()method performs real threshold-breach evaluation, including dotted-path field resolution againstAnalyticsResultevidence (§13). - Phase 07.3 — Decision Intelligence Analysis Layer is implemented: the analytical capabilities operating on already-produced
Recommendation/DecisionResultobjects.DecisionScorer/ConfidenceScorer(§23, §24) compute the numeric weight backing ranking and the trust weight backing how strongly a recommendation should be acted on — the latter deriving fromanalytics.DataQualityScorewhen present in aDecisionContext's evidence, never recomputing data quality itself; both reuse one shared_rule_strength/_SEVERITY_WEIGHTSfoundation so ranking and prioritization never silently disagree on what "critical" numerically means.RankingStrategy(ABC)/WeightedScoreRanking(§16) orderRecommendations byDecisionScore.value, descending (stable-sort tie-break), self-registered intoREGISTRY; its ownrank()method is the primary, richly-tested batch-ranking capability, with_decide()a thin ABC-satisfying adapter returning the top-ranked item.ExplanationBuilder/ExplanationStage(§17) walk aRecommendation's provenance into a structured, evidence-linkedExplanation;ExplanationStageis a non-terminal pipeline stage (see its own module docstring for a disclosed spec-text inconsistency this resolves).ActionPrioritizer(§20) assigns eachRankedRecommendationanActionPriority(urgency from severity, impact fromDecisionScore.value, effort from an optional caller-supplied estimate) — a distinct question from ranking.RootCauseAnalyzer(§18) is an interface-only ABC with zero concrete subclasses by design (ADR-0007), mirroringanalytics.ForecastingModel's own interface-only shape.DecisionContextgained a third field this phase,recommendations(alongsidetriggered_rulesfrom 07.2), for the same "batch operation over a context-only method signature" reason. - Phase 07.4 — Decision Operational Services is implemented, completing the package:
WhatIfEngine(§19) is an interface-only ABC with zero concrete subclasses by design, the decision-layer counterpart toRootCauseAnalyzer— it deliberately reusesevents.AsOf's already-reservedscenariofield rather than inventing a second scenario concept, so a future Digital Twin plugin implements_simulateagainst a hook that already exists.ActionPlanner(§21) sequences prioritized actions into anActionPlan, respecting caller-supplied dependencies via its own narrow, self-contained topological ordering (a priority-queue-based Kahn's algorithm,O((V+E) log V)) rather than reusingkpis.DependencyGraph, which is tightly coupled toRegistry[str, type[BaseKPI]]/KPIMetadata.dependencies— a shape that does not fit arbitrary action-to-action dependencies (§33's own anti-pattern entry); it fails loudly (Result.err) on both a cyclic dependency and a duplicatepolicy_codeamong the actions being planned (the latter caught by this phase's own QA review — silently keeping only one same-keyed action would silently drop the other from the plan).AlertGenerator(§22) produces anAlertfrom aThresholdBreachor a high-severityRecommendation— a pure value-object factory with no channel-delivery side effects; since neither aThresholdBreachnor aRecommendationcarries a severity-for-a-breach or a scope value directly,AlertGeneratorreusesThresholdDecisionStrategy's own precedent of a caller/policy-configured severity (breach_severity, rather than inventing a magnitude-to-severity heuristic) and an optionalscopekeyword mirroringActionPlanner.plan's owndependenciesdefault-mapping convention.RealTimeDecisionSession/BatchDecisionRunner(§25, §26) are the two execution modes — the live, event-driven counterpart and the bounded, scheduled-report counterpart of running oneDecisionPipeline— both composingkpis.KPIEngine/analytics.BatchAnalyticsRunnerrather than recomputing anything themselves (§3.2), mirroringanalytics.StreamingAnalyticsSession/BatchAnalyticsRunnerone layer down; both accept an optionalaudit_trailbeyond what §25/§26's own bare pseudocode constructors show, the smallest compatible way to honor §33's "never bypassDecisionAuditTrail" anti-pattern without breaking the spec's literal signature.RealTimeDecisionSessionguards its per-scopelatest()result against an out-of-order-delivery race (caught by this phase's own QA review: a handler's refresh work runs outside its lock, so two concurrent deliveries for the same scope could otherwise let an older envelope's slower handler overwrite a newer one's already-stored result) by keying its stored state on the envelope's own canonicalevent_time_utcrather than last-writer-wins.DecisionAuditTrail/DecisionAuditEntry(§27, §28) are the append-only accountability record every operationally-actionableDecisionPipelinerun should feed —record()serializes concurrent appends via one lock,query()reads a snapshot and filters outside it, and every entry serializes viacore.serializationwith no bespoke handling, exactly like every other value object in this package.recommendation.pyexists as the §6 module holding recommendation-generation logic with, per §6's own entry for it, no public classes, functions, or API of its own (theRecommendationtype lives inresult.py;ThresholdDecisionStrategy's methods delegate construction to it, keeping exactly one summary-text/traceability format package-wide) — originally folded intostrategy.pyin Phase 07.2 and extracted into its own file during this phase's completion pass, so the package structure matches §6's twenty-two-module list exactly. This completes every module design spec §6 enumerates —decisionis now feature-complete per the Reference Implementation Blueprint, including the checklist's examples (examples/decision/, four scripts) and recorded benchmarks (benchmark/reports/decision/).
Contents¶
__init__.py— public API surface (49 symbols, the full design spec §7 list).abstractions.py—DecisionModel(ABC),DecisionContext.metadata.py—DecisionMetadata,DecisionCategory.result.py—DecisionResultand every concrete result/value type implemented in Phase 07.1.thresholds.py—Threshold(included ahead of schedule; see its own module docstring).pipeline.py—DecisionPipeline,PipelineStage(ABC),ModelStage.rules.py—Rule,RuleEngine,RuleEngineStage.policy.py—DecisionStatus,Policy.strategy.py—DecisionStrategy(ABC),ThresholdDecisionStrategy.recommendation.py— recommendation-generation logic (no public API of its own, per design spec §6;ThresholdDecisionStrategydelegates here).scoring.py—DecisionScorer,ConfidenceScorer.ranking.py—RankingStrategy(ABC),WeightedScoreRanking.explanation.py—ExplanationBuilder,ExplanationStage.prioritization.py—ActionPrioritizer.root_cause.py—RootCauseAnalyzer(ABC, interface only — zero concrete subclasses).what_if.py—WhatIfEngine(ABC, interface only — zero concrete subclasses).planning.py—ActionPlanner.alerting.py—AlertGenerator.realtime.py—RealTimeDecisionSession.batch.py—BatchDecisionRunner.audit.py—DecisionAuditTrail,DecisionAuditEntry._registry.py—REGISTRY,register.exceptions.py— the package's exception hierarchy.README.md— this file.
Dependencies¶
Depends on: core, events, registry, kpis, analytics (currently exercised); ontology, plugins, connectors are permitted under the platform-wide layering rule but not yet exercised — connectors for the same reason as analytics (decision operates on already-computed KPIResult/AnalyticsResult objects, never a vendor-specific wire format), ontology/plugins because no concrete strategy needing entity-type scoping or explicit plugin-lifecycle wiring exists yet.
Depended on by: digital_twin, simulation, optimization, visualization, agents, cli
Future Work¶
decision is feature-complete per the Reference Implementation Blueprint's design spec §6 module list. Future work is limited to: a concrete RootCauseAnalyzer/WhatIfEngine plugin (first-party or third-party, per §31.2 — deliberately never shipped inside this package itself, §33), new Policy authoring (a governed, no-code-change extension, §31.4), and whatever digital_twin/simulation/optimization/agents/visualization need from this package as those packages move from architecture-complete to implemented (§36).
References¶
- Master Architecture Handbook v1.0
- Reference Implementation Blueprint v1.0