risk

package
v2.8.2 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package risk provides pure risk-policy evaluation and related domain contracts. It performs no I/O and owns no broker or runtime state; callers supply typed observations and policies, and retain responsibility for state mutation, persistence, transport, and enforcement.

Evaluators preserve missing, stale, and unapproved inputs as explicit non-passing outcomes. Fingerprint helpers identify the complete normalized policy projections used by callers.

Index

Constants

View Source
const (
	CapitalTierOK         = "ok"
	CapitalTierWarn       = "warn"
	CapitalTierBlock      = "block"
	CapitalTierUnknown    = "unknown"
	CapitalTierUnapproved = "unapproved"
)

CapitalTierOK and the related constants are capital-evaluation outcomes. Missing observations and unapproved policy remain explicit non-OK tiers.

View Source
const (
	EnforcementShadow   = "shadow"
	EnforcementAdvisory = "advisory"
)

EnforcementShadow and EnforcementAdvisory are the enforcement classes a constitution control may declare. Validation rejects unsupported classes.

View Source
const (
	// DefaultReconcileWarningDays is the rolling reconcile warning horizon.
	DefaultReconcileWarningDays = 2
	// DefaultMonthlyPulseWorkingDay is the Nth working day of the month the
	// monthly pulse becomes due (Monday through Friday, weeks start Monday).
	DefaultMonthlyPulseWorkingDay = 1
	// DefaultMonthlyPulseAtLocal is the local wall time the pulse fires.
	DefaultMonthlyPulseAtLocal = "09:00"
)

Cadence defaults (operator-accepted 2026-08-03): every cadence key defaults in code so a policy file never needs the exact key phrases; an authored key is an override, never approval material.

View Source
const (
	NudgeKindReconcileDue       = "reconcile_due"
	NudgeKindReconcileException = "reconcile_exception"
	NudgeKindShadowWouldBlock   = "shadow_would_block"
	NudgeKindDrawdownLatched    = "drawdown_latched"
	NudgeKindPolicyDrift        = "policy_drift"
	NudgeKindConfirmedFlow      = "confirmed_flow"
	NudgeKindMonthlyPulse       = "monthly_pulse"

	NudgeStateDueSoon  = "due_soon"
	NudgeStateOverdue  = "overdue"
	NudgeStateOpen     = "open"
	NudgeStateObserved = "observed"
	NudgeStateDue      = "due"

	NudgeSeverityWatch = "watch"
	NudgeSeverityAct   = "act"

	NudgeDestinationMonitor = "monitor"
	NudgeDestinationAlerts  = "alerts"
	// NudgeDestinationBrief lands a process/governance nudge on the Brief tab,
	// where the reconcile clock, monthly pulse, and confirmed-flow context live.
	// Act-severity governance occurrences still land on Alerts.
	NudgeDestinationBrief = "brief"

	MonthlyPulseStatusNotDue    = "not_due"
	MonthlyPulseStatusDue       = "due"
	MonthlyPulseStatusCompleted = "completed"
	MonthlyPulseStatusBlocked   = "blocked"

	MonthlyPulseEvidenceRender = "render"
)

NudgeKindReconcileDue and the related constants define the closed nudge vocabulary accepted by CanonicalizeNudgeCandidate. Zero and unknown values are invalid.

View Source
const (
	RuleStatusPass         = "pass"
	RuleStatusInfo         = "info"
	RuleStatusWatch        = "watch"
	RuleStatusAct          = "act"
	RuleStatusUnknown      = "unknown"
	RuleStatusNotEvaluated = "not_evaluated"
)

RuleStatusPass and the related constants are rule-row outcomes. Missing, pending, or partial inputs cannot produce a false pass.

View Source
const (
	EarningsReasonTerminalNonReporting = "terminal_non_reporting"
	EarningsReasonBrokerNonIssuer      = "broker_nonissuer"
	EarningsReasonNonIssuerSecurity    = "nonissuer_security"
	EarningsReasonNotApplicable        = "earnings_not_applicable"
	RuleReasonOffSession               = "off_session"
	RuleReasonNoLongBook               = "no_long_book"
	RuleReasonPnLUnavailable           = "pnl_unavailable"
)

These are the closed, policy-owned reasons that can make one canonical Rulebook row not applicable. Alert recovery accepts no free-form or future reason without an explicit policy change.

View Source
const (
	RuleSingleNameExposure = "single_name_exposure"
	RuleOptionLinePremium  = "option_line_premium"
	RuleCashSellOnly       = "cash_sell_only"
	RuleExtrinsicBudget    = "extrinsic_budget"
	RuleExpiryRunway       = "expiry_runway"
	RuleCatalystCoverage   = "catalyst_coverage"
	RuleOverwriteEarnings  = "overwrite_earnings"
	RuleEarningsSizeFreeze = "earnings_size_freeze"
	RuleRedOnGreen         = "red_on_green"
	RuleWinnerTrim         = "winner_trim"
	RuleGreenDayAction     = "green_day_action"
	RuleHedgeIntegrity     = "hedge_integrity"
	RuleExitDiscipline     = "exit_discipline"
	RuleFXExposure         = "fx_exposure"
)

RuleSingleNameExposure and the related constants identify rules in stable display order.

View Source
const (
	UnderlyingSourceGreeksTick   = "greeks_tick"
	UnderlyingSourceStockLegMark = "stock_leg_mark"
)

UnderlyingSourceGreeksTick and UnderlyingSourceStockLegMark identify how a LegInput obtained its underlying price. The empty value has greeks-tick semantics for compatibility.

View Source
const (
	RegimeBucketCalm         = "calm"
	RegimeBucketEarlyWarning = "early_warning"
	RegimeBucketConfirmed    = "confirmed"
)

RegimeBucketCalm and the related constants are normalized regime buckets consumed by regime-conditional rules. The evaluator does not accept raw lifecycle stage names.

View Source
const (
	AlertCandidateSnapshotVersion = "alert-candidate-snapshot-v3"
)

AlertCandidateSnapshotVersion identifies the scope-bound source-neutral alert candidate wire contract. It does not approve routing or pageability.

View Source
const ConstitutionKind = "ibkr.risk_policy"

ConstitutionKind identifies the operator-authored risk constitution schema.

View Source
const MarketValueBaseSourceSubstituted = "substituted_unconverted"

MarketValueBaseSourceSubstituted marks a leg whose MarketValueBase is the raw contract-currency figure rather than a converted one, because no FX rate was available. The number is only meaningful when the leg's currency IS the base currency; otherwise it is wrong by the exchange rate, in whichever direction the pair happens to run. Every threshold that reads MarketValueBase must therefore treat such a leg as unmeasured rather than compare it, because an understating pair silences the comparison instead of failing it. The empty value means the figure was converted and may be compared.

View Source
const StressPolicyFingerprintVersion = "stress-policy-fp-v1"

StressPolicyFingerprintVersion labels fingerprints of the stress threshold policy and keeps that identity domain separate from the constitution.

Variables

This section is empty.

Functions

func BuildAlertAuthorityScope

func BuildAlertAuthorityScope(account, mode string) (string, error)

BuildAlertAuthorityScope binds private alert state to one normalized broker account/mode context without exposing either raw value. The canonicalization is intentionally part of the builder so case or surrounding whitespace cannot split one authority. Callers must still reject aggregate or unknown broker scopes before invoking it.

func BuildAlertEpisodeKey

func BuildAlertEpisodeKey(source AlertSource, kind AlertKind, identityParts ...string) (string, error)

BuildAlertEpisodeKey hashes a producer-approved semantic identity into an opaque stable key. identityParts may contain sensitive source identities; callers must not persist or log them. Only the returned key belongs on the alert contract. Part order is significant.

func BuildAlertOccurrenceKey

func BuildAlertOccurrenceKey(episodeKey string, identityParts ...string) (string, error)

BuildAlertOccurrenceKey hashes a daemon-authored occurrence identity for one EpisodeKey. The daemon decides when opening, re-arm, or a page-worthy escalation starts a new occurrence; this helper only makes that decision opaque and stable across transport. The identity parts must not be persisted or logged outside the owning runtime. Because both keys are opaque digests, candidate validation cannot reconstruct this relationship; producers must use this helper and persist the result.

func OptionExtrinsicPerShare

func OptionExtrinsicPerShare(right string, underlying *float64, strike, mark float64) (float64, bool)

OptionExtrinsicPerShare is mark minus intrinsic, floored at zero (a stale mark below intrinsic means the quote, not negative time value). ok=false when the underlying spot is unavailable or the mark is non-positive — callers must treat that as uncomputable, never as zero extrinsic.

func OptionIntrinsicPerShare

func OptionIntrinsicPerShare(right string, underlying, strike float64) float64

OptionIntrinsicPerShare is the per-share in-the-money amount; 0 for an out-of-the-money option or an unrecognized right.

func OptionSpreadPct

func OptionSpreadPct(bid, ask *float64) (float64, bool)

OptionSpreadPct is the bid/ask spread as a percentage of mid. Returns ok=false when either side is missing or the quote is crossed/locked.

func RulebookHedgeLeg

func RulebookHedgeLeg(l LegInput) bool

RulebookHedgeLeg exposes the policy-owned hedge classification to daemon composition without duplicating rule 12's predicate. Callers map their typed position row into LegInput and receive the exact classification used by rules 1, 2, 4, 5, 12, and 13.

