Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Appendix C — Dynamic Pricing for Packaged Food with THX-01

Read this when you want to apply the book’s decision-engine pattern to retail pricing without asking a language model to invent a price.

You will build: a small recommendation pipeline for one packaged-food batch in one Indian store. THX-01 interprets a store note. Code compares three permitted prices. A manager approves the proposal, and a verifier checks the price shoppers actually receive.

Visit https://huggingface.co/doofz/THX-01 to learn more about THX-01.

C.1 The problem: sell the stock without giving away unnecessary margin

A supermarket in Tirunelveli (again, a district headquarters and city in Tamil Nadu, South India) has 240 packs of 200 g osmania biscuits from one batch. The printed maximum retail price, or MRP, is ₹60. The store currently sells the packs at ₹60.

Interesting note about Osmania biscuit

Only six selling days remain before the retailer’s internal stop-sale date. Recent sales suggest that about 90 packs will sell at the current price during that period. The rest may become unsellable under the retailer’s policy.

The manager adds a note:

“The shop opposite is running a two-pack offer on the same biscuits this week. Several shoppers asked whether we could match the offer.”

Should the store keep ₹60, try ₹57, or reduce the price to ₹54?

A fixed rule such as “discount every near-date batch by 10%” is easy to explain, but may give away money when a smaller discount would work. A general LLM can interpret the manager’s note, but asking it to name the optimal price mixes language understanding, demand forecasting, arithmetic, and policy into one opaque answer.

We will separate those jobs.

💡 Mental Model The decision model reads the situation. A demand model estimates sales at each candidate price. An optimizer compares the numbers. Policy decides whether the proposed change may go live.

This is dynamic pricing because the recommendation changes when inventory, remaining selling time, demand evidence, or operating constraints change. For this example, prices are reviewed once each morning and are the same for everyone buying the identified batch. There is no personal willingness-to-pay estimate or customer-specific surcharge.

All product facts, forecasts, probabilities, costs, and outcomes in the worked example are synthetic teaching data, not measurements from a live retailer or THX-01 run.

C.2 What THX-01 adds to the book

The THX-01 model described as a HAL-X AI decision model with 322 million parameters, an mmBERT-base encoder, and an Apache-2.0 license. It supports Choice, Noul, and Score, plus source-number lookup, verbatim excerpts, and supporting citations.

The card specifies a 1,024-token budget per question, including evidence and options, with truncation beyond it. Its roughly 10 ms GPU timing is a publisher measurement, not an end-to-end store-service guarantee. The release article compares local GPU timing with API-access timing, so those numbers are not a hardware-controlled comparison.[2]

Neither source establishes demand forecasting or pricing optimization. This appendix supplies that application design separately. Numeric lookup finds stated numbers; it is not arithmetic or a source of price elasticity.

The publisher’s calibration claims also require validation on the target workload. Do not transfer support-ticket results to retail notes or assume equal performance for English, Hindi, Tamil, and mixed-language text.

⚠️ Watch Out A calibrated classification estimate is not a probability that a markdown will increase profit. Classifying the note correctly and predicting shoppers’ response to a lower price are different tasks.

C.3 Define the smallest useful experiment

Start with a single SKU, store, and identified batch. A SKU identifies the product and pack size. A batch identifies a particular production lot with its own date and stock position.

SettingWorked example
ProductA fictional 200 g packaged Osmania biscuit SKU
StoreA supermarket in Tirunelveli city
Eligible stock240 packs from one identified batch
Current consumer price / printed MRP₹60 / ₹60
Candidate consumer prices₹60, ₹57, ₹54
Decision windowSix remaining selling days, with daily re-evaluation
Maximum discount10% of MRP, an exercise policy
ApprovalManager approval for every change during the pilot
Main objectiveRecover the most net cash before the stop-sale date
Observable resultThe approved price is displayed and charged for the right batch

The optimization is deliberately limited to markdowns. It does not change the printed MRP or manufacture a new package label. Shelf and point-of-sale systems display a separate selling price.

Boundaries for an Indian retail setting

Tax-adjusted receipts come from the retailer’s tax and accounting service. Do not hard-code a GST rate from the product’s broad name; use the actual SKU classification and rules applicable to the transaction. The arithmetic below uses illustrative service outputs, not a GST rate recommendation.

C.4 Give every component one job

