gold.decision_vector and gold.action_vector, mirrors them to
Lakebase Postgres, and the Solya app reads them there. This page covers the app side: how
those vectors are read, gated, displayed, attributed, and turned into action.
Read path — analytics schema + services
The gold tables are exposed as read-only Drizzle schemas undersrc/server/database/analytics/schema/gold/ (decision-vector.ts, action-vector.ts), with
column constants in src/constants/datasetColumns/gold/. Three services wrap them:
The
DecisionDomain constant, the scores JSONB keys, and the urgency thresholds live in
src/constants/decisionDistribution.ts — a single source of truth shared by the SQL
orchestrator and the UI helpers.
Urgency thresholds & heatmap
URGENCY_THRESHOLDS maps raw scores to “needs action” flags, chip colours, and heatmap tiers:
decisionDistribution rolls these up — e.g. shopsInRestockZone counts shops with
restock_urgency ≥ 0.5, and the brand summary surfaces a cross-domain urgentCount.
Score-driven workflows
WorkflowADD_ITEMS_TO_PLAN strategies route to the decision layer (src/types/workflows.ts):
scoreDriven(quantity / matching) — the data platform’s resolver reads the decision vector to set the quantity or to match rebalance shops. No app-side parameters.recommended(markdown) — decision-layer discount with three bounded knobs (fallbackPercent15,maxDiscountPct70,marginFloorPct0).
CREATE_TASKS — materializing the action vector into the inbox
TheCREATE_TASKS workflow action turns action_vector rows into PRODUCT_ACTION tasks,
scoped to the trigger’s matched (variantId, shopId) pairs:
domains— a non-empty subset of["restock", "rebalance", "markdown"].minConfidence— rows below this confidence are suppressed; rows with null confidence (e.g. restock) are always kept.
Confidence gating on read
getActionVectorsForItemsAction (alert-workspace rich tier, plan-review reference reco)
applies the org-global confidence threshold at read time: a row whose confidence is below the
threshold is returned with resolved: false, so the UI treats it as “no recommendation —
enter manually” rather than pre-filling a low-confidence value.
The plan-review hook usePlanReviewReferenceReco fetches action_vector rows (deduplicated,
capped at 200 pairs) only for lines that have no stored snapshot — so review screens can
show a reference recommendation even for manually-added lines.
Immutable per-item lineage
When an item is emitted into a plan from a recommendation, the strategy’sdecisionVectorSnapshot is captured at emit time and stored immutably on the plan item
(*_plan_items.decision_vector_snapshot, plus applied_rules). The shape is
PlanItemDecisionVectorSnapshot (src/types/planItemLineage.ts): capturedAt, strategyId /
strategyVersion, confidence, markdown-only markdownScore / agedStockFlag, and a
snapshot_date fallback. It is .passthrough() for forward-compatibility.
LineageBadge — recommended vs final
LineageBadge (src/components/shared/chips/LineageBadge.tsx) surfaces the difference between
what the strategy recommended and what was finally persisted (after OTB / budget / supplier
constraints). It renders nothing when there is no recommendation and no applied rules, or when
the recommendation equals the final value with no constraint deltas — otherwise it shows the
recommended value with a tooltip of the applied rules and strategy id.
Audit attribution
Every recommended item is attributed in the plan’s activity log. ADECISION_VECTOR
attribution carries a decisionVectorId linking back to the snapshot; MANUAL and
WORKFLOW_FALLBACK carry no snapshot reference (src/constants/planAuditLog.ts).
Source (app)
- Analytics schema:
src/server/database/analytics/schema/gold/{decision-vector.ts, action-vector.ts} - Services:
src/server/services/{decisionVectors, actionVectors, decisionDistribution}/ - Constants:
src/constants/decisionDistribution.ts,src/constants/taskConfidence.ts,src/constants/planAuditLog.ts - Lineage:
src/types/planItemLineage.ts,src/components/shared/chips/LineageBadge.tsx - Workflows:
src/types/workflows.ts