func ValidateAlertAuthorityScope

func ValidateAlertAuthorityScope(value string) error

ValidateAlertAuthorityScope accepts only the opaque value produced by BuildAlertAuthorityScope. Raw account or mode values never belong in a candidate snapshot, daemon registry document, or app inbox.

func ValidateSizePlan

func ValidateSizePlan(in SizeInput) error

ValidateSizePlan checks the flag-level plan shape (side, prices, target, risk percent, lot, fx) without requiring account data. ComputeSize re-runs the full validation with NLV required; this exists so a runner can fail fast on bad input before paying an account-snapshot round-trip.

Types

type AlertCandidate

type AlertCandidate struct {
	EpisodeKey          string                `json:"episode_key"`
	OccurrenceKey       string                `json:"occurrence_key"`
	EvidenceFingerprint string                `json:"evidence_fingerprint"`
	Source              AlertSource           `json:"source"`
	Kind                AlertKind             `json:"kind"`
	PresentationCode    AlertPresentationCode `json:"presentation_code"`
	State               AlertEpisodeState     `json:"state"`
	Severity            AlertSeverity         `json:"severity"`
	EvidenceHealth      AlertEvidenceHealth   `json:"evidence_health"`
	Destination         AlertDestination      `json:"destination"`
	EvidenceAsOf        time.Time             `json:"evidence_as_of"`
	StateChangedAt      time.Time             `json:"state_changed_at"`
	ObservedAt          time.Time             `json:"observed_at"`
}

AlertCandidate contains classified, redacted semantics only. It deliberately has no display copy, source subject, account, symbol, order, route, display ID, target ID, device ID, or delivery-attempt ID.

EpisodeKey is stable for the same root problem. EvidenceFingerprint changes when classified supporting evidence changes. OccurrenceKey changes when the daemon opens/reopens the root problem or classifies an escalation as a new page-worthy occurrence; it stays stable for evidence-only revisions and the occurrence's recovery. App delivery records bind this private occurrence key and create their own per-target attempt IDs; they never infer re-arm, page-worthy escalation, or use a display ID as authority. StateChangedAt is the daemon's semantic transition time.

func (AlertCandidate) MarshalJSON

func (candidate AlertCandidate) MarshalJSON() ([]byte, error)

MarshalJSON validates candidate before encoding it.

func (*AlertCandidate) UnmarshalJSON

func (candidate *AlertCandidate) UnmarshalJSON(data []byte) error

UnmarshalJSON rejects unknown or missing fields and validates the decoded candidate before assigning it to the receiver.

func (AlertCandidate) Validate

func (candidate AlertCandidate) Validate() error

Validate checks the candidate's opaque identities, enum values, timestamps, and recovery coherence.

type AlertCandidateSnapshot

type AlertCandidateSnapshot struct {
	SchemaVersion  string                `json:"schema_version"`
	AuthorityScope string                `json:"authority_scope"`
	AsOf           time.Time             `json:"as_of"`
	CurrentState   AlertSnapshotState    `json:"current_state"`
	Coverage       AlertCoverage         `json:"coverage"`
	Sources        []AlertSourceCoverage `json:"sources"`
	Candidates     []AlertCandidate      `json:"candidates"`
}

AlertCandidateSnapshot is the versioned daemon-side measurement contract. CurrentState is validated from candidates and coverage: an empty result is Clear only with complete, current coverage; otherwise it is Unknown.

func (AlertCandidateSnapshot) IsClear

func (snapshot AlertCandidateSnapshot) IsClear() bool

IsClear reports a trustworthy clear only for a fully valid snapshot. It is intentionally false for empty snapshots with incomplete or stale coverage.

func (AlertCandidateSnapshot) MarshalJSON

func (snapshot AlertCandidateSnapshot) MarshalJSON() ([]byte, error)

MarshalJSON validates snapshot before encoding it.

func (*AlertCandidateSnapshot) UnmarshalJSON

func (snapshot *AlertCandidateSnapshot) UnmarshalJSON(data []byte) error

UnmarshalJSON rejects unknown or missing fields and validates the decoded snapshot before assigning it to the receiver.

func (AlertCandidateSnapshot) Validate

func (snapshot AlertCandidateSnapshot) Validate() error

Validate checks the complete snapshot contract and verifies that CurrentState is the state implied by its candidates and coverage.

type AlertCoverage

type AlertCoverage struct {
	State           AlertCoverageState     `json:"state"`
	Freshness       AlertCoverageFreshness `json:"freshness"`
	AsOf            time.Time              `json:"as_of"`
	ExpectedSources []AlertSource          `json:"expected_sources"`
	CoveredSources  []AlertSource          `json:"covered_sources"`
}

AlertCoverage makes the universe behind an empty candidate list explicit. CoveredSources must be a subset of ExpectedSources. Complete means the two sets are equal; unavailable means CoveredSources is empty.

func (AlertCoverage) MarshalJSON

func (coverage AlertCoverage) MarshalJSON() ([]byte, error)

MarshalJSON validates coverage before encoding it.

func (*AlertCoverage) UnmarshalJSON

func (coverage *AlertCoverage) UnmarshalJSON(data []byte) error

UnmarshalJSON rejects unknown or missing fields and validates the decoded coverage before assigning it to the receiver.

func (AlertCoverage) Validate

func (coverage AlertCoverage) Validate() error

Validate checks coverage set membership and the coherence of state and freshness. CoveredSources must be non-nil even when it is empty.

type AlertCoverageFreshness

type AlertCoverageFreshness string

AlertCoverageFreshness describes the timeliness of the covered sources. An unavailable source set must use AlertCoverageUnknown.

const (
	AlertCoverageCurrent AlertCoverageFreshness = "current"
	AlertCoverageStale   AlertCoverageFreshness = "stale"
	AlertCoverageUnknown AlertCoverageFreshness = "unknown"
)

AlertCoverageCurrent and the related constants classify coverage freshness.

type AlertCoverageState

type AlertCoverageState string

AlertCoverageState describes how much of the expected source set was evaluated. The zero value is invalid.

const (
	AlertCoverageComplete    AlertCoverageState = "complete"
	AlertCoveragePartial     AlertCoverageState = "partial"
	AlertCoverageUnavailable AlertCoverageState = "unavailable"
)

AlertCoverageComplete and the related constants classify expected-source coverage.

type AlertDestination

type AlertDestination string

AlertDestination names a redacted product surface, not a device or target. Per-target delivery identity belongs to the app delivery ledger.

const (
	AlertDestinationMonitor AlertDestination = "monitor"
	AlertDestinationAlerts  AlertDestination = "alerts"
	AlertDestinationBrief   AlertDestination = "brief"
)

AlertDestinationMonitor and the related constants name redacted product surfaces rather than delivery targets.

type AlertEpisodeState

type AlertEpisodeState string

AlertEpisodeState is the daemon producer's lifecycle state. The daemon owns dwell, escalation, recovery, and re-arm; the app only persists delivery and receipt state for the producer-authored occurrence. A new opening/reopen or daemon-qualified page-worthy escalation starts a new occurrence; evidence- only revisions and recovery do not.

const (
	AlertEpisodeOpen      AlertEpisodeState = "open"
	AlertEpisodeEscalated AlertEpisodeState = "escalated"
	AlertEpisodeRecovered AlertEpisodeState = "recovered"
)

AlertEpisodeOpen and the related constants describe a producer-owned episode transition.

type AlertEvidenceHealth

type AlertEvidenceHealth string

AlertEvidenceHealth describes whether a candidate's supporting observation is usable and current. The zero value is invalid.

const (
	AlertEvidenceCurrent     AlertEvidenceHealth = "current"
	AlertEvidencePartial     AlertEvidenceHealth = "partial"
	AlertEvidenceStale       AlertEvidenceHealth = "stale"
	AlertEvidenceUnavailable AlertEvidenceHealth = "unavailable"
	AlertEvidenceError       AlertEvidenceHealth = "error"
)

AlertEvidenceCurrent and the related constants classify the supporting evidence's usability.

type AlertKind

type AlertKind string

AlertKind is the redacted semantic class of an operator condition. Source and kind remain independent so adapters do not recreate producer policy.

const (
	AlertKindMarketState             AlertKind = "market_state"
	AlertKindPortfolioRisk           AlertKind = "portfolio_risk"
	AlertKindMarginSafety            AlertKind = "margin_safety"
	AlertKindDrawdown                AlertKind = "drawdown"
	AlertKindProtectionGap           AlertKind = "protection_gap"
	AlertKindOrderIntegrity          AlertKind = "order_integrity"
	AlertKindReconciliationException AlertKind = "reconciliation_exception"
	AlertKindGovernance              AlertKind = "governance"
	AlertKindPolicyDrift             AlertKind = "policy_drift"
	AlertKindDataHealth              AlertKind = "data_health"
	AlertKindDeliveryHealth          AlertKind = "delivery_health"
)

AlertKindMarketState and the related constants classify the root operator condition independently of its producer.

type AlertPresentationCode

type AlertPresentationCode string

AlertPresentationCode is a closed, redacted copy key. Adapters may map it to human text, but cannot receive or interpolate broker identifiers through it.