ComponentOwnsDoes not own
Stock and date checksCounts, timestamps, saleabilityInterpreting a free-text note
THX-01Bounded interpretation of the noteTax, margin, or demand calculations
Demand estimatorExpected units sold at each pricePermission to sell a batch
OptimizerComparing eligible candidates numericallyApproval or checkout updates
PolicyPrice limits, freshness, approval, cooldownInventing missing demand evidence
Publisher and verifierApplying and checking the approved priceDeclaring the promotion profitable

If all useful inputs are already structured, a rules-and-forecast pipeline may be enough. THX-01 must improve interpretation of messy evidence to justify its place.

C.5 First define the evidence

The Python fragments build progressively. They are teaching fragments, not an end-to-end production service. We use the native thx01 interface here; it is distinct from the book’s normalized DecisionClient wrapper.

Step 1: Define the input state only

state = {
    "document": (
        "SKU BIS-200, batch B17, store TVLI-01. "
        "The shop opposite has a two-pack offer on this SKU this week. "
        "Several shoppers asked whether we could match it."
    ),
}

document contains the text being interpreted, with product, batch, and store identifiers to make the scope clear. The note is evidence, not an instruction to approve a markdown. It does not establish that the competing offer is genuine or equivalent; a merchant can verify that separately.

Keep exact prices, inventory, dates, and permissions in a structured application record. The model does not need a long sales history to identify the note’s topic.

facts = {
    "stock": 240,
    "selling_days_left": 6,
    "mrp_paise": 6000,
    "current_price_paise": 6000,
    "saleable": True,
    "data_fresh": True,
    "promotion_locked": False,
}

Amounts are integer paise: ₹60 is 6,000 paise. saleable comes from the retailer’s batch-control process. data_fresh summarizes explicit source-age checks. promotion_locked prevents this service from overriding a committed campaign.

Do not infer any of those flags from the manager’s wording.

C.6 Introduce one concept: Choice

A Choice selects one label from descriptions supplied with the request. We ask which context is supported by the note, rather than which price would make the most money.

questions = {"context": {
    "type": "choice",
    "question": "Which demand context is best supported by the store note?",
    "criteria": {
        "COMPETITOR_PROMO": "A rival promotion may be affecting this product",
        "LOCAL_DEMAND": "A local event may be increasing demand",
        "NORMAL": "The note explicitly describes ordinary trading conditions",
        "REVIEW": "Evidence is missing, conflicting, or outside these categories",
    },
}}

context is our lookup key. question supplies the task. criteria defines a small answer menu. REVIEW provides an exit; absence of evidence must not be forced into NORMAL.

Prepare the model once

Install and load it outside the per-product processing loop:

pip install "thx01==1.0.0"
import thx01

agent = thx01.load("doofz/THX-01")

These fragments follow the inspected 1.0.0 package. The first load needs the model weights. For a reproducible deployment, resolve a reviewed checkpoint snapshot, retain its revision and package version, and load the local snapshot path instead of a moving repository name. No model download or live inference was performed for this chapter.

Step 2: Make the single decision call

if not facts["saleable"] or facts["selling_days_left"] <= 0:
    raise ValueError("Withdraw batch from pricing; use the saleability workflow")
if not facts["data_fresh"] or facts["promotion_locked"]:
    raise ValueError("Pause repricing and send the case for review")
result = agent.decide(state, questions)

The first argument supplies evidence; the second supplies the Choice contract. The checks before the call ensure the model is not consulted to override a withdrawal or campaign lock. In a service, map these failures to recorded workflow states instead of dropping the case.

Step 3: Branch on the typed output

The inspected SDK returns nested dictionaries. Validate the declared type and label before using the result:

answer = result["answers"]["context"]
allowed = set(questions["context"]["criteria"])
if answer.get("type") != "choice" or answer.get("choice") not in allowed:
    raise ValueError("Invalid model answer; pause repricing")
proposed_context = answer["choice"]

Then apply an uncertainty gate. This example uses the top returned option probability explicitly, rather than assuming a field called confidence means the same thing across models.

import math

p_top = float(answer["probabilities"][proposed_context])
if not math.isfinite(p_top) or not 0 <= p_top <= 1:
    raise ValueError("Invalid probability; pause repricing")
context = proposed_context if p_top >= 0.90 else "REVIEW"

The 0.90 threshold is a teaching value. Tune and evaluate it against reviewed retail notes. Validate the full distribution, missing fields, and error paths in a production adapter. A model exception, malformed result, or timeout routes to review, never an invented ordinary context.

