A business owner's account of using AI agents to investigate real sales history, test machine-learning models and decide what was useful enough to build into BizOps (Authored with Codex).
I wanted my business application to help me look forward.
BizOps could already show me what had happened. We had financial plans, sales history, product information and operational reporting. We had an AI chat interface. My next question seemed reasonable: could we use that history to learn how customers behave, forecast the next financial year and let me test different futures before discussing them with the CEO and CFO?
I wanted to know which customers were likely to buy again, which were declining, what they might buy and where our next growth opportunity could come from. I also wanted to move sliders and explore a major customer cutting expenditure, a contract ending or a region recovering. Eventually, I wanted to understand the conditions under which the business would become vulnerable.
That became a substantial research exercise with Codex. It also changed how I think about commissioning data science. The agent could inspect a codebase, research methods, write the data adapters, train models, build benchmarks, investigate failures and produce working local reports. My contribution was to keep bringing the work back to the business question, challenge conclusions and supply better source data.
The journey included premature recommendations, disappointing models and moments when I had to tell the agent to stop and rethink. Those parts explain the result as much as the models we eventually kept.
Our business operates in traffic infrastructure and equipment, with substantial public-sector and municipal exposure. Purchasing is shaped by projects, tenders, maintenance programmes, budgets and the timing of expenditure. Customers can buy in bursts and then go quiet. Some return after long gaps. Product demand reflects installed equipment and replacement cycles as well as new projects. The financial-year push matters.
A quiet period has several possible meanings. A customer may have enough stock, be waiting for funding, have delayed a project or have moved to another supplier. Sales history can reveal patterns associated with those possibilities. It cannot directly tell us which explanation is true. A billing record also tells us something different from an order, a tender award or a signed renewal.
We considered a wider set of inputs: tender history, contracts, production metrics, engineering projects and public evidence such as Auditor-General findings on municipal financial health. Those could become useful context. I wanted to prove what our sales history could tell us first. Current contract knowledge could not be slipped into an old forecast as though the model had inferred it. The completed experiments used sales-derived history; the wider market-research layer remains future work.
That domain context mattered throughout. A method that performs well on frequent supermarket purchases does not automatically become the best method for irregular municipal equipment sales. Much of my role was explaining why a technically plausible answer still needed another look.
Codex initially suggested CatBoost. I challenged it: how had it arrived at that recommendation, and had it actually researched suitable methods for this problem? CatBoost's handling of categorical information made it a plausible candidate. That was a starting hypothesis, with much more work needed before calling it the right choice. The CatBoost paper explains the algorithm's techniques; it does not settle a forecasting decision for my business.
I asked Codex to consult Claude through our collaboration skill. Codex led the investigation and implementation; Claude provided independent, read-only challenges to the design and source code. Their exchanges addressed the target, credits, customer and product granularity, historical availability of inputs and validation. Agreement between agents was a design checkpoint. Actual predictions still had to face actual outcomes.
The recommendation changed to a strongly regularised, pooled LightGBM starting model. “Pooled” meant learning across customer histories instead of building a separate complex model for each sparse customer. The plan used past sales, recency and calendar information to predict future monthly signed revenue, including credits. The LightGBM research, forecasting literature and published business benchmarks provided reasons to try that family. None established a universal winner for municipal sales.
CatBoost remained an early recommendation. LightGBM was the boosted implementation we actually tested. That distinction is easy to lose when a long conversation gets compressed into “we tried AI.”
We began with the data already available through BizOps and its local Cosmos environment. It covered the recent financial years and connected naturally to the application. I expected Codex to use its existing knowledge of the platform and inspect the documentation and data rather than ask me to describe everything again. That expectation was reasonable: access to the repository should make an agent a better collaborator.
The first models did not deliver the customer spending forecasts I wanted. We revised features, regularisation and the way annual and monthly targets were represented. Some experiments searched a small, declared set of settings on earlier development years; later ones tested a fixed recipe. Throughout, simple historical references remained in the comparison. Repeating last year's pattern or using a recent run rate is a meaningful competitor when a learned model is supposed to improve a business decision.
We then investigated Chronos-2, a pretrained time-series model. A useful way to think about it is that the model arrives with patterns learned from other time series and conditions its predictions on the history supplied to it. Our initial zero-shot experiments used those pretrained weights locally; they did not train a new foundation model from scratch. The checkpoint itself postdated the historical forecast origins, so these were retrospective method comparisons, not a reconstruction of a model available then.
There was also a separate, genuine local fine-tuning experiment using LoRA adapters. These train a relatively small set of additional parameters while retaining the pretrained base. Adaptation improved the matched model's starting performance in several comparisons. It still failed our business forecasting requirements. Lower training loss and improvement over an earlier neural result were insufficient reasons to replace a stronger simple reference.
Other experiments explored seasonal smoothing, methods for intermittent demand, annual tree models, quantile regression and separate activity-and-amount models. Those represented different hypotheses: perhaps we were asking a monthly model to solve an annual spending problem; perhaps the occurrence of a purchase and its size needed separate treatment; perhaps credits required an explicit component. The experiments gave us evidence about those questions, including evidence that several plausible approaches were inadequate.
At one point I became frustrated. I could see work continuing, but I could not see clearly enough what each attempt was testing or whether we were getting closer. I asked whether we were still searching for perfection. An agent can execute experiments quickly and still leave its owner feeling stuck in a loop. Progress updates need to explain the hypothesis, the result and the decision that follows. A stream of completed scripts is a poor substitute.
I also challenged the data conversation. When the limitations of the application extract became apparent, why had we not moved sooner to raw exports? When recommendations started expanding towards more detailed invoice information, I pushed back. We needed to work with the data I could realistically provide and establish what it could support.
I supplied an SAP Excel export covering 2015–2026. That changed the practical approach. We were experimenting on my workstation; Cosmos did not need to be an intermediary. Codex could preserve the workbook and build a direct, versioned adapter for research.
We tested the same boosted and Chronos recipes on the shorter recent history and the longer Excel history, comparing FY24, FY25 and FY26 against common actual outcomes and common references. More history produced mixed changes. It revealed additional purchasing behaviour, but did not consistently repair the customer, product and business forecasts. We had to keep distinguishing “more observations” from “a better prediction problem.”
The more consequential change was how we divided the problem. I asked whether different models could serve different expectations. Customer behaviour, product propensity and annual revenue had been bundled into an ambition that sounded simple in a product mockup and was much harder to validate.
Around that point, I asked Codex to find and use a data-science skill. We installed the community data-scientist skill from magnus919's agent-skills repository, pinned to a reviewed version. It provides methodological instructions: formulate the question, examine assumptions, choose a defensible method, evaluate it and make the result reproducible. Loading it does not change the agent's model weights or confer a professional qualification.
The skill reinforced a useful change in emphasis. We already had chronological tests and frozen specifications. We now made the distinction between describing history, predicting another billing event and forecasting money much more explicit. The improvement I would credit to this stage was a clearer research direction. It came from the skill, my steering and the accumulated evidence together; we did not isolate a causal accuracy gain from installing a file.
Even the skill needed scrutiny. Generic examples using shuffled validation folds were unsuitable for our time-dependent histories. Illustrative code and hardware heuristics needed checking against the actual runtime. A specialist skill is a resource an agent must apply thoughtfully, with the business's data and engineering rules taking precedence.
The first model we banked answered a narrower question: for a known customer, how likely is another positive-billing month within the next three, six or twelve months?
It uses a regularised logistic model in a discrete-time survival framework. At each historical monthly starting point, the model learns the conditional likelihood of the next billing event from activity features such as recency, frequency, gaps and seasonality. It pools information across customers, and combines the monthly conditional predictions into coherent probabilities over the supported windows. It learns coefficients from observed outcomes; the resulting predictions go beyond a hand-written “recent customers are good” rule.
Defining the event carefully was essential. Multiple invoice lines did not become multiple independent orders. A month with a positive billing line could still count as activity when a credit offset its net revenue. A credit-only month did not count as a positive purchase event. Follow-up stopped at the available training cutoff, so an unknown future was never labelled as inactivity. That gave us a behaviour model whose target we could explain and test.
The second banked model applied the same general approach to customer and broad product-category combinations. It incorporated customer activity, category history, changing mix, seasonality and related-category information. It scored combinations a customer had bought before as well as eligible combinations they had never bought. We used governed material-to-category mappings from the platform, with unresolved history explicitly unclassified, because the business discussion belonged at portfolio level rather than individual material codes.
This model supports questions about likely category activity and potential sales priorities. Several categories can be relevant to one customer. Their probabilities overlap; they are not shares that add up to a spending budget. A promising buying propensity also does not tell us the quantity, invoice value or profitability of a future purchase.
Both propensity models produced encouraging retrospective evidence against their declared simple references. They also retained weaknesses around sparse histories, quiet customers and raw probability reliability. Separate conditional-spending experiments reinforced the boundary: attaching an amount model to a useful buying probability still failed the monetary requirements. Better estimates of who might buy did not solve how much they would spend.
Later I found a much larger SAP billing export extending back to 2003. My reaction was understandable: surely more than two decades of history would give the models enough to learn from. It made a much richer experiment possible. It also brought older account codes, changing product descriptions, different report columns and historical regimes into view.
The adapters had real work to do. One workbook contained duplicate-looking quantity headings with different meanings. The application's financial-year convention needed to be derived consistently from dates. The larger export was a different SAP report, so copying column assumptions from the previous adapter would have misinterpreted fields. Credits, cancellations and unresolved materials had to survive the transformation. Four implausibly future-dated lines were preserved and quarantined when the available evidence could not justify a replacement date.
We checked overlap between exports instead of assuming a longer file was simply the earlier one with extra years attached. Revenue and source cost required separate reconciliation. We also kept current catalogue classifications distinct from historical knowledge: mapping old materials into today's reporting categories helps a business owner understand the portfolio, but does not recreate the exact catalogue that existed at every old forecast date.
Customer identity raised another limit. An SAP account code is an observed account, with uncertain continuity to other historical codes. Our limited current customer master could help corroborate a mapping; it could not become the definitive truth about decades of accounts. I eventually paused that reconciliation. Useful research could continue with the remaining identity limits visible.
The third component was an annual business-revenue model: a small, regularised vector autoregression, or VAR. It learns relationships among the past seasonal changes of related category revenue and source-cost series. In practical terms, it estimates a matrix of lag relationships, applies a constraint to limit unstable propagation and forecasts monthly values whose sum can be evaluated as annual business revenue.
That is learned statistical modelling. A neural network is one possible form of machine learning, and a fitted logistic or autoregressive model is another way to learn predictive relationships. The useful distinction for us was whether the chosen method improved the task it was intended to perform. The VAR earned a place as an annual business-total research baseline. Its success did not carry over automatically to customer spending, category amounts, management gross profit or cash. The current FY27 monetary outputs remain research diagnostics, with planning readiness still unestablished.
We also reran the boosted and zero-shot Chronos recipes on the new billing export, comparing history from 2003 with history from 2015 on the same source and target years. The already evaluated VAR supplied a fixed comparison without unnecessary refitting. The arms shared observed target outcomes, accounting rules and references, while retaining their own available histories and known accounts. Longer history could reveal additional accounts; that difference stayed visible. The exercise preserved the useful annual-total result and the much weaker evidence for detailed customer and product amounts.
Full-history propensity refits and chronological calibration had their own experiment records. Calibration adjusts the probability scale rather than teaching a new ordering of customers. It helped some task and horizon comparisons and weakened others. An improvement in one window did not justify silently replacing every banked probability.
“Banked” became an important word. We preserved a specific recipe, data identity, fitted states, model card and evidence for reuse. We had three accepted research components, each with a defined task. Production qualification and future reliability still required work. The original propensity banks retained their 2015–2026 source identities; later full-history refits were separate experiments. The revenue bank used the extended history. Discovering a larger dataset did not silently rewrite the earlier records.
Training meant writing and running a local data pipeline. Codex transformed preserved source rows into consistent, dated monthly histories in Python. Features stopped at each event-date cutoff within the accepted, as-restated source. That preserved local training chronology without pretending to reconstruct every historical revision. Scalers were fitted within the permitted history. Known missing periods, observed inactivity and unobserved prehistory had different meanings. Signed financial values were retained and reconciled using exact cents at the reporting boundary.
For the historical tests, we moved the clock back. To forecast an old financial year, local fitting saw only its allowed earlier sales-derived data. We repeated that across forecast origins and compared the results at the customer, product and whole-business levels relevant to each experiment. Rolling-origin evaluation explains this approach. We also acknowledged that historical years already examined during the research were reused retrospective evidence, even when a particular run kept their outcomes outside fitting.
The metrics followed the question. Money forecasts needed annual errors, signed bias and comparisons that exposed cancellation between individual misses. Behaviour models needed probability error, calibration and useful ranking against simple activity references. In a sparse dataset, an impressive overall classification accuracy can reward predicting no activity for nearly everyone. I wanted a useful customer list and understandable probabilities, which required more specific tests.
Engineering verification had a separate purpose. Tests checked source transformations, dates, credits, rounding and incomplete months. Saved-state replays checked whether retained models reproduced their outputs. Independent audits reconstructed calculations, and local browser reports let me inspect the actual results. Passing those checks established that the machinery worked as recorded. Forecast usefulness still depended on the comparisons with real outcomes. We had several experiments that executed correctly and failed predictively.
All this changed the product strategy. My early mockups imagined a richer monetary forecast than the models had earned. I wanted independent customer and product sliders. We eventually agreed to build the first increment around the demonstrated capabilities: a business outlook, customer buying likelihood and category intelligence, with historical context and budget comparisons where an eligible forecast and a comparable plan exist.
Management assumptions would have their own clear place. A decision to explore lower customer spending is an assumption I supply, with its arithmetic consequences visible. It is not proof that a propensity model has learned the causal effect of losing a tender. Profit, runway and workforce scenarios also need expenses, working capital, cash and cost-response assumptions. Sales history alone cannot answer when a business will run out of cash.
I then asked for a strategic view through FY32. We ran a bounded longer-horizon VAR experiment on the full source, comparing one- through six-year annual and cumulative errors with simple baselines. For uncertainty, we generated joint residual paths, advanced each path through the model and summed its monthly values before calculating annual ranges. The time-series bootstrap literature informed that design; historical coverage determined how much trust the ranges deserved.
The short-horizon advantage was modest, and it did not persist at the longer leads. The raw simulation ranges also contained historical outcomes less often than their nominal labels suggested. We retained the original annual bank and treated the continuation as research evidence. That result gave us a clear product decision: build strategic growth, downturn and recovery controls as explicit management scenarios, with model projections available only at their demonstrated level of support. Simulated futures add possible paths, never additional observed sales history.
The local pipeline now exists. It preserves source identities, builds research datasets, fits and evaluates models, retains protected results and produces inspectable reports. Derived research datasets, fitted states and predictions remain in encrypted local artifacts outside Git. Original SAP workbooks are preserved separately and are not committed to source control; those original files are not covered by the research-artifact encryption. Source code, specifications, tests and technical identities are versioned so a later result can be traced and reproduced.
The production design keeps that computation separate from everyday use. Training and batch inference can run locally. An approved publication process would create portable, immutable result releases in private storage. The existing authorised BizOps API would serve them to the page and to Signal AI. The application would not need my workstation online for every question, and moving a scenario slider would not start a training job or ask a language model to perform the arithmetic. Publication, rollback, refresh and production acceptance are still work to build.
The chat experience will use those same versioned results through bounded tools. It should be able to explain the model's question, the history behind a profile, the forecast origin, the scenario assumptions and the relevant limitations. Its fluency must not turn a purchase probability into an invented revenue forecast. As new data arrive, we can produce new versions and roll the planning window forward while retaining the predictions issued earlier.
That architecture also fits the economics of this experiment. We did not begin by provisioning a permanent ML server or a GPU cluster. A substantial longer-horizon evaluation ran in minutes on my workstation with a few gigabytes of memory. Some earlier adaptation and replay runs took much longer. Execution time for one script is only one part of the journey; investigation, corrections, interpretation and owner review took place across days.
Which brings me back to the hiring question.
I built a business prediction engine without hiring a data scientist
The research and engineering Codex performed here is work I would ordinarily budget several days for a human specialist, and potentially a couple of weeks once data investigation, competing approaches, validation, reporting and architecture are included. That is my estimate of the assignment, rather than a measured comparison between Codex and a particular data scientist. We did not run a head-to-head productivity study.
What I can say directly is that I commissioned a substantial data-science workflow through AI agents and obtained executable work, preserved evidence and decisions I could review. Codex did far more than suggest Python snippets. It did the implementation and much of the investigation, with Claude and additional agents providing bounded review. My existing platform, workstation, subscription and time supplied the environment. The business context and acceptance decisions remained my responsibility.
That changes the starting point for a manager considering a full-time data scientist. I would now want to test a bounded, consequential business problem with an agent, a knowledgeable owner and clear evaluation criteria before assuming a permanent specialist hire was necessary. A capable Codex subscription can give a business leader access to substantial research and engineering capacity without a dedicated human implementing every experiment. Selective specialist review may be a better initial purchase than committing immediately to full-time headcount.
Yes, I think parts of the data-scientist role are at risk. Work centred on routine preparation, model wrappers, standard comparisons and report production is increasingly contestable. Expertise has to earn its place through better questions, stronger judgment, novel methods, reliable operations or a level of assurance the agent-assisted process cannot provide. High-stakes decisions and unfamiliar statistical problems can justify substantial human expertise. Managers should make that case explicitly, based on the work their business actually needs.
This experience also made me more demanding of agents. Access to a skill file does not excuse weak assumptions. More experiments do not excuse poor communication. A confident model recommendation needs reasons, and an attractive result needs a fair benchmark. When the evidence is disappointing, I expect the agent to tell me what failed and what we learned, without quietly changing the definition of success.
We ended this phase with three bounded research models, a reproducible local pipeline, an honest account of failed approaches and a more practical product plan. My ambition for BizOps is still broad. The route now follows questions we can test, capabilities we can explain and assumptions I can own in a management discussion.
I would have previously expected to hire specialist capacity to get this far. Now I know how much of that work I can direct through agents. That will change my next hiring conversation.
Machine learning does not have to mean a neural network
Two of our banked models use supervised machine learning: customer buying likelihood and customer–product-category propensity. Both use logistic hazard models whose coefficients are learned from historical examples. Logistic regression is an established supervised learning method, despite its roots in statistics. The third banked component, our revenue VAR, is best described as a fitted statistical forecasting model. All three estimate relationships from data; none is simply a manually assigned score. Scikit-learn’s supervised-learning documentation places logistic regression within that same family of learning methods.
For the propensity models, we designed the historical features and specified the training objective. Training then determined how those features contributed to predictions. We did not manually decide how much importance each customer’s recency, purchasing frequency or seasonality should receive. A neural network would also learn weights, but could combine its inputs through additional layers and nonlinear relationships. That extra flexibility would need to produce better predictions to justify its complexity.
We also genuinely tested neural forecasting. Chronos is a pretrained neural model, and our experiments included both using its existing weights and training smaller adapters through LoRA. The neural configurations we evaluated did not provide sufficiently dependable monetary forecasts to earn promotion. That finding applies to those configurations and tasks. It does not establish that neural networks cannot work for this business. A purpose-built neural customer-propensity model would be a different experiment from the monetary forecasting approaches already tested.
If we pursue that experiment, we can begin with the sales history already available. We do not need to make detailed invoice enrichment or another decade of data a prerequisite. We do need consistent monthly histories, traceable product-category mappings, explicit account-identity limitations, and a distinction between observed inactivity and unavailable history. Twenty-three years of records provide valuable evidence, but repeated examples from overlapping periods are not twenty-three years of independent evidence for every customer.
One plausible candidate would be a compact network shared across customers and categories. It could learn from sequences of purchasing activity, recency, seasonality and changing product mix, allowing sparse histories to benefit from patterns elsewhere in the portfolio. Learning across related series is an established direction in global neural forecasting research. That supports investigating the approach; it does not identify a winning architecture for our particular business.
The output must match the question. For buying propensity, a neural model could estimate monthly conditional billing probabilities and combine them into three-, six- and twelve-month likelihoods, while retaining our treatment of incomplete follow-up. For revenue, it would additionally need to learn positive spending over the same forecast window conditional on activity, with credits handled consistently and separately. Accurate buying probabilities alone do not establish accurate spending forecasts. The combined monetary outputs would need their own evaluation and coherent aggregation into business totals.
Training would involve choosing the network’s size, historical lookback, learning rate and regularization, then updating its weights over batches of historical examples. Those choices—and when to stop training—must be assessed on chronological development data. Otherwise, a flexible network could become increasingly good at reproducing the past without improving its forecasts.
The acceptance test would remain practical: compare the neural candidate with our banked models and simple controls using the same forecast origins, target populations and accounting rules. We would examine probability error, ranking, calibration, monetary errors and uncertainty coverage according to the task. Because FY24–FY26 have already informed this research, another comparison against those years would remain retrospective evidence. Newly arriving outcomes would be important for establishing prospective reliability.
A bounded experiment could still follow our frugal operating model: train locally, measure runtime and memory, and retain reproducible fitted outputs. We would assess whether GPU acceleration justified its cost rather than assume it was mandatory. A successful neural model would not automatically require an additional always-on production service.
What remains unsolved is substantial. We have not established dependable customer and category spending forecasts, calibrated six-year revenue predictions, or a complete model of business survival. Bankruptcy and workforce scenarios also require expenses, cash, working capital and assumptions about how costs respond. Our research produced trained components with useful, bounded evidence. The broader forecasting platform remains an objective whose capabilities must continue to earn their place through testing..
Technical appendix: what we actually trained and tested
A practitioner should be able to distinguish an implemented model from a plausible story about one. Our three banks contain fitted states, versioned feature definitions, training cutoffs, fixed experiment specifications, dependency identities, saved predictions and evaluation evidence. “Banked” means preserved and accepted for a stated research task. It does not mean that every output has passed production or financial-planning qualification.
A plain-language guide to the terminology
Training estimates a model's numerical relationships from historical examples. Inference applies the fitted model to make a prediction. A feature is an input such as months since the last purchase. A parameter is learned, such as the weight attached to that feature; a hyperparameter is a setting we choose, such as the penalty on large weights. An intercept is a constant term. More parameters do not automatically mean more useful intelligence.
The forecast origin is the date at which available information stops; the horizon is how far ahead we predict. A backtest moves that origin into the past and checks the subsequent actual outcome. A baseline or control is a simple reference, such as repeating the previous year, which a more complex model should justify improving upon. Granularity means the level being scored: customer, category, month or whole-business year.
| Term | What it means in this project | How to read it |
|---|---|---|
| VAR — vector autoregression | A model of several related time series, using their earlier values to predict subsequent values jointly | Our VAR(1) uses one preceding monthly vector of seasonal changes; the 1 is not one year of training history |
| APE — absolute percentage error | One absolute forecast error divided by the absolute actual value, multiplied by 100 | Used for an individual annual total; lower is better |
| WAPE — weighted absolute percentage error | The sum of absolute forecast errors divided by the sum of absolute actuals, multiplied by 100 | Larger actual totals carry more weight; it is not an equal-weight average of annual APEs |
| AP — average precision | A summary of precision across recall levels when ranking likely buyers; precision is the fraction of selected cases with positive billing, and recall is the fraction of all positive-billing cases selected | Higher is better; AP is neither percentage accuracy nor an individual buying probability |
| Brier score | The average squared difference between each predicted probability and its observed 0 or 1 outcome | Lower is better; zero means perfect probabilities on those observations, not a guarantee about the future |
| Log loss | A probability-error score that penalizes confidently wrong predictions especially strongly | Lower is better; theoretical log loss is unbounded. Our scorer clips probabilities to [1e-12, 1 - 1e-12] for finite computation |
| Calibration | Whether groups assigned similar probabilities experience events at approximately those rates | A well-ranked customer list can still overstate its buying probabilities |
| Prediction interval and coverage | An interval describes a range for a future outcome; coverage is how often historical outcomes fell inside the stated ranges | A nominal 95% label is a target, not evidence of 95% empirical coverage |
For example, the reported 4.03% annual WAPE describes combined absolute annual errors relative to combined absolute annual actuals. It does not mean 95.97% of customers were predicted correctly, or that next year's outcome has a 95.97% probability of being right. Likewise, 88.8% AP is a ranking score, not an 88.8% chance of purchasing.
The datasets and the time boundary
The data grew in three stages. Months below describe source coverage before restricting each training fold; they are not independent observations for every customer.
| Source used during the journey | Closed monthly coverage | What it added |
|---|---|---|
| Initial Cosmos-derived platform history | August 2020–September 2026; 74 months | A practical starting point using data already in the application |
| First direct SAP workbook | August 2015–July 2026; 132 months | Eleven complete August–July fiscal years, with detailed billing lines |
| Extended SAP billing export | October 2003–September 2026; 276 months | Twenty-two complete fiscal years plus partial edge years; a much longer view of repeat and dormant behaviour |
We preserved source workbooks, checked date and sign semantics, and built monthly account and account–category panels. A positive-billing event means at least one positive billed line: a positive sale offset by a credit still counts as activity. Credit-only months do not. Signed revenue retains credits rather than silently dropping them. Unresolved dates stayed quarantined. Detailed materials were mapped to reporting categories through traceable catalogue links, with an explicit Unclassified bucket. We did not treat a limited present-day customer master as definitive evidence for twenty years of account identity.
Historical tests moved the cutoff forward. Training labels, fitted scaling and features stopped at the origin; the following fiscal year supplied the outcomes.
| Test target | Last training month | Held-out target months | 2015-start training months | 2003-start training months |
|---|---|---|---|---|
| FY24 | July 2023 | August 2023–July 2024 | 96 | 238 |
| FY25 | July 2024 | August 2024–July 2025 | 108 | 250 |
| FY26 | July 2025 | August 2025–July 2026 | 120 | 262 |
The two original propensity banks use the 2015 workbook. Their results below must not be relabelled as 2003-history models. The later revenue comparison uses two start dates from the same extended export, keeping target actuals and reporting taxonomy fixed. That isolates the history-window comparison more fairly than comparing scores from different exports.
These are chronological, retrospective backtests, following the logic of rolling-origin evaluation. They are not newly untouched holdouts after the entire research journey. We reused FY24–FY26 while choosing approaches. The export, category mapping and source costs are also a current, as-restated vintage; event-date cutoffs do not reconstruct exactly what management knew years earlier. No random row split, invented extra years, tender outcome or contract-status label was used to establish these results.
Three banked models, three prediction targets
The first two models are supervised statistical learning. The third is an estimated multivariate time-series model. All learn numerical parameters from data. The simple rules shown later are comparison controls, not substitutes quietly passed off as trained models.
Model 1: customer purchase likelihood
The question is: will an already observed account generate positive billing within the next three, six or twelve months? The target is billing activity, not contract renewal, physical product demand or the size of an order.
We implemented a pooled discrete-time logistic hazard model. Discrete-time means we work in monthly steps. The hazard is the chance of the next billing event in a month, conditional on no event yet since the forecast origin. Survival means the probability of still waiting for that event. Logistic describes the function that converts a weighted feature score into a probability between zero and one. Pooled means one shared set of coefficients learns across accounts; different histories still produce different predictions.
This formulation fits the observable question in our business: irregular purchases separated by quiet months, with an uncertain wait until the next bill. We can model timing and seasonality without deciding that every quiet account has permanently left. Sharing coefficients offers a practical way to learn from sparse account histories. Discrete-time event-history methods and their treatment of censoring are well established in Allison's foundational work. Our choice of features and overlapping landmarks is an adaptation to test, not a prescription from that paper.
A landmark is a dated snapshot from which we ask about the next event. Each eligible monthly landmark produces an at-risk sequence. Follow-up stops at the first subsequent positive month, twelve months, or the training cutoff. An incomplete future is right-censored: we use the follow-up actually observed, without labelling the unobserved remainder as non-purchasing. Landmarks start after twelve globally observed months; an account's own exposure starts when it first appears. Repeated landmarks and horizons are dependent training examples, not additional independent customers.
The model has 23 features: observed exposure, recency, positive-month frequencies over several windows, completed gaps, changes in annual activity, target-calendar activity, sine/cosine seasonality and horizon terms. It does not use customer ID or monetary amounts as predictors. Historical features describe the prefix; future-month features condition on no intervening event.
For a nondegenerate fit, training estimates 23 slopes and an intercept. With training-standardized features z, the conditional monthly hazard and cumulative probability are:
h_m = sigmoid(b0 + beta' z_m)
P(first positive billing by month H) = 1 - product_m=1..H(1 - h_m)
loss = mean Bernoulli negative log likelihood + (0.01 / 2) * ||beta||²
This survival product combines conditional hazards; it does not assume independent unconditional monthly purchases. The intercept is unpenalized. The L2 penalty, a form of regularization, discourages large weights that might fit historical noise too closely; it trades some flexibility for stability. Feature means and population standard deviations are fitted only on the training rows, with scale one for constant columns. Initialization uses the training event-rate logit and zero slopes. SciPy L-BFGS-B uses maxiter=1000, ftol=1e-12 and gtol=1e-7; non-success or nonfinite fits are rejected without a retry. L-BFGS-B is the numerical optimization algorithm that updates the weights to reduce the loss; maxiter limits iterations, while ftol and gtol are stopping tolerances for objective improvement and gradient size. Those are fixed numerical settings, not parameters selected to win on FY26. Optimizer success is a computational check, not a guarantee of statistical validity.
The useful output is an account-prioritization and dormancy view. It cannot discover the identity of an account that has never appeared, or convert a buying probability into expected revenue without another qualified model. The original bank contains the three historical test fits; it does not contain a later FY27 customer fit by implication.
Model 2: customer–product-category propensity
This asks: which reporting categories is an observed customer likely to buy within each horizon? We modeled customer–category pairs, including pairs with no previous purchase, using the same censored hazard formulation and optimization policy.
The pair-level question is naturally sparser than the account-level question: a customer may buy regularly but purchase a particular equipment category only occasionally. Pooling pair history with customer activity and portfolio information lets the model learn shared associations instead of fitting a separate model to every thin customer–category history. That is why we reused the event-time formulation at this finer level, then tested it separately.
There are 35 features and, in a nondegenerate fit, 35 learned slopes plus an intercept. Pair recency and frequency combine with overall customer activity, category activity, historical mix shifts, other-category affinity and seasonality. Recency means time since the last event; affinity describes an observed purchasing association. Beta(1,1) smoothing stabilizes sparse activity-rate features by adding one event and one non-event pseudo-count, so very short histories do not immediately produce extreme rates. Some mix features use historical positive-billed-value shares; this is still an activity target, not a fitted spend prediction. Pair exposure begins only once both the customer and category are observed.
This learns an association across customers and categories rather than merely listing last year's orders. It supports portfolio reviews, repeat-purchase prioritization and tentative cross-sell exploration. It is not a causal recommendation engine: exposure, availability and sales effort were not randomized. Category probabilities can overlap because one customer can buy several categories; they are neither mutually exclusive product shares nor revenue allocations.
The original bank preserves three test fits and a fourth July 2026 opening fit using the full 132-month workbook. Later expanded-history or calibration experiments are separate evidence, not an invisible upgrade to that bank.
How the propensity models performed
For each task, we evaluated the complete origin-known population. Brier score is mean squared probability error; log loss is Bernoulli negative log likelihood. Lower is better for both. Average precision (AP) measures ranking across the precision–recall curve; higher is better. AP is shown on a percentage scale, not as percentage accuracy. Brier and log loss are shown in their native units. Metric definitions matter particularly when positive outcomes are relatively uncommon.
These are the learned models' twelve-month results. Mean probability and observed event rate are population summaries, not individual customer disclosures.
| Task | Target | Brier ↓ | Log loss ↓ | AP ↑ | Mean probability | Observed event rate |
|---|---|---|---|---|---|---|
| Customer | FY24 | 0.095 | 0.315 | 87.1% | 34.9% | 28.5% |
| Customer | FY25 | 0.071 | 0.256 | 90.5% | 31.8% | 24.4% |
| Customer | FY26 | 0.065 | 0.241 | 89.2% | 28.9% | 21.3% |
| Customer–category | FY24 | 0.049 | 0.179 | 79.4% | 13.4% | 11.9% |
| Customer–category | FY25 | 0.038 | 0.143 | 77.9% | 12.1% | 9.0% |
| Customer–category | FY26 | 0.035 | 0.131 | 82.4% | 11.4% | 9.2% |
The customer model's Brier score fell across these three test years; that is not a controlled learning curve. Training history, the evaluated accounts and business conditions all changed. The customer model's annual AP also did not improve monotonically. A good report should preserve that distinction.
For the same twelve-month outcomes pooled across the three origins, the comparisons were:
| Task | Method | Brier ↓ | Log loss ↓ | AP ↑ |
|---|---|---|---|---|
| Customer | Learned hazard | 0.076 | 0.269 | 88.8% |
| Customer | Recency/frequency | 0.237 | 0.958 | 76.4% |
| Customer | Seasonal activity | 0.335 | 1.104 | 72.2% |
| Customer–category | Learned hazard | 0.040 | 0.150 | 79.9% |
| Customer–category | Customer activity × affinity | 0.087 | 0.325 | 68.5% |
| Customer–category | Pair recency/frequency | 0.208 | 0.701 | 59.1% |
| Customer–category | Seasonal pair | 0.097 | 0.343 | 67.3% |
| Customer–category | Previous-FY repeat* | 0.075 | 2.068 | 47.6% |
| Customer–category | Three-year annual frequency* | 0.054 | 0.197 | 62.1% |
The two starred category controls were added as post-hoc sanity checks: a smoothed frequency of activity across complete historical twelve-month blocks, using up to the latest three, and repetition of the previous fiscal year's activity. They did not trigger a model refit or rewrite the original acceptance screen. Their results are useful checks, not evidence of a preregistered comparison.
The other controls use recent activity frequency, same-calendar seasonal activity, or overall customer activity combined with category affinity. We score them against the same targets as the learned models. Pooling recomputes metrics from all scored entity–origin rows; it is not an unweighted average of the yearly scores.
The horizon breakdown also exposes probability bias:
| Task | Months ahead | Brier ↓ | AP ↑ | Mean probability | Observed event rate |
|---|---|---|---|---|---|
| Customer | 3 | 0.063 | 83.1% | 18.4% | 16.9% |
| Customer | 6 | 0.068 | 85.9% | 24.8% | 19.8% |
| Customer | 12 | 0.076 | 88.8% | 31.7% | 24.5% |
| Customer–category | 3 | 0.028 | 70.4% | 5.9% | 5.6% |
| Customer–category | 6 | 0.033 | 75.8% | 8.6% | 7.5% |
| Customer–category | 12 | 0.040 | 79.9% | 12.3% | 10.0% |
The learned models improve on these controls, but their twelve-month mean probabilities still exceed the realized event frequencies. Lower Brier score alone does not establish good calibration: it reflects discrimination as well as calibration. A reliability curve, subgroup checks and fresh prospective outcomes remain necessary before treating a stated probability as a dependable decision threshold. Nor can customer and customer–category Brier scores be compared as if the tasks had the same prevalence. The distinction follows standard probability-calibration guidance.
Model 3: annual whole-business revenue
The banked monetary model is a seasonal-change ridge vector autoregression, VAR(1). It operates on category-level signed revenue and source-cost channels jointly. Here, signed values preserve positive billings and negative credits. The accepted research task is the annual sum of business revenue. Source cost is an input; it does not make management gross profit or cash flow qualified outputs.
This was a suitable candidate because the categories form related monthly histories, and the annual decision does not require a separate complex spend model for every sparse account. A VAR can learn predictive relationships across those histories as well as within each one. Seasonal differencing compares a month with the same month a year earlier, giving the model a way to work with changes around an annual pattern. It does not guarantee that those changes are stable through every business regime. VARs for related series and coefficient shrinkage are established forecasting methods, described in Forecasting: Principles and Practice.
We chose a short lag and ridge regularization to limit flexibility and numerical instability relative to the available history. Ridge is an L2 penalty on the coefficient matrix, rather than a rule that sets selected coefficients exactly to zero. Its suitability here rests on the recorded annual comparisons and low compute cost; the later six-year experiment shows where that case weakens.
For K categories there are M = 2K channels. Each channel is scaled by its training-prefix mean absolute monthly level, with structural-zero handling. We difference normalized levels at lag twelve, then estimate how the vector of seasonal changes depends on its previous monthly value:
z_t = channel-scaled monthly levels
d_t = z_t - z_(t-12)
d_t = a + d_(t-1) B + error_t
ridge objective = ||Y_centered - X_centered B||²_F / N + 0.1 * ||B||²_F
Training learns an M × M lag matrix and an M-component intercept from T - 13 transition rows. It uses a float64 ridge solve, with a condition-number guard of 1e12. Singular-value decomposition (SVD) expresses a matrix in directions with different amplification strengths. We cap those singular values at 0.95, then recompute the intercept from the training means. In the equation, the squared Frobenius norm is the sum of squared matrix entries; the separate operator 2-norm cap limits the largest directional amplification. These are different controls. The cap bounds propagation of perturbations in the seasonal-change dynamics; it does not guarantee bounded revenue levels or calibrated forecast errors. The ridge penalty, lag and cap were fixed for this experiment, without a hyperparameter sweep over the reported test years.
Forecasting recursively generates twelve monthly points, restores seasonal levels and channel scales, rounds signed category/month values once, and derives parent totals by exact sums. A cross-category coefficient is a learned predictive association, not proof that one product causes another to sell. Historical customer-share allocations attached to this model are bookkeeping allocations, not learned customer spending.
Its use case is an annual business revenue reference and a candidate baseline for an explicitly labelled management sensitivity. The original revenue bank retained sixteen fitted prefix states across the two history arms. Historical annual screening passed; current FY27 estimates, category/customer money and operational publication remain separately unqualified.
Revenue benchmarks: more history, same target actuals
The following is a whole-business annual comparison using the extended SAP export. Every method is scored against the same full signed target population, including accounts that were unknown at the forecast origin. VAR includes an unallocated entrant reserve in its business total; Boost and Chronos forecast origin-known named series without that reserve. These are delivered-system comparisons, not an experiment isolating only the learning algorithm.
Each FY column is annual absolute percentage error (APE). The final column is pooled annual WAPE: absolute annual errors summed across origins, divided by the sum of absolute annual actuals. Errors are made absolute before pooling, so over- and under-prediction cannot cancel. A zero denominator would be reported as undefined. WAPE is not “100 minus accuracy.”
WAPE gives a readable, scale-free summary for the business-level comparison, and is documented in commercial forecasting evaluation. It can tolerate some zero-valued observations without dividing by each one separately. It can also hide individual failures, weight large periods heavily and change as the test period's scale changes. Hyndman explains why WAPE can mislead on trending or otherwise nonstationary series. We therefore read these as descriptive errors on the named, identical target windows, alongside baselines and granularity checks. They do not certify a stable future error rate. Training-scaled measures such as mean absolute scaled error (MASE) and root mean squared scaled error (RMSSE) are useful complements for future evaluation; they have not been added to these preserved results.
| Method | Training start | FY24 APE ↓ | FY25 APE ↓ | FY26 APE ↓ | Pooled annual WAPE ↓ |
|---|---|---|---|---|---|
| VAR | 2003 onward | 1.96% | 8.08% | 1.83% | 4.03% |
| VAR | 2015 onward | 3.03% | 9.32% | 2.28% | 4.94% |
| Boost | 2003 onward | 12.91% | 27.26% | 15.67% | 18.85% |
| Boost | 2015 onward | 21.25% | 32.08% | 24.84% | 26.27% |
| Chronos | 2003 onward | 10.96% | 3.95% | 180.56% | 68.32% |
| Chronos | 2015 onward | 0.24% | 11.38% | 171.01% | 64.29% |
| Repeat last FY | Common prefix control | 3.59% | 12.82% | 1.87% | 6.17% |
| Three-year seasonal mean | Common prefix control | 20.30% | 18.71% | 11.28% | 16.57% |
“Boost” here is the implemented LightGBM activity–amount system, not CatBoost. Gradient boosting combines decision trees sequentially so later trees improve the chosen loss after earlier ones. Its fixed recipe fits 350 boosting rounds per component: a positive-activity classifier, a conditional positive-amount Gamma regressor and an unconditional credit-magnitude Tweedie regressor with variance power 1.3. It combines activity probability times positive amount, subtracts credit magnitude, and reconciles joint customer–category points to customer anchors. Gamma models strictly positive, skewed amounts; this Tweedie model accommodates a mixture of zero and positive credit magnitudes. Separating occurrence from size was a reasonable hypothesis for intermittent billing, but this implementation did not beat the annual VAR. Those are actual fitted trees and objectives, not a prompt asking a language model to estimate sales.
“Chronos” in this table is pinned pretrained Chronos-2 used without weight updates, with eligible prefix history and deterministic calendar covariates. Its signed point comes from a monotonically rearranged 21-quantile grid integrated by the trapezoidal rule with flat outer tails; it is not the returned median or a demonstrated calibrated conditional mean. The public checkpoint postdates the simulated origins, so we cannot certify historical pretraining availability. Zero-shot means using pretrained weights without fitting them to our history. A quantile is a percentile-like point in a predicted distribution; calendar covariates are extra inputs such as the month. Chronos was worth testing because it could transfer patterns learned from other time series, but transfer is a hypothesis to benchmark. A separate experiment genuinely updated adapter weights through LoRA, low-rank adaptation: small trainable adapter matrices augment the frozen base model. These table rows are not that experiment.
The full-history VAR improved its pooled annual error relative to its 2015 arm and both controls in this three-year comparison. More history also helped this Boost recipe, but did not rescue Chronos: the FY26 error dominates its pooled score. This is evidence for the selected business task and dataset, not a universal ranking of the model families.
Annual aggregation hides substantial timing error. Full-history VAR's pooled whole-business monthly WAPE was 33.79%, versus 33.62% for repeating last FY, despite its 4.03% annual WAPE. Category and historical customer-allocation quality also failed qualification. We therefore banked an annual business research model, rather than advertising accurate monthly or customer revenue forecasts.
What changed when we forecast six years ahead
We extended the same VAR recurrence, including its generated seasonal buffer after month twelve. Historical July origins ran from 2007 through 2025; only fully observed targets through FY26 were scored. That provides 19 one-year outcomes and 14 six-year outcomes, with 99 observed origin–year outcomes across all leads. They overlap heavily. They are not 99 independent business histories.
For raw uncertainty, each origin used 2,000 paths with coefficients fixed. A residual is an observed value minus the fitted model value. Block bootstrap simulation resamples runs of residuals rather than isolated months, retaining some of their time dependence. We centered the final model's residual vectors and sampled circular twelve-month blocks jointly across all channels. Each path advanced its own seasonal state. A fixed origin-specific seed made the draw reproducible. We summed rounded monthly/category values within each complete path before taking nearest-rank annual and cumulative quantiles; summing marginal quantiles would have produced a different, invalid aggregation.
This resamples historical residual variation and preserves within-block temporal and cross-channel structure. It does not incorporate parameter uncertainty or an unseen structural break. Simulated paths were never fed back as additional training history. More paths reduce simulation noise; they do not create more observed fiscal years.
The table scores the individual year at each lead, not cumulative revenue through that year. Baselines hold the origin's last-year pattern or trailing three-year seasonal mean fixed, without refreshing them from future actuals. Coverage is the percentage of historical outcomes inside the raw central interval.
| Lead years | Origins | VAR WAPE ↓ | Last FY WAPE ↓ | Seasonal mean WAPE ↓ | 80% interval coverage | 95% interval coverage |
|---|---|---|---|---|---|---|
| 1 | 19 | 16.29% | 16.59% | 22.95% | 57.9% | 84.2% |
| 2 | 18 | 23.65% | 24.75% | 29.58% | 66.7% | 83.3% |
| 3 | 17 | 31.04% | 31.34% | 34.20% | 47.1% | 64.7% |
| 4 | 16 | 35.88% | 35.25% | 35.58% | 37.5% | 81.2% |
| 5 | 15 | 40.56% | 36.37% | 35.37% | 40.0% | 60.0% |
| 6 | 14 | 39.40% | 35.91% | 37.51% | 35.7% | 50.0% |
The one-year advantage over repeating last FY is small over this longer test period. At four to six years the controls outperform VAR. Its nominal 95% interval covers only 50% of the six-year outcomes. That is serious undercoverage, not a validated 95% assurance level. Small, overlapping samples also prevent treating these percentages as precise population estimates.
We produced opening and latest-data FY27–FY32 research paths, but this evidence does not justify presenting them as reliable six-year financial forecasts. The strategic product direction is consequently an assumption-led growth, downturn and recovery planner, clearly distinguished from a model prediction. A latest-data FY27 landing also contains closed actual months; those must stay fixed when a future scenario is changed. Monthly update origins and remaining-year forecasting need their own validation.
Is this industry best practice?
The model families and evaluation methods have established foundations. Our method choices combine those foundations with the business question and our own results. A method's presence in a textbook does not certify our implementation or make it the best choice for municipal infrastructure sales. There is no evidence here for an industry-wide winning algorithm.
The stronger claim is about the discipline: define the target, respect time order, keep transformations inside the training window, compare against credible simple controls, examine the level of detail actually needed, measure probability quality and interval coverage, and preserve failed results. These align with established forecast-evaluation practice. Our small, repeatedly examined set of fiscal-year tests still leaves selection uncertainty and prospective performance to establish.
For our three banks, the rationale is specific. The customer hazard fits the wait until observable billing; the category hazard fits the same event question for sparse customer–category pairs; the regularized VAR offers a compact annual business reference using related seasonal histories. Their recorded comparisons supported retaining them for those tasks. The exact 23 or 35 features, penalty settings, one-lag choice and stability cap are our design decisions, not industry-mandated settings. More independent outcomes could change those choices.
That is how I would explain the solution to a CEO or CFO: established statistical methods, adapted to the available evidence, tested against alternatives and assigned specific uses. The claim is stronger when we can explain where each model helps and where a management assumption must take over.
Reproducibility and measured computational cost
The preserved evidence binds input, mapping, feature schema, experiment specification, source code, environment and model state through hashes. Private derived datasets, fitted states and detailed results are retained outside Git in Windows Data Protection API (DPAPI)-protected artifacts; raw source workbooks remain separate and are not encrypted by that mechanism. Git holds code, specifications, dependency locks, tests and technical manifests. Machine-bound encryption is not itself a disaster-recovery strategy.
For the appendix, independent metric extraction checked the saved native/result identities and recalculated all 54 aggregate propensity records in the companion evidence, all 18 revenue comparison scores, the common revenue controls and the long-horizon origin summaries. Propensity metrics matched saved receipts within 1e-12, and cumulative hazards reproduced delivered probabilities. This was saved-evidence verification: it did not reread the raw workbooks, refit weights, rerun Chronos or certify source-system completeness.
The completed long-horizon experiment also has a separate saved-state/seed replay: zero fits, exact equality of complete result and native payloads. An independent audit checked draw indices, annual aggregation and metrics, plus 63 monthly witness paths. That is a stated audit scope, not a claim to have independently recomputed every simulated monthly recurrence. Forty-seven focused tests cover data, evaluation, model, runner, audit and reporting mechanics; passing them does not establish forecast accuracy.
Measured runs used the existing Python 3.12.14 CPU environment with 72 pinned packages. The banked fits used one native numerical thread. A CPU is the general-purpose processor; a GPU is a processor often used to accelerate neural-network computation. RSS, resident set size, measures physical memory occupied by a process; GiB, gibibyte, is a binary memory unit equal to 2³⁰ bytes. Peak RSS below is observed process memory, not total workstation memory or a minimum hardware requirement.
| Completed local workload | Fits or replay | Wall time | Peak RSS |
|---|---|---|---|
| Original customer likelihood evaluation | Three historical fits | 30.40 seconds | 0.45 GiB |
| Original customer–category evaluation | Three historical fits plus FY27 opening fit | 271.81 seconds | 1.22 GiB |
| Original annual VAR evaluation | Sixteen prefix fits | 138.04 seconds | 1.31 GiB |
| Long-horizon VAR evaluation and simulation | Thirteen earlier fits, eight saved states reused | 391.17 seconds | 1.95 GiB |
| Complete long-horizon saved-state/seed replay | Zero fits | 330.31 seconds | 1.96 GiB |
These are measured batch workloads on this machine. They do not measure the whole research journey, developer productivity against a human control group, interactive latency or production throughput. The long-horizon run's 8 GiB/20-minute guard was an experiment bound, not a claim that production requires a dedicated machine of that size.
The cost-frugal pipeline and production boundary
The upper panel is implemented: preserve and qualify source data, build cutoff-safe features, fit and batch-score, compare against controls, replay and audit, then retain the accepted or rejected evidence. The lower panel is the agreed design for the new Traffic feature. Its publisher, release integration, application routes and model-backed AI tools still need implementation. Existing BizOps hosting, authentication and Signal AI infrastructure can be reused.
The workstation will train and generate supported batch outputs. A separate authorized publication boundary will validate lineage, permissions, supported origins/horizons and release readiness. Production will receive small, typed, non-executable result tables in private immutable storage, not raw SAP workbooks, local DPAPI blobs or a Python training runtime.
Publication will write and read back all required objects, write a ready manifest last, then change the active release pointer conditionally using If-Match. This selects a complete validated release; it does not assume a multi-object upload is atomic. Failed publication retains a visibly dated last-approved release. Rollback selects an intact compatible version; absent or unsupported results remain explicitly unavailable.
The existing Node API—the application programming interface through which the app requests data—will enforce business-unit (BU) and account access before exposing results. The dashboard and Signal AI tools will pin the same release, cutoff, model/data version and qualification status. Budget is a separate same-FY comparator, not a training label. Scenario controls will call shared deterministic arithmetic, so chat and charts cannot silently disagree about the effect of an assumption. A large language model (LLM) can retrieve and explain approved outputs; it will not invent coefficients, perform unverified financial arithmetic or retrain on a slider drag.
Refresh, inference and retraining are different operations. A newly imported month can trigger a local assessment; it cannot automatically qualify an origin or model capability we have never validated. Annual rollover will create a new dated output and preserve earlier forecast vintages, enabling comparison with subsequent actuals. The laptop is needed for preparing updates, not for users reading an approved published release.
This design avoids an additional always-on ML server, Python endpoint, GPU or managed training platform in the first increment. Existing storage, application hosting and AI usage still have costs. The savings come from performing bounded batch work locally and serving compact results through infrastructure we already operate, while retaining a clear path to a stronger model when evidence supports one.