const (
	AlertPresentationPortfolioStress                  AlertPresentationCode = "portfolio_stress"
	AlertPresentationMarginCushion                    AlertPresentationCode = "margin_cushion"
	AlertPresentationRegimeMarketStress               AlertPresentationCode = "regime_market_stress"
	AlertPresentationRulebookSingleNameExposure       AlertPresentationCode = "rulebook_single_name_exposure"
	AlertPresentationRulebookOptionLinePremium        AlertPresentationCode = "rulebook_option_line_premium"
	AlertPresentationRulebookCashSellOnly             AlertPresentationCode = "rulebook_cash_sell_only"
	AlertPresentationRulebookExtrinsicBudget          AlertPresentationCode = "rulebook_extrinsic_budget"
	AlertPresentationRulebookExpiryRunway             AlertPresentationCode = "rulebook_expiry_runway"
	AlertPresentationRulebookCatalystCoverage         AlertPresentationCode = "rulebook_catalyst_coverage"
	AlertPresentationRulebookOverwriteEarnings        AlertPresentationCode = "rulebook_overwrite_earnings"
	AlertPresentationRulebookEarningsSizeFreeze       AlertPresentationCode = "rulebook_earnings_size_freeze"
	AlertPresentationRulebookRedOnGreen               AlertPresentationCode = "rulebook_red_on_green"
	AlertPresentationRulebookWinnerTrim               AlertPresentationCode = "rulebook_winner_trim"
	AlertPresentationRulebookGreenDayAction           AlertPresentationCode = "rulebook_green_day_action"
	AlertPresentationRulebookHedgeIntegrity           AlertPresentationCode = "rulebook_hedge_integrity"
	AlertPresentationRulebookExitDiscipline           AlertPresentationCode = "rulebook_exit_discipline"
	AlertPresentationRulebookFXExposure               AlertPresentationCode = "rulebook_fx_exposure"
	AlertPresentationProtectionOrphanedOrder          AlertPresentationCode = "protection_orphaned_order"
	AlertPresentationProtectionReconciliationRequired AlertPresentationCode = "protection_reconciliation_required"
	AlertPresentationOrderIntegrityMismatch           AlertPresentationCode = "order_integrity_mismatch"
	AlertPresentationDataHealthGateway                AlertPresentationCode = "data_health_gateway"
	AlertPresentationDataHealthStorage                AlertPresentationCode = "data_health_storage"
	AlertPresentationDataHealthProposals              AlertPresentationCode = "data_health_proposals"
	AlertPresentationDataHealthOpportunities          AlertPresentationCode = "data_health_opportunities"
	AlertPresentationDataHealthDataFarms              AlertPresentationCode = "data_health_data_farms"
	AlertPresentationDataHealthRegime                 AlertPresentationCode = "data_health_regime"
	AlertPresentationDataHealthGamma                  AlertPresentationCode = "data_health_gamma"
	AlertPresentationDataHealthQuality                AlertPresentationCode = "data_health_quality"
	AlertPresentationRiskPolicyLimitWouldBlock        AlertPresentationCode = "risk_policy_limit_would_block"
	AlertPresentationRiskPolicyDrawdownLatched        AlertPresentationCode = "risk_policy_drawdown_latched"
	AlertPresentationRiskPolicyDrift                  AlertPresentationCode = "risk_policy_drift"
	AlertPresentationReconciliationDue                AlertPresentationCode = "reconciliation_due"
	AlertPresentationReconciliationException          AlertPresentationCode = "reconciliation_exception"
	AlertPresentationReconciliationConfirmedFlow      AlertPresentationCode = "reconciliation_confirmed_flow"
	AlertPresentationGovernanceMonthlyPulse           AlertPresentationCode = "governance_monthly_pulse"
	AlertPresentationDeliveryHealth                   AlertPresentationCode = "delivery_health"
	AlertPresentationRulebookLegacyCondition          AlertPresentationCode = "rulebook_condition"
	AlertPresentationRiskPolicyLegacyCondition        AlertPresentationCode = "risk_policy_condition"
	AlertPresentationReconciliationLegacyCondition    AlertPresentationCode = "reconciliation_condition"
	AlertPresentationGovernanceLegacyCondition        AlertPresentationCode = "governance_condition"
)

Alert presentation codes cover every producer-owned candidate class. The generic condition codes exist only to preserve lifecycle identity while a version-2 registry is upgraded; the next producer observation replaces them with the precise code without opening a new occurrence.

type AlertSeverity

type AlertSeverity string

AlertSeverity expresses the producer-classified urgency of an alert candidate. The zero value is invalid.

const (
	AlertSeverityObserve AlertSeverity = "observe"
	AlertSeverityWatch   AlertSeverity = "watch"
	AlertSeverityAct     AlertSeverity = "act"
	AlertSeverityUrgent  AlertSeverity = "urgent"
)

AlertSeverityObserve and the related constants rank candidate urgency.

type AlertSnapshotState

type AlertSnapshotState string

AlertSnapshotState is the state derived from validated candidates and coverage. Clear requires complete, current coverage.

const (
	AlertSnapshotClear   AlertSnapshotState = "clear"
	AlertSnapshotActive  AlertSnapshotState = "active"
	AlertSnapshotUnknown AlertSnapshotState = "unknown"
)

AlertSnapshotClear and the related constants are derived snapshot states.

type AlertSource

type AlertSource string

AlertSource names the daemon authority that produced a candidate. These are product subsystem names, never broker, account, symbol, order, or device identifiers.

const (
	AlertSourceStress         AlertSource = "canary"
	AlertSourceRegime         AlertSource = "regime"
	AlertSourceRulebook       AlertSource = "rulebook"
	AlertSourceRiskPolicy     AlertSource = "risk_policy"
	AlertSourceProtection     AlertSource = "protection"
	AlertSourceOrderIntegrity AlertSource = "order_integrity"
	AlertSourceReconciliation AlertSource = "reconciliation"
	AlertSourceGovernance     AlertSource = "governance"
	AlertSourceDataHealth     AlertSource = "data_health"
	AlertSourceDelivery       AlertSource = "delivery"
)

AlertSourceStress and the related constants identify candidate-producing subsystems without carrying private subject identity.

AlertSourceStress keeps the wire value "canary" for the same reason stressEpisodeIdentity keeps "portfolio_canary": BuildAlertEpisodeKey hashes the source into the episode key, so changing this string produces a different key for the same condition with no mapping from the old one. The identity parts are raw account/mode values that no stored document carries, so no registry or ledger migration can recompute the new key from the old — every open portfolio-stress episode would be abandoned mid-flight and reopen as a fresh occurrence, re-paging the operator for an alert they already hold. The Go identifier is the name; this literal is a persisted identity.

type AlertSourceCoverage

type AlertSourceCoverage struct {
	Source         AlertSource         `json:"source"`
	Status         string              `json:"status"`
	Reason         string              `json:"reason"`
	EvidenceHealth AlertEvidenceHealth `json:"evidence_health"`
	InputAsOf      time.Time           `json:"input_as_of"`
	ObservedAt     time.Time           `json:"observed_at"`
	EvidenceAsOf   time.Time           `json:"evidence_as_of"`
	FreshUntil     time.Time           `json:"fresh_until"`
	Covered        bool                `json:"covered"`
}

AlertSourceCoverage names the health of one expected producer in the same snapshot as its candidates. Times are absent only before that producer has been observed in the current authority scope.

func (AlertSourceCoverage) MarshalJSON

func (source AlertSourceCoverage) MarshalJSON() ([]byte, error)

MarshalJSON validates source coverage before encoding it.

func (*AlertSourceCoverage) UnmarshalJSON

func (source *AlertSourceCoverage) UnmarshalJSON(data []byte) error

UnmarshalJSON rejects unknown or missing fields. Snapshot validation applies the final timestamp and aggregate-coverage coherence checks.

func (AlertSourceCoverage) Validate

func (source AlertSourceCoverage) Validate(snapshotAsOf time.Time) error

Validate checks one source row without interpreting producer-specific status or reason codes. Those codes remain bounded lowercase identifiers and cannot carry free text or private identity.

type CapitalObservation

type CapitalObservation struct {
	EquityBase float64
	AsOf       time.Time
}

CapitalObservation is one equity reading in base currency.

type CapitalRuntime

type CapitalRuntime struct {
	// AdjustedPeakBase is the peak of (equity − cumulative external flows).
	AdjustedPeakBase float64
	PeakAsOf         time.Time
	// CumExternalFlowsBase is the policy-version-selected cumulative flow
	// input: declared events through v2, statement truth plus bridges in v3.
	CumExternalFlowsBase float64
	// Seeded is false until the first equity observation establishes the
	// peak; an unseeded state evaluates unknown, never ok.
	Seeded bool
	// BlockLatched persists across restarts and mark recovery; only a
	// journaled human reset clears it.
	BlockLatched bool
	// LastReconciledAt is the last human or automatic reconcile evidence;
	// zero means never reconciled.
	LastReconciledAt time.Time
	// UnreconciledOverrideUntil is populated only from an active, unexpired
	// one-shot override on capital.max_unreconciled_days. No other override
	// control reaches evaluation.
	UnreconciledOverrideUntil time.Time
}

CapitalRuntime is the daemon-owned runtime state the evaluator consumes: the cash-flow-adjusted peak, effective cumulative external flows, the drawdown latch, and reconciliation recency. The daemon owns mutation; the evaluator only reads.

type CapitalVerdict