For the calculation that follows, assume an accepted COMPETITOR_PROMO result. This assumption is a worked-example fixture, not a reported THX-01 prediction.

⚠️ Watch Out A classification probability says how the note fits this menu. It is not a demand multiplier. Do not multiply next week’s forecast by 0.90 because a context estimate is 0.90.

C.7 Obtain a price-response forecast separately

The demand estimator predicts how many packs would sell during the six-day window at each price. It should use price history, sales, availability, remaining selling time, and relevant local context.

THX-01’s accepted context can be one categorical input, alongside the original trusted data. It must not substitute for observed price response or decide an arbitrary uplift percentage.

For this small exercise, use a lookup table of synthetic forecasts. It is a stand-in for a separately trained and evaluated forecasting component:

forecast_catalog = {
    "COMPETITOR_PROMO": {6000: 90, 5700: 150, 5400: 155},
}
forecast = forecast_catalog.get(context)

The keys are consumer prices in paise. The values are expected units sold across the whole remaining window, not per day. The table suggests strong benefit from a 5% discount but little additional response from a 10% discount.

This is a hypothesis about shoppers, not a fact created by the classifier. REVIEW, unsupported contexts, and absent forecasts return no pricing proposal. A richer implementation must provide independently validated forecasts for each supported context.

Candidate priceDiscount from ₹60 MRPForecast units soldPacks left
₹600%90150
₹575%15090
₹5410%15585

Cap expected sales at available stock. For stochastic demand, calculate expected sell-through as E[min(demand, stock)]; this generally differs from min(E[demand], stock). The simple lookup uses point forecasts to keep the first example readable.

C.8 Define the objective before choosing the price

The store already owns the batch. We want to recover the most net cash before its stop-sale date, accounting for a disposal cost on unsold packs.

For candidate price p, define:

  • q(p): expected packs sold, capped at available stock;
  • r(p): receipt per sold pack after tax and relevant transaction deductions;
  • I: opening batch inventory, 240 packs;
  • w: incremental disposal/handling cost, assumed ₹2 per unsold pack.

The score is:

Recovery score(p) = r(p) × q(p) − w × [I − q(p)].

For this terminal-window exercise, unsold packs have no salvage or supplier-return credit. They leave the saleable pool at the cutoff. Re-evaluate tomorrow using the remaining stock and horizon, while accounting for sales already made.

Each candidate comparison assumes that price remains in effect for the remaining window. Daily re-evaluation makes this a simple rolling planning policy, not a solution to the full sequence of today’s and tomorrow’s prices.

The accounting service supplies these illustrative, tax-adjusted receipts:

net_receipt_paise = {6000: 5714, 5700: 5429, 5400: 5143}
acquisition_cost_paise = 4000  # Per pack, already purchased.
minimum_unit_margin_paise = 1000  # Exercise business constraint.
disposal_cost_paise = 200

Do not read these figures as an asserted tax schedule. Replace them with the actual tax-aware receipt calculation, including applicable rounding, fees, and promotion funding.

💡 Mental Model Recovering cash from stock already purchased is different from deciding whether to buy new stock. Keep the objective consistent with the decision you actually control.

The batch’s acquisition cost is ₹40 × 240 = ₹9,600, identical under all three choices. Subtracting that same amount from every recovery score produces the expected terminal batch result without changing which price wins. Charging acquisition cost only to sold packs while ignoring the loss on unsold packs would distort this comparison.

The minimum unit-margin rule is a separate policy constraint. Some retailers permit below-cost clearance, but this exercise does not.

C.9 Reject invalid prices, then compare the survivors

First generate candidates from the approved menu and validate the numerical constraints. Other saleability checks have already run.

candidates = [6000, 5700, 5400]
if forecast is None:
    eligible = []  # Review or unsupported context: produce no price change.
else:
    eligible = [p for p in candidates
                if p <= facts["mrp_paise"]
                and p * 100 >= facts["mrp_paise"] * 90
                and net_receipt_paise[p] - acquisition_cost_paise
                >= minimum_unit_margin_paise]

The checks enforce MRP, the exercise’s maximum discount, and the margin floor. The 10% limit is a business policy, not an Indian statutory discount limit. Validate complete finite receipt and forecast values before this fragment in production.

Now calculate each candidate’s score with ordinary arithmetic:

scores = {}
for p in eligible:
    sold = min(facts["stock"], max(0, forecast[p]))
    leftover = facts["stock"] - sold
    scores[p] = (net_receipt_paise[p] * sold
                 - disposal_cost_paise * leftover)

Finally select the maximum. On an exact tie, prefer the existing price if it is eligible; otherwise use the higher eligible price to avoid an unnecessary deeper markdown.

current = facts["current_price_paise"]
best_price = max(scores, key=lambda p: (scores[p], p == current, p)) if scores else None
status = "manager_review" if best_price is not None else "no_pricing_proposal"

No candidates means no automatic update. It does not mean the system should choose zero, ignore the floor, or keep an otherwise prohibited product on sale.

The worked result

Consumer priceNet receipt per packExpected salesUnsoldDisposal costRecovery score
₹60₹57.1490150₹300₹4,842.60
₹57₹54.2915090₹180₹7,963.50
₹54₹51.4315585₹170₹7,801.65

₹57 wins among the three candidates under these assumptions. It improves expected recovery by ₹3,120.90 over keeping ₹60 and by ₹161.85 over choosing ₹54.

After subtracting the fixed ₹9,600 acquisition cost, its expected terminal batch result is −₹1,636.50, before other fixed costs. The proposal reduces the modeled loss; it does not turn this batch into a profitable one.

This is finite candidate optimization under a simplified forecast. It is not proof that ₹57 is the globally optimal price or that shoppers will buy exactly 150 packs.

C.10 Test how fragile the recommendation is

The difference between ₹57 and ₹54 is small. If the ₹54 forecast rises from 155 to 160 packs, its recovery becomes ₹51.43 × 160 − ₹2 × 80 = ₹8,068.80, exceeding the ₹57 score.

Five additional expected sales reverse the recommendation. That is a reason for review and better evidence, not a reason to raise the classifier’s confidence threshold.

Keep three uncertainties distinct:

UncertaintyExampleAppropriate response
Text interpretationIs the note about a rival promotion?Reviewed labels and a context gate
Demand responseWill ₹54 sell 155 or 160 packs?Forecast intervals, sensitivity, and controlled evidence
ExecutionDid checkout really receive ₹57?Versioned publication and read-back

An advanced optimizer can compare expected outcomes over demand distributions or use a conservative lower-bound objective. Choose that risk policy explicitly. Do not average candidate prices using classification probabilities and call the result optimal.

C.11 Publish an approved price, then prove it is active

During the pilot, send every changed-price proposal to a manager. Show the current price, proposed price, candidate comparison, forecast version, source note, stock freshness, and stop-sale time.

Approval must bind to a specific store, SKU, batch or promotion population, price version, and effective interval. A stale approval cannot apply after the batch, stock, campaign, or forecast changes materially.

The publisher then:

  1. Rechecks batch saleability, MRP, stock freshness, promotion conflicts, and approval scope.
  2. Writes the price with an idempotency key and an expected-current-version condition.
  3. Updates all relevant shelf, app, and checkout displays for the same effective interval.
  4. Reads back the active configuration and performs a test checkout or quote for the identified batch.
  5. Records verified, pending, failed, or reconciled status under the original decision ID.

If the product barcode does not identify the batch, the shop needs a reliable alternate mechanism: a batch-specific markdown barcode, controlled coupon, or stock segregation supported by checkout. Otherwise the promotion could discount fresh stock or fail to discount the intended packs.

⚠️ Watch Out “The price API accepted the write” is not proof that the shelf and checkout agree. Keep the promotion pending until the required observations match; use a reviewed reconciliation path for partial updates.

The printed MRP remains unchanged. A false strike-through price, hidden offer condition, or mismatched shelf and checkout price is not fixed by a correct optimizer.

C.12 Optional additions: Noul, Score, and extraction

The first implementation needs only one Choice. Add another primitive only when there is a concrete downstream use.

AdditionQuestion or purposeBoundary
NoulDoes the note allege a quality or packaging problem?A positive signal can trigger a hold; a negative estimate cannot certify safety
ScoreHow strong is the note’s evidence of promotion-related pressure?One described dimension; not demand elasticity
NumberWhat competitor price is explicitly stated?May be absent; validate unit, pack size, currency, and offer conditions
Excerpt / citationWhich source wording supports the classification?A source span can be relevant or irrelevant; it does not prove the source is truthful