type CapitalVerdict struct {
	Tier string
	// EffectiveRiskCapitalBase = min(declared, equity − floor); nil when
	// unapproved inputs or no usable equity observation.
	EffectiveRiskCapitalBase *float64
	// DrawdownBase and ConsumedPct measure from the cash-flow-adjusted
	// peak; ConsumedPct is drawdown / declared risk capital × 100.
	DrawdownBase *float64
	ConsumedPct  *float64
	EquityStale  bool
	// ReconcileStale means the declared-events ledger is older than
	// capital.max_unreconciled_days (or never attested).
	ReconcileStale bool
	Unapproved     []string
	Reasons        []string
}

CapitalVerdict is the pure evaluation result.

func EvaluateCapital

func EvaluateCapital(c *Constitution, rt CapitalRuntime, obs *CapitalObservation, now time.Time) CapitalVerdict

EvaluateCapital applies the constitution to the runtime state and the latest observation. Invariants: absence of data or of approved numbers never yields ok; the latch dominates everything except unapproved disclosure; risk-reducing exemptions are the caller's concern (order classification lives on the preview path, not here).

type Constitution

type Constitution struct {
	Kind          string `toml:"kind" json:"kind"`
	SchemaVersion int    `toml:"schema_version" json:"schema_version"`
	PolicyID      string `toml:"policy_id" json:"policy_id"`
	PolicyVersion int    `toml:"policy_version" json:"policy_version"`

	Capital   ConstitutionCapital   `toml:"capital" json:"capital"`
	Drawdown  ConstitutionDrawdown  `toml:"drawdown" json:"drawdown"`
	Override  ConstitutionOverride  `toml:"override" json:"override"`
	Recon     ConstitutionRecon     `toml:"recon" json:"recon"`
	Cadence   ConstitutionCadence   `toml:"cadence" json:"cadence"`
	Inventory ConstitutionInventory `toml:"inventory" json:"inventory"`
}

Constitution is the typed operator-authored capital policy. Material limits are pointers: nil means unapproved, and validation never backfills them.

func (Constitution) EffectiveBlockEnforcement

func (c Constitution) EffectiveBlockEnforcement() string

EffectiveBlockEnforcement resolves the block tier's enforcement class; empty defaults to shadow — the fail-safe direction (observe and journal, never gate).

func (Constitution) FingerprintKey

func (c Constitution) FingerprintKey() string

FingerprintKey hashes an explicit JSON projection of the full policy (risk.Policy / protection-policy discipline — the rulebook's %.4f variant is the outlier, not the model). Absent material keys marshal as null and are part of the identity: an unapproved gap is policy state.

func (Constitution) UnapprovedKeys

func (c Constitution) UnapprovedKeys() []string

UnapprovedKeys lists the material keys the operator has not chosen yet. Order matches the explain view.

func (Constitution) Validate

func (c Constitution) Validate() error

Validate rejects a structurally unusable constitution. It never backfills material keys: a file that is valid but incomplete loads with unapproved gaps, which is the intended state until the operator writes each number.

type ConstitutionArtefact

type ConstitutionArtefact struct {
	Class string `toml:"class" json:"class,omitempty"`
}

ConstitutionArtefact declares one cadence artefact. An empty Class means the artefact is undeclared; validation accepts advisory as the only non-empty class.

type ConstitutionCadence

type ConstitutionCadence struct {
	Morning ConstitutionArtefact `toml:"morning" json:"morning"`
	EOD     ConstitutionArtefact `toml:"eod" json:"eod"`
	Weekly  ConstitutionArtefact `toml:"weekly" json:"weekly"`
	// Nudges and Monthly are policy-version-4-only. Pointers preserve the
	// distinction between an absent table and an explicitly authored one, so
	// old policies can reject the new keys and v4 can report missing material.
	Nudges  *ConstitutionNudgeCadence   `toml:"nudges" json:"nudges,omitempty"`
	Monthly *ConstitutionMonthlyCadence `toml:"monthly" json:"monthly,omitempty"`
}

ConstitutionCadence declares operating-cadence artefacts whose completion can be journaled. Artefact validation accepts only advisory declarations.

func (ConstitutionCadence) NudgeLocation added in v2.7.0

func (c ConstitutionCadence) NudgeLocation() (*time.Location, error)

NudgeLocation resolves the clock cadence-driven nudges run on: the machine's local timezone unless the policy authors an explicit override.

func (ConstitutionCadence) ResolvedMonthlyNudgeAtLocal added in v2.7.0

func (c ConstitutionCadence) ResolvedMonthlyNudgeAtLocal() string

ResolvedMonthlyNudgeAtLocal returns the authored override when present, else the code default.

func (ConstitutionCadence) ResolvedMonthlyWorkingDay added in v2.7.0

func (c ConstitutionCadence) ResolvedMonthlyWorkingDay() int

ResolvedMonthlyWorkingDay returns the authored override when present, else the code default.

func (ConstitutionCadence) ResolvedReconcileWarningDays added in v2.7.0

func (c ConstitutionCadence) ResolvedReconcileWarningDays() int

ResolvedReconcileWarningDays returns the authored override when present, else the code default.

type ConstitutionCapital

type ConstitutionCapital struct {
	BaseCurrency        string   `toml:"base_currency" json:"base_currency"`
	ProtectedFloor      *float64 `toml:"protected_floor" json:"protected_floor"`
	DeclaredRiskCapital *float64 `toml:"declared_risk_capital" json:"declared_risk_capital"`
	// MaxEquityAgeMinutes bounds trust in the last equity observation;
	// beyond it the evaluator marks the capital state stale and does not pass it.
	MaxEquityAgeMinutes *int `toml:"max_equity_age_minutes" json:"max_equity_age_minutes"`
	// MaxUnreconciledDays bounds trust in the declared capital-event ledger
	// between reconciliation evidence; expiry is reported as stale.
	MaxUnreconciledDays *int `toml:"max_unreconciled_days" json:"max_unreconciled_days"`
}

ConstitutionCapital anchors the capital authority: an internal protected equity floor and a declared (human-authorized) risk capital, both in the account base currency. Effective risk capital = min(declared_risk_capital, equity − protected_floor); nothing — deposits, profits, live events — raises the declared number without a fingerprinted policy revision.

type ConstitutionDrawdown

type ConstitutionDrawdown struct {
	WarnConsumedPct  *float64 `toml:"warn_consumed_pct" json:"warn_consumed_pct"`
	BlockConsumedPct *float64 `toml:"block_consumed_pct" json:"block_consumed_pct"`
	// BlockEnforcement is shadow (default when empty) or advisory in v1.
	BlockEnforcement string `toml:"block_enforcement" json:"block_enforcement"`
}

ConstitutionDrawdown is the two-tier response ladder. Both thresholds are percentages of declared risk capital consumed from the cash-flow-adjusted equity peak. Warn is advisory and self-clearing; block latches in daemon state and clears only through a journaled human reset that re-bases the peak.

type ConstitutionInventory

type ConstitutionInventory struct {
	Rulebook   *ConstitutionPolicyPin `toml:"rulebook" json:"rulebook,omitempty"`
	Protection *ConstitutionPolicyPin `toml:"protection" json:"protection,omitempty"`
	Stress     *ConstitutionPolicyPin `toml:"stress" json:"stress,omitempty"`
}

ConstitutionInventory pins the sibling policies by identity so the policy view can disclose drift between what the constitution was approved against and what is live. Pins are identity references, not threshold copies: the siblings stay authoritative for their own numbers.

type ConstitutionLimit

type ConstitutionLimit struct {
	Key         string `json:"key"`
	Value       string `json:"value"`
	Meaning     string `json:"meaning"`
	Source      string `json:"source"`      // file | default | unapproved
	Enforcement string `json:"enforcement"` // advisory | shadow | structural
}

ConstitutionLimit is one row of the generated human view (`canary policy show --explain`): a limit key, its effective value, what it means in plain English, where the value came from, and its enforcement class. Observation and override columns are overlaid by the daemon; this layer is pure policy so every surface renders identical meanings.

func ConstitutionLimits

func ConstitutionLimits(c *Constitution) []ConstitutionLimit

ConstitutionLimits renders every material limit and governance field of the constitution. A nil policy (no file) yields the same rows with every value unapproved, so the view never hides what is missing.

type ConstitutionMonthlyCadence

type ConstitutionMonthlyCadence struct {
	Class        *string `toml:"class" json:"class"`
	DayOfMonth   *int    `toml:"day_of_month" json:"day_of_month"`
	NudgeAtLocal *string `toml:"nudge_at_local" json:"nudge_at_local"`
}

ConstitutionMonthlyCadence declares the one standing monthly touchpoint. DayOfMonth is the Nth working day of the month — Monday through Friday, weeks starting Monday — limited to 1..20 so every month has the day.

type ConstitutionNudgeCadence

type ConstitutionNudgeCadence struct {
	Timezone             *string `toml:"timezone" json:"timezone"`
	ReconcileWarningDays *int    `toml:"reconcile_warning_days" json:"reconcile_warning_days"`
}

ConstitutionNudgeCadence carries optional overrides for cadence-driven nudges. Both fields default in code (operator decision 2026-08-03: the desk clock and warning horizon are operating cadence, not risk policy): an absent Timezone means the machine's local timezone, an absent ReconcileWarningDays means DefaultReconcileWarningDays.

type ConstitutionOverride

type ConstitutionOverride struct {
	MaxDurationHours *int `toml:"max_duration_hours" json:"max_duration_hours"`
}

ConstitutionOverride caps the one-shot exception mechanism: human-only, single named control, reason required, hard expiry. The mechanism itself (origin gating, journaling) is code-owned; only the lifetime cap is policy.

type ConstitutionPolicyPin

type ConstitutionPolicyPin struct {
	ID      string `toml:"id" json:"id"`
	Version string `toml:"version" json:"version"`
}

ConstitutionPolicyPin identifies one sibling policy version. Version is a string so integer-versioned (rulebook, protection) and string-versioned (stress) policies pin uniformly.

type ConstitutionRecon

type ConstitutionRecon struct {
	// A statement flow and a declared event match on amount when they
	// differ by at most max(amount_tolerance_pct% of the statement
	// amount, amount_tolerance_min in base currency).
	AmountTolerancePct *float64 `toml:"amount_tolerance_pct" json:"amount_tolerance_pct"`
	AmountToleranceMin *float64 `toml:"amount_tolerance_min" json:"amount_tolerance_min"`
	// DateWindowBusinessDays bounds how far apart the statement value
	// date and the declared effective date may sit (weekday count).
	DateWindowBusinessDays *int `toml:"date_window_business_days" json:"date_window_business_days"`
	// MaxReportAgeDays bounds how old the newest ingested statement may
	// be for a recon report to back a reconcile sign-off.
	MaxReportAgeDays *int `toml:"max_report_age_days" json:"max_report_age_days"`
	// MaxEquityDivergencePct bounds the absolute same-day difference between
	// broker statement equity and the runtime observation before v3 may
	// automatically accept a clean report as reconcile evidence.
	MaxEquityDivergencePct *float64 `toml:"max_equity_divergence_pct" json:"max_equity_divergence_pct"`
}

ConstitutionRecon sets what counts as a reconciliation exception when broker statement flows are matched against the declared capital-event ledger (internal-docs/design/post-trade-truth.md). These are policy, not plumbing: they decide which differences the operator must look at.

type EarningsInput

type EarningsInput struct {
	Known bool
	// NotApplicable marks fresh exact broker identity proving that this held
	// contract is a nonissuer security. It is independent from reviewed
	// terminal/non-reporting issuer evidence.
	NotApplicable bool
	// NonIssuerSecurity marks a holding whose security type has no issuer
	// earnings at all — an index, future, fund, or cash instrument. It rests on
	// the position's own security type rather than an exact broker proof, so it
	// is a weaker authority than NotApplicable and stays a separate field: a
	// reader must never mistake a typed classification for a proven contract.
	NonIssuerSecurity bool
	// TerminalNonReporting marks reviewed exact-contract evidence that no
	// future issuer earnings event applies. It is neither a known date nor an
	// unknown: rules 6-8 disclose an exemption for the relevant name.
	TerminalNonReporting bool
	Date                 time.Time // ET calendar date (midnight ET)
	TimeOfDay            string    // "amc" | "bmo" | "" (unspecified)
	Estimated            bool
	Stale                bool
	// SessionsUntil is the number of US equity sessions from today (ET) to
	// the earnings date inclusive, computed by the daemon via marketcal.
	// nil when unknown.
	SessionsUntil *int
	// Source is the daemon's closed provenance vocabulary. verified_terminal
	// means exact-contract authority was present; TerminalNonReporting is true
	// only when that authority is current, identity-matched, and conflict-free.
	Source string
	// Reason is a stable typed explanation for unknown/stale evidence. It is
	// disclosure only and never turns absence into a pass.
	Reason string
}

EarningsInput is the per-name earnings context mapped by the daemon.

type Evaluation

type Evaluation struct {
	Rows   []RuleRow
	Ranked []int
}

Evaluation is the pure result: rows in rulebook order plus the hardest-first ranking (indexes into Rows).

func EvaluateRulebook

func EvaluateRulebook(in RuleInputs, pol RulebookPolicy) Evaluation

EvaluateRulebook computes all 14 rules. It never returns fewer than 14 rows; degraded inputs degrade statuses, not row presence.

type LegInput

type LegInput struct {
	Desc       string // "NOW 20260717 C 130"
	Right      string // C | P
	Strike     float64
	Expiry     time.Time // ET calendar date
	DTE        int
	Quantity   float64 // signed contracts
	Multiplier float64
	Mark       float64
	Underlying *float64
	Delta      *float64
	// MarketValueBase is the signed base-currency mark value of the leg.
	MarketValueBase float64
	// MarketValueBaseSource discloses whether MarketValueBase was converted or
	// substituted: empty for a converted figure,
	// MarketValueBaseSourceSubstituted when no FX rate existed and the raw
	// contract-currency value stands in. Follows UnderlyingSource's shape.
	MarketValueBaseSource string
	// ExtrinsicBase is the base-currency extrinsic value for long legs;
	// nil when uncomputable (missing underlying or mark) — never zero it.
	ExtrinsicBase *float64
	// CostBasisBase is the base-currency premium paid for the leg (avg cost
	// is multiplier-inclusive on options — do not re-multiply); nil when the
	// gateway didn't deliver it.
	CostBasisBase *float64
	// FXToBase converts the leg's quote currency into base; nil when the FX
	// path is unknown (rule 1's lower bound then treats the leg as
	// unbounded).
	FXToBase *float64
	// UnderlyingSource discloses where Underlying came from: empty or
	// UnderlyingSourceGreeksTick for the per-leg model tick,
	// UnderlyingSourceStockLegMark for the same-name stock-leg join. Derived
	// spots support OTM-ness and extrinsic; they never classify hedge legs.
	UnderlyingSource string
	// HedgeListed marks the underlying as being on the policy hedge list.
	HedgeListed bool
}

LegInput is one option leg of a name.

type MonthlyPulseCompletion

type MonthlyPulseCompletion struct {
	Month             string
	PolicyFingerprint string
	// CompletedAt and Evidence are daemon-authored from paired brief render
	// evidence. Origin enforcement remains outside this pure evaluator.
	CompletedAt time.Time
	Evidence    string
}

MonthlyPulseCompletion carries daemon-authored evidence that the pulse for one policy fingerprint and local calendar month was completed. The pure evaluator validates the evidence fields but cannot establish their origin.

type MonthlyPulseEvaluation

type MonthlyPulseEvaluation struct {
	Status    string
	Month     string
	DueAt     time.Time
	Candidate *NudgeCandidate
}

MonthlyPulseEvaluation reports the local policy month, its resolved due instant, and an optional due candidate. Invalid or ambiguous schedules are blocked rather than assigned a fallback time.

func EvaluateMonthlyPulse

func EvaluateMonthlyPulse(input MonthlyPulseInput) MonthlyPulseEvaluation

EvaluateMonthlyPulse derives the monthly cadence state. Completion is accepted only for the current month and policy fingerprint at or after the unambiguous due instant.

type MonthlyPulseInput

type MonthlyPulseInput struct {
	Now               time.Time
	Cadence           ConstitutionCadence
	PolicyFingerprint string
	// PolicyEvidenceReady means current readable policy pins all match. Before
	// due it is ignored; from due onward false blocks both due and completion.
	PolicyEvidenceReady bool
	Completion          *MonthlyPulseCompletion
}

MonthlyPulseInput supplies the current instant, approved cadence, policy identity, evidence readiness, and optional completion evidence.

type NameInput

type NameInput struct {
	Symbol string
	// StockConID and StockSecType preserve the held underlying stock's broker
	// identity for exact-contract classifications. Zero means no stock leg or
	// no broker identity; symbol alone never activates such a classification.
	StockConID   int
	StockSecType string
	// UnderlyingSecType is the canonical security type of the held non-option
	// row for this name ("STOCK", "INDEX", "FUTURE", "FUND", ...). Unlike
	// StockSecType it is not narrowed to equities, because its job is to
	// recognize the types that have no issuer earnings. Empty for option-only
	// groups, which carry no such row and therefore no typed classification.
	UnderlyingSecType string
	// ExposureBase = stock + Σ delta×contracts×multiplier×spot, base ccy.
	ExposureBase float64
	// ExposureBaseComplete reports whether ExposureBase covers every leg the
	// aggregator saw (false when any priced leg was excluded: delta without
	// spot, markless stock, missing FX). Rule 1's lower bound refuses to
	// build on a partial sum — "proven ≥" must never overstate.
	ExposureBaseComplete bool
	// GreeksGapNotionalBase is |notional| of option legs missing delta —
	// exposure understatement risk.
	GreeksGapNotionalBase float64
	MarketValueBase       float64
	HasStockLeg           bool
	// StockDayChangePct is the stock leg's quote-enriched day change; nil
	// for option-only names or when enrichment failed.
	StockDayChangePct *float64
	Legs              []LegInput
}

NameInput is the per-underlying aggregation the daemon maps from PositionGroup/UnderlyingExposure. ExposureBase must be the same value the canary's concentration check reads.

type NudgeCandidate

type NudgeCandidate struct {
	Fingerprint string    `json:"fingerprint"`
	Kind        string    `json:"kind"`
	State       string    `json:"state"`
	Severity    string    `json:"severity"`
	Title       string    `json:"title"`
	Body        string    `json:"body"`
	OccurredAt  time.Time `json:"occurred_at,omitzero"`
	DueAt       time.Time `json:"due_at,omitzero"`
	ExpiresAt   time.Time `json:"expires_at,omitzero"`
	Destination string    `json:"destination"`
}

NudgeCandidate is the pure semantic result consumed by daemon adapters. It deliberately has no details, URL, raw source identity, money, symbol, account, or order fields. CanonicalizeNudgeCandidate replaces Title, Body, Severity, and Destination from the candidate's kind and state.

func CanonicalizeNudgeCandidate

func CanonicalizeNudgeCandidate(candidate NudgeCandidate) (NudgeCandidate, error)

CanonicalizeNudgeCandidate validates the narrow candidate contract and replaces all caller-authored display fields with approved template copy. It is pure so RPC and other adapters share the same semantic boundary.

func EvaluateConfirmedFlow

func EvaluateConfirmedFlow(statementRowIdentity string, occurredAt time.Time) *NudgeCandidate

EvaluateConfirmedFlow returns a candidate keyed by a normalized, non-empty statement-row identity. The identity is hashed and is not copied into the returned candidate.

func EvaluateDrawdownLatched

func EvaluateDrawdownLatched(latchEpisode string, open bool, occurredAt time.Time) *NudgeCandidate

EvaluateDrawdownLatched returns an open drawdown candidate for a non-empty latch episode. It returns nil when the latch is closed or unidentified.

func EvaluatePolicyDrift

func EvaluatePolicyDrift(mismatches []NudgePinMismatch, occurredAt time.Time) *NudgeCandidate

EvaluatePolicyDrift returns one order-independent candidate for valid policy identity mismatches. Equal or incomplete identities are ignored.

func EvaluateReconcileDue

func EvaluateReconcileDue(input ReconcileDueInput) *NudgeCandidate

EvaluateReconcileDue uses an exact rolling duration. Equality at the deadline remains due-soon; overdue begins only when Now.After(Deadline).

func EvaluateReconcileException

func EvaluateReconcileException(unresolved []ReconcileExceptionIdentity, occurredAt time.Time) *NudgeCandidate

EvaluateReconcileException returns one order-independent candidate for the valid unresolved identities. It returns nil when no usable identity remains.

type NudgePinMismatch

type NudgePinMismatch struct {
	Policy        string
	PinnedID      string
	PinnedVersion string
	LiveID        string
	LiveVersion   string
}

NudgePinMismatch compares one constitution pin with the corresponding live policy identity.

type PlannerMode

type PlannerMode string

PlannerMode identifies the action family a downstream planner may prepare. It conveys no broker-write authority.

const (
	PlannerModeNone        PlannerMode = "none"
	PlannerModeStage       PlannerMode = "stage"
	PlannerModeDefend      PlannerMode = "defend"
	PlannerModeRebalance   PlannerMode = "rebalance"
	PlannerModeDeploy      PlannerMode = "deploy"
	PlannerModeConfirmData PlannerMode = "confirm_data"
)

PlannerModeNone and the related constants enumerate planner action modes.

type PlannerReadiness

type PlannerReadiness string

PlannerReadiness describes how close a planner is to presenting an action. Ready still conveys no broker-write authority.

const (
	PlannerReadinessNone     PlannerReadiness = "none"
	PlannerReadinessWatch    PlannerReadiness = "watch"
	PlannerReadinessPrestage PlannerReadiness = "prestage"
	PlannerReadinessReady    PlannerReadiness = "ready"
	PlannerReadinessBlocked  PlannerReadiness = "blocked"
)

PlannerReadinessNone and the related constants enumerate preparation states.

type Policy

type Policy struct {
	Name    string `json:"name"`
	Profile string `json:"profile"`
	Version string `json:"version"`

	MarginUrgentPct float64 `json:"margin_urgent_pct"`
	MarginActPct    float64 `json:"margin_act_pct"`
	MarginWatchPct  float64 `json:"margin_watch_pct"`
	MarginTargetPct float64 `json:"margin_target_pct"`

	GrossExposureWatchPct float64 `json:"gross_exposure_watch_pct"`
	NetDeltaWatchPct      float64 `json:"net_delta_watch_pct"`
	GrossDeltaWatchPct    float64 `json:"gross_delta_watch_pct"`

	GrossExposureStressActPct float64 `json:"gross_exposure_stress_act_pct"`
	NetDeltaStressActPct      float64 `json:"net_delta_stress_act_pct"`
	GrossDeltaStressActPct    float64 `json:"gross_delta_stress_act_pct"`

	GrossExposureStressUrgentPct float64 `json:"gross_exposure_stress_urgent_pct"`
	NetDeltaStressUrgentPct      float64 `json:"net_delta_stress_urgent_pct"`
	GrossDeltaStressUrgentPct    float64 `json:"gross_delta_stress_urgent_pct"`

	SingleNameExposureWatchPct float64 `json:"single_name_exposure_watch_pct"`
	SingleNameDeltaWatchPct    float64 `json:"single_name_delta_watch_pct"`
	SingleNameTargetPct        float64 `json:"single_name_target_pct"`

	OptionGreeksMinCoveragePct float64 `json:"option_greeks_min_coverage_pct"`

	SPYDropPct      float64 `json:"spy_drop_pct"`
	SPYHardDropPct  float64 `json:"spy_hard_drop_pct"`
	SPYCrashPct     float64 `json:"spy_crash_pct"`
	SPYRallyPct     float64 `json:"spy_rally_pct"`
	SPYHardRallyPct float64 `json:"spy_hard_rally_pct"`

	VIXSpikePct     float64 `json:"vix_spike_pct"`
	VIXHardSpikePct float64 `json:"vix_hard_spike_pct"`
	VIXCrushPct     float64 `json:"vix_crush_pct"`
	VIXHardCrushPct float64 `json:"vix_hard_crush_pct"`

	DailyPnLWatchPct float64 `json:"daily_pnl_watch_pct"`
	DailyPnLActPct   float64 `json:"daily_pnl_act_pct"`

	HeldStressMaterialPct             float64 `json:"held_stress_material_pct"`
	HeldUnderlyingPnLWatchPct         float64 `json:"held_underlying_pnl_watch_pct"`
	HeldUnderlyingPnLActPct           float64 `json:"held_underlying_pnl_act_pct"`
	HeldOptionNearDTE                 int     `json:"held_option_near_dte"`
	HeldOptionDeltaWatchPct           float64 `json:"held_option_delta_watch_pct"`
	HeldOptionDeltaActPct             float64 `json:"held_option_delta_act_pct"`
	HeldLiquidityStockSpreadPct       float64 `json:"held_liquidity_stock_spread_pct"`
	HeldLiquidityOptionSpreadPctOfMid float64 `json:"held_liquidity_option_spread_pct_of_mid"`

	Reduce ReducePolicy `json:"reduce"`
}

Policy holds the shared stress thresholds used by live monitors and protection proposal policy.

func DefaultPolicy

func DefaultPolicy() Policy

DefaultPolicy returns the complete compiled stress policy.

func (Policy) FingerprintKey

func (p Policy) FingerprintKey() string

FingerprintKey returns a deterministic digest of the policy profile, version, and every threshold field. Name is represented through the PolicyProfile fallback and is otherwise not part of the digest.

func (Policy) PolicyProfile

func (p Policy) PolicyProfile() string

PolicyProfile returns Profile, falling back to Name for older policy values.

func (Policy) PolicyVersion

func (p Policy) PolicyVersion() string

PolicyVersion returns the policy's version label.

type PortfolioPosture

type PortfolioPosture string

PortfolioPosture summarizes the portfolio response implied by a set of signals. The zero value is unspecified.

const (
	PortfolioPostureNeutral           PortfolioPosture = "neutral"
	PortfolioPostureThreat            PortfolioPosture = "threat"
	PortfolioPostureRebalance         PortfolioPosture = "rebalance"
	PortfolioPostureOpportunity       PortfolioPosture = "opportunity"
	PortfolioPostureThreatOpportunity PortfolioPosture = "threat_opportunity"
	PortfolioPostureConfirmData       PortfolioPosture = "confirm_data"
)

PortfolioPostureNeutral and the related constants enumerate portfolio response summaries.

type ReconcileDueInput

type ReconcileDueInput struct {
	Now         time.Time
	Deadline    time.Time
	WarningDays *int
}

ReconcileDueInput supplies the current instant, reconciliation deadline, and approved warning horizon. A nil WarningDays leaves the evaluation inactive.

type ReconcileExceptionIdentity

type ReconcileExceptionIdentity struct {
	Kind     string
	Identity string
	Material []string
}

ReconcileExceptionIdentity contains only the identity/material fields the daemon has already allowlisted for semantic dedupe. They are normalized and hashed; none is copied into the candidate.

type ReducePolicy

type ReducePolicy struct {
	FrontDTE                int     `json:"front_dte"`
	MidDTE                  int     `json:"mid_dte"`
	HedgeOffsetMinPct       float64 `json:"hedge_offset_min_pct"`
	HedgeOffsetMaxPct       float64 `json:"hedge_offset_max_pct"`
	MaxOptionSpreadAbs      float64 `json:"max_option_spread_abs"`
	MaxOptionSpreadPctOfMid float64 `json:"max_option_spread_pct_of_mid"`
	OrderType               string  `json:"order_type"`
	TIF                     string  `json:"tif"`
	AllowMarketOrders       bool    `json:"allow_market_orders"`
}

ReducePolicy contains the option-selection and order-shape constraints used when constructing risk-reduction proposals. It does not authorize an order.

type RegimeThresholds

type RegimeThresholds struct {
	CashSellOnlyPct   float64 `toml:"cash_sell_only_pct" json:"cash_sell_only_pct"`
	ExtrinsicWatchPct float64 `toml:"extrinsic_watch_pct" json:"extrinsic_watch_pct"`
	ExtrinsicActPct   float64 `toml:"extrinsic_act_pct" json:"extrinsic_act_pct"`
	HedgeBandMinPct   float64 `toml:"hedge_band_min_pct" json:"hedge_band_min_pct"`
	HedgeBandMaxPct   float64 `toml:"hedge_band_max_pct" json:"hedge_band_max_pct"`
}

RegimeThresholds is one stage's threshold set for the regime-conditional rules: rule 3 cash floor, rule 4 extrinsic budget (ex-hedge), rule 12 hedge band.

type RuleInputs

type RuleInputs struct {
	AsOf         time.Time
	BaseCurrency string

	Positions SourceState
	Account   SourceState

	NLVBase      *float64
	CashBase     *float64
	DailyPnLBase *float64

	Names []NameInput

	// SessionOpen: US equity regular session per marketcal.
	SessionOpen bool
	// SPYDayChangePct is the market tape for rule 9; nil when unavailable.
	SPYDayChangePct *float64

	Earnings map[string]EarningsInput

	// RegimeStage is the bucketed regime lifecycle stage (RegimeBucket*);
	// empty when no stage has ever been observed. RegimeStageCarried marks a
	// stage older than the policy max age or restored from the persisted
	// store — carried stages evaluate worse-of(carried set, calm set).
	RegimeStage        string
	RegimeStageAsOf    time.Time
	RegimeStageCarried bool

	// NonBaseNLVBase is the base-currency net liquidation held in non-base
	// currencies (rule 14). nil = unavailable (absent currency report,
	// missing FX) — never zero it: an empty currency report on a book with
	// non-base legs is a data gap, not a base-only book.
	NonBaseNLVBase *float64
	// NonBaseCurrencies names the currencies behind NonBaseNLVBase.
	NonBaseCurrencies []string
}

RuleInputs is the full mapped snapshot for one evaluation.

type RuleOffender

type RuleOffender struct {
	Symbol     string  `json:"symbol"`
	Leg        string  `json:"leg,omitempty"`
	Observed   float64 `json:"observed"`
	ImpactBase float64 `json:"impact_base,omitempty"`
	Note       string  `json:"note,omitempty"`
}

RuleOffender is one name or leg contributing to a breach, worst first.

type RuleRow

type RuleRow struct {
	ID         string         `json:"id"`
	Number     int            `json:"number"`
	Title      string         `json:"title"`
	Status     string         `json:"status"`
	Observed   *float64       `json:"observed,omitempty"`
	Threshold  *float64       `json:"threshold,omitempty"`
	Unit       string         `json:"unit,omitempty"`
	Evidence   string         `json:"evidence"`
	Reason     string         `json:"reason,omitempty"`
	Offenders  []RuleOffender `json:"offenders,omitempty"`
	Exempt     []RuleOffender `json:"exempt,omitempty"`
	ImpactBase float64        `json:"impact_base,omitempty"`
	Notes      []string       `json:"notes,omitempty"`
	// ObservedIsLowerBound marks Observed as a provable minimum computed
	// from partial inputs ("≥ X%"), not an exact measurement. Only breaches
	// may carry it — a lower bound can indict, never acquit.
	ObservedIsLowerBound bool `json:"observed_is_lower_bound,omitempty"`
}

RuleRow is one rule's verdict.

type RulebookPolicy

type RulebookPolicy struct {
	ID      string `toml:"id" json:"id"`
	Version int    `toml:"version" json:"version"`

	// Rule 1 — single_name_exposure (% of NLV, delta-dollar exposure).
	SingleNameWatchPct float64 `toml:"single_name_watch_pct" json:"single_name_watch_pct"`
	SingleNameActPct   float64 `toml:"single_name_act_pct" json:"single_name_act_pct"`

	// Rule 2 — option_line_premium (% of NLV, long option line market value).
	// Hedge-classified legs (rule12HedgeLeg) evaluate against the hedge tier;
	// rule 12 owns hedge sizing, this tier only bounds premium at risk.
	OptionLineWatchPct float64 `toml:"option_line_watch_pct" json:"option_line_watch_pct"`
	OptionLineActPct   float64 `toml:"option_line_act_pct" json:"option_line_act_pct"`
	HedgeLineWatchPct  float64 `toml:"hedge_line_watch_pct" json:"hedge_line_watch_pct"`
	HedgeLineActPct    float64 `toml:"hedge_line_act_pct" json:"hedge_line_act_pct"`

	// Rule 5 — expiry_runway (calendar DTE bounds for long options).
	RunwayWatchDTE      int     `toml:"runway_watch_dte" json:"runway_watch_dte"`
	RunwayActDTE        int     `toml:"runway_act_dte" json:"runway_act_dte"`
	RunwayITMDeltaFloor float64 `toml:"runway_itm_delta_floor" json:"runway_itm_delta_floor"`

	// Rule 7 — overwrite_earnings short-put act tier: a spanning short put
	// escalates from watch to act when its assignment notional reaches the
	// line share of NLV, or a name's spanning short puts together reach the
	// name share.
	ShortPutActLinePctNLV float64 `toml:"short_put_act_line_pct_nlv" json:"short_put_act_line_pct_nlv"`
	ShortPutActNamePctNLV float64 `toml:"short_put_act_name_pct_nlv" json:"short_put_act_name_pct_nlv"`

	// Rule 8 — earnings_size_freeze (US sessions to earnings).
	EarningsFreezeSessions int `toml:"earnings_freeze_sessions" json:"earnings_freeze_sessions"`

	// Rules 9/10 — tape thresholds (day-change %).
	RedOnGreenNameDropPct float64 `toml:"red_on_green_name_drop_pct" json:"red_on_green_name_drop_pct"`
	RedOnGreenSPYUpPct    float64 `toml:"red_on_green_spy_up_pct" json:"red_on_green_spy_up_pct"`
	WinnerTrimDayUpPct    float64 `toml:"winner_trim_day_up_pct" json:"winner_trim_day_up_pct"`
	WinnerTrimMinExpoPct  float64 `toml:"winner_trim_min_exposure_pct" json:"winner_trim_min_exposure_pct"`

	// Rules 3/4/12 — regime-conditional threshold sets. A fresh regime stage
	// selects its set; a carried or never-seen stage evaluates the carried set
	// AND the calm set
	// and keeps the worse verdict, so stale regime data can hold or tighten
	// a verdict but never relax it.
	RegimeCalm         RegimeThresholds `toml:"regime_calm" json:"regime_calm"`
	RegimeEarlyWarning RegimeThresholds `toml:"regime_early_warning" json:"regime_early_warning"`
	RegimeConfirmed    RegimeThresholds `toml:"regime_confirmed" json:"regime_confirmed"`
	// RegimeStageMaxAgeMinutes bounds trust in the latched regime stage;
	// older stages evaluate as carried (worse-of semantics above).
	RegimeStageMaxAgeMinutes int `toml:"regime_stage_max_age_minutes" json:"regime_stage_max_age_minutes"`

	// Rule 13 — exit_discipline (% of premium paid lost on a long line).
	ExitWatchLossPct float64 `toml:"exit_watch_loss_pct" json:"exit_watch_loss_pct"`
	ExitActLossPct   float64 `toml:"exit_act_loss_pct" json:"exit_act_loss_pct"`

	// Rule 14 — fx_exposure (% of NLV held in non-base currencies). This is a
	// watch-only structural condition.
	FXExposureWatchPct float64 `toml:"fx_exposure_watch_pct" json:"fx_exposure_watch_pct"`

	// HedgeSymbols is the policy-owned index list whose long puts classify
	// as hedges (rules 1, 2, 5, 12, 13). Uppercased on load.
	HedgeSymbols []string `toml:"hedge_symbols" json:"hedge_symbols"`

	// GreeksGapFloorPctNLV is the materiality floor: a name whose legs
	// missing delta exceed this notional share of NLV renders its
	// exposure-dependent rows unknown instead of silently understating.
	GreeksGapFloorPctNLV float64 `toml:"greeks_gap_floor_pct_nlv" json:"greeks_gap_floor_pct_nlv"`

	// EarningsStaleDays bounds trust in a fetched earnings date; older
	// observations flip rules 6-8 to unknown until refreshed or overridden.
	EarningsStaleDays int `toml:"earnings_stale_days" json:"earnings_stale_days"`
}

RulebookPolicy carries the compiled thresholds for the daily trading rulebook. The TOML tags reserve the planned operator policy loader; no such loader is shipped today. It owns rulebook verdict thresholds, not the source observations that callers map into RuleInputs.

func DefaultRulebookPolicy

func DefaultRulebookPolicy() RulebookPolicy

DefaultRulebookPolicy returns a complete baseline policy.

func (RulebookPolicy) FingerprintKey

func (p RulebookPolicy) FingerprintKey() string

FingerprintKey hashes the full policy so every result discloses exactly which thresholds produced it (mirrors risk.Policy.FingerprintKey). Every field must appear here: a threshold outside the fingerprint is a silent policy change.

func (RulebookPolicy) IsHedgeSymbol

func (p RulebookPolicy) IsHedgeSymbol(sym string) bool

IsHedgeSymbol reports whether sym is on the policy hedge list.

func (*RulebookPolicy) Normalize

func (p *RulebookPolicy) Normalize()

Normalize uppercases and sorts the hedge list so fingerprints are stable regardless of TOML ordering.

func (RulebookPolicy) SetForBucket

func (p RulebookPolicy) SetForBucket(bucket string) RegimeThresholds

SetForBucket returns the threshold set for a regime bucket; unrecognized buckets fall to the early-warning set (middle, disclosed by the caller), never silently to calm.

type ShadowWouldBlockEvaluation

type ShadowWouldBlockEvaluation struct {
	Candidate *NudgeCandidate
	Count     int
}

ShadowWouldBlockEvaluation carries the updated episode count and, only for the first qualifying preview, its candidate.

func EvaluateShadowWouldBlock

func EvaluateShadowWouldBlock(input ShadowWouldBlockInput) ShadowWouldBlockEvaluation

EvaluateShadowWouldBlock emits one candidate for the first qualifying preview in a policy/latch episode. Later qualifying previews increment the episode count without repeating the candidate.

type ShadowWouldBlockInput

type ShadowWouldBlockInput struct {
	PolicyFingerprint string
	LatchEpisode      string
	RiskIncreasing    bool
	Exempt            bool
	WouldBlock        bool
	PriorCount        int
	OccurredAt        time.Time
}

ShadowWouldBlockInput describes one risk-increasing preview against a stable policy and latch episode. PriorCount is the previously persisted episode count and negative values are treated as zero.

type Signal

type Signal struct {
	ID               SignalID         `json:"id"`
	Direction        SignalDirection  `json:"direction"`
	Posture          PortfolioPosture `json:"posture,omitempty"`
	Severity         SignalSeverity   `json:"severity"`
	Subject          string           `json:"subject,omitempty"`
	Metric           string           `json:"metric,omitempty"`
	Observed         *float64         `json:"observed,omitempty"`
	Threshold        *float64         `json:"threshold,omitempty"`
	Target           *float64         `json:"target,omitempty"`
	Unit             string           `json:"unit,omitempty"`
	Evidence         string           `json:"evidence,omitempty"`
	Confidence       string           `json:"confidence,omitempty"`
	ConfidenceImpact string           `json:"confidence_impact,omitempty"`
	BlockedBy        []string         `json:"blocked_by,omitempty"`
}

Signal is a typed, serializable risk observation. Optional numeric fields remain nil when unavailable; callers must not interpret their absence as zero. BlockedBy explains which missing or degraded inputs limited the signal.

type SignalDirection

type SignalDirection string

SignalDirection describes whether a signal supports defense, deployment, rebalancing, mixed action, or data-quality confirmation.

const (
	DirectionDefensive    SignalDirection = "defensive"
	DirectionConstructive SignalDirection = "constructive"
	DirectionRebalance    SignalDirection = "rebalance"
	DirectionMixed        SignalDirection = "mixed"
	DirectionDataQuality  SignalDirection = "data_quality"
)

DirectionDefensive and the related constants enumerate signal directions.

type SignalID

type SignalID string

SignalID identifies a stable risk or data-quality condition.

const (
	SignalMarginCushionLow              SignalID = "margin_cushion_low"
	SignalLookAheadCushionLow           SignalID = "lookahead_cushion_low"
	SignalMarketSelloffViolent          SignalID = "market_selloff_violent"
	SignalVolSpikeConfirmed             SignalID = "vol_spike_confirmed"
	SignalMarketRallyViolent            SignalID = "market_rally_violent"
	SignalVolCrushConfirmed             SignalID = "vol_crush_confirmed"
	SignalRegimeStressConfirmed         SignalID = "regime_stress_confirmed"
	SignalRegimeStressEarly             SignalID = "regime_stress_early"
	SignalFXCarryUnwind                 SignalID = "fx_carry_unwind"
	SignalGammaRed                      SignalID = "gamma_red"
	SignalGrossExposureHigh             SignalID = "gross_exposure_high"
	SignalNetDeltaHigh                  SignalID = "net_delta_high"
	SignalGrossDeltaHigh                SignalID = "gross_delta_high"
	SignalSingleNameExposureHigh        SignalID = "single_name_exposure_high"
	SignalSingleNameDeltaHigh           SignalID = "single_name_delta_high"
	SignalHeldUnderlyingPnLShock        SignalID = "held_underlying_pnl_shock"
	SignalHeldOptionExpiryConcentration SignalID = "held_option_expiry_concentration"
	SignalHeldLiquidityDegraded         SignalID = "held_liquidity_degraded"
	SignalOptionGreeksDegraded          SignalID = "option_greeks_degraded"
	SignalShortConvexityHigh            SignalID = "short_convexity_high"
	SignalPortfolioPnLShock             SignalID = "portfolio_pnl_shock"
	SignalRiskDataDegraded              SignalID = "risk_data_degraded"
	SignalMarketDataStale               SignalID = "market_data_stale"
)

SignalMarginCushionLow and the related constants identify supported risk and data-quality conditions.

type SignalSeverity

type SignalSeverity string

SignalSeverity ranks the urgency of a risk signal. The zero value is unspecified.

const (
	SeverityObserve SignalSeverity = "observe"
	SeverityWatch   SignalSeverity = "watch"
	SeverityAct     SignalSeverity = "act"
	SeverityUrgent  SignalSeverity = "urgent"
)

SeverityObserve and the related constants enumerate signal urgency.

type SizeInput

type SizeInput struct {
	Symbol      string
	Side        string  // "long" | "short"
	Entry       float64 // quote currency
	Stop        float64 // quote currency
	Target      float64 // optional take-profit; 0 disables the R block
	RiskPct     float64 // percent of NLV; (0, 100]
	Lot         int     // round shares down to this multiple; >= 1
	FX          float64 // quote-currency units per 1 base-currency unit; > 0
	NLV         float64 // base currency
	BuyingPower float64 // base currency (0 disables BP check)
	Currency    string  // base currency code, surfaced in output only
}

SizeInput is the validated input to ComputeSize. Fields mirror the CLI flags one-for-one so the pure function is testable without the runner.

Target is optional. When set, ComputeSize derives the R-multiple (reward-to-risk ratio = profit-to-stop distance / entry-to-stop distance) and the breakeven win rate. Long trades require target > entry; short trades require target < entry.

type SizeResult

type SizeResult struct {
	Symbol           string   `json:"symbol"`
	Side             string   `json:"side"`
	Entry            float64  `json:"entry"`
	Stop             float64  `json:"stop"`
	Target           *float64 `json:"target,omitempty"`
	RiskPct          float64  `json:"risk_pct"`
	Lot              int      `json:"lot"`
	FX               float64  `json:"fx"`
	NLV              float64  `json:"nlv"`
	BaseCurrency     string   `json:"base_currency,omitempty"`
	RiskBase         float64  `json:"risk_base"`  // NLV * pct/100
	RiskQuote        float64  `json:"risk_quote"` // RiskBase * fx
	PerShareRisk     float64  `json:"per_share_risk"`
	Shares           int      `json:"shares"`
	Notional         float64  `json:"notional"`    // shares * entry
	MaxLoss          float64  `json:"max_loss"`    // shares * per_share_risk (quote ccy)
	R                *float64 `json:"r,omitempty"` // (|target-entry|) / (|entry-stop|)
	RewardQuote      *float64 `json:"reward_quote,omitempty"`
	RewardBase       *float64 `json:"reward_base,omitempty"`
	BreakevenWinRate *float64 `json:"breakeven_win_rate,omitempty"` // 1 / (1+R), fraction
	Status           string   `json:"status"`                       // "ok" | "tight_risk" | "exceeds_buying_power"
}

SizeResult is the wire shape of `canary size --json` and the input to the CLI text renderer.

Target / R / RewardQuote / RewardBase / BreakevenWinRate are populated only when the input carries a non-zero Target. R is the reward-to-risk ratio (|target − entry| / |entry − stop|). BreakevenWinRate is 1 / (1 + R).

func ComputeSize

func ComputeSize(in SizeInput) (SizeResult, error)

ComputeSize validates and applies fixed-fractional sizing. It returns a result with zero shares and status tight_risk when the risk budget is below one lot; buying power excess is reported in Status rather than as an error.

type SourceState

type SourceState struct {
	Healthy bool
	Reason  string // positions_pending, account_unavailable, …
}

SourceState is the mapped health of one input source.

type UnreconciledClock

type UnreconciledClock struct {
	Approved      bool
	Deadline      time.Time
	DaysRemaining *int
	Stale         bool
}

UnreconciledClock is the shared pure projection of the constitution's unreconciled horizon. Approved is false when the operator has not declared capital.max_unreconciled_days. A zero LastReconciledAt is stale with no fabricated year-one deadline.

func EvaluateUnreconciledClock

func EvaluateUnreconciledClock(maxDays *int, lastReconciledAt, overrideUntil, now time.Time) UnreconciledClock

EvaluateUnreconciledClock computes the deadline used by both capital evaluation and reporting. The one-shot outage override may only extend the ordinary deadline; it can never shorten it.

Jump to

Keyboard shortcuts

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