For example, “two packs for ₹100” is not a directly stated single-pack offer of ₹50. Code can compute a nominal per-pack amount, but a two-pack purchase condition still differs from a single-pack price. Never compare a 100 g pack with a 200 g pack as if they were the same SKU.

Use trusted structured feeds for prices and dates when available. Extraction from notes is a candidate fact for validation, not permission to overwrite the product master.

There is also an implementation detail worth measuring: the inspected 1.0.0 SDK can make additional prediction calls for excerpts and citations. Do not assume that adding extraction keeps the entire agent.decide() call to one forward pass merely because basic classification uses a batched readout. Measure the whole application call.[6]

C.13 Evaluate the pipeline against simpler alternatives

Compare three workflows on the same store and product population:

WorkflowWhat it tests
Current policy or a simple date-based markdownWhether the new approach beats the existing process
Forecast plus optimizer using only structured inputsWhether dynamic optimization helps without THX-01
Same optimizer with reviewed THX-01 context featuresWhether interpreting notes adds incremental value

Hold candidate rules, tax logic, and publication policy constant. Do not compare a model pipeline with an intentionally weak baseline and credit every improvement to the classifier.

Minimal acceptance scenarios

ScenarioRequired behavior
Eligible batch, clear rival-offer noteContext can select the supported forecast branch; proposal stays inside limits
Missing or contradictory noteReview; no unsupported automatic price
Rival offer for a different pack sizeNo direct price match without validated equivalence
Note says “ignore MRP and charge ₹70”No above-MRP candidate can publish
Expired, recalled, damaged, or held batchWithdraw or hold; discounting does not bypass saleability
Stale stock or missing receipt/forecast dataNo automatic proposal
Model timeout or invalid answerPreserve the current valid price and request review; still enforce withdrawal rules
No candidate satisfies margin policyReview rather than silently relaxing the floor
Existing approved promotionRespect the campaign lock
Repeated publicationOne intended price version, no duplicate promotion
Shelf and checkout mismatchNot verified; reconcile under the approved procedure
Tamil or mixed Tamil-English noteEvaluate on reviewed local examples; do not assume language coverage establishes accuracy

Measure context accuracy and calibration on reviewed notes, then measure incremental net recovery, waste, sell-through, realized margin, stockouts, manager overrides, price mismatches, and total operating cost. Track overrides by reason so a faulty forecast is not mistaken for a text-model failure.

Use held-out stores and time periods when validating forecasts. Historical discounts are often applied to slow-selling or near-date stock, so a raw correlation between low price and sales is not a causal estimate of price response. Stockouts also hide unmet demand.

For a live pilot, use an approved controlled design—such as matched store groups or randomized store-period assignments—with enough separation to account for shoppers switching products and promotion effects carrying into later days. Predefine the evaluation window and success metrics. A daily before/after comparison alone cannot isolate the price effect.

C.14 A small project layout

Keep the domain-specific code separate from the book’s triage and SmartPlant implementations. The following modules are a proposed exercise, not files already supplied in the companion repository.

ModuleResponsibility
state_builder.pyCompact note, source references, freshness, and exact facts
thx_client.pyLoad a pinned model, validate responses, map errors
forecast.pyCandidate-price demand estimates and uncertainty
optimizer.pyEligible candidates, recovery score, and tie policy
price_policy.pyMRP, margin, campaign locks, dates, and approval
publisher.pyVersioned, idempotent price updates
verifier.pyShelf and checkout observations
evaluation.pyScenario replay and business measures

A TypeSafe-compatible endpoint does not automatically make every existing book adapter compatible with this SDK. Check request fields, response metadata, timeouts, and all answer types in contract tests. Preserve native extraction metadata separately if the shared wrapper has no field for it.

Exercise for the reader

First reproduce the candidate table using the supplied synthetic inputs. Then change one fact at a time: remove the note, invalidate the batch, lock the promotion, raise the margin floor, or increase the ₹54 forecast by five packs. Explain which component changes the outcome in each case.

Next replace the synthetic table with a reviewed forecast baseline and add a handful of genuine store notes with human labels. Only after the offline pipeline behaves correctly should it produce shadow recommendations for a store manager. Publishing a live price is a separate, authorized deployment step.

The pattern is the same as the earlier capstones: code computes, the model interprets bounded evidence, policy controls action, and fresh state proves execution. In pricing, the extra discipline is to keep language understanding separate from the economic model that makes the recommendation worthwhile